diff --git a/.babelrc b/.babelrc index a539190..1deaf9e 100644 --- a/.babelrc +++ b/.babelrc @@ -21,5 +21,8 @@ "@babel/plugin-proposal-nullish-coalescing-operator", "@babel/plugin-proposal-do-expressions", "@babel/plugin-proposal-function-bind" - ] + ], + "targets": { + "chrome": "59" + } } \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index a917ae1..01878e9 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,6 +1,5 @@ { "parser": "@babel/eslint-parser", - "extends": "airbnb/base", "env": { "browser": true, "node": true, diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..d5cad93 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,39 @@ +{ + // Verwendet IntelliSense zum Ermitteln möglicher Attribute. + // Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen. + // Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Mocha single Test", + "skipFiles": [ + "/**" + ], + "runtimeArgs": ["--preserve-symlinks"], + "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", + "args": [ + "--require", + "@babel/register", + "--reporter", + "dot", + "--timeout", + "300000", + "test/mongo/mocked/client/patch.js" + ], + "env": { + "LOG_LEVEL": "debug" + } + }, + { + "type": "node", + "request": "launch", + "name": "Launch Complex Resource", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}/examples/server.js" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/Makefile b/Makefile index ce31d71..841a558 100644 --- a/Makefile +++ b/Makefile @@ -14,11 +14,19 @@ test: @node_modules/.bin/mocha\ --require @babel/register \ --reporter $(REPORTER) \ + --exclude test/failing/*.js \ + --exclude test/support/*.js \ + test/**/**/**/*.js \ + test/**/**/*.js \ + test/**/*.js \ test/*.js test-cov: - @node node_modules/istanbul/lib/cli.js cover -x '**/examples/**' \ - ./node_modules/mocha/bin/_mocha test/*.js -- \ + @node node_modules/istanbul/lib/cli.js cover -x '**/examples/**' -x '**/lib/**' \ + ./node_modules/mocha/bin/_mocha test/*.js test/**/*.js test/**/**/*.js -- \ --require @babel/register \ --reporter $(REPORTER) \ + --exclude test/failing/*.js \ + test/**/**/*.js \ + test/**/*.js \ test/*.js \ diff --git a/README.md b/README.md index 8a296e0..8c7d303 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,25 @@ Create awesome REST APIs abide by [OData Protocol v4](http://www.odata.org/). I [![License](http://img.shields.io/npm/l/node-odata.svg?style=flat)](https://raw.githubusercontent.com/zackyang000/node-odata/master/LICENSE) ```JavaScript -var odata = require('node-odata'); - -var server = odata('mongodb://localhost/my-app'); - -server.resource('books', { +const odata = require('node-odata'); +const server = odata('mongodb://localhost/my-app'); +const mongoose = require('mongoose'); +const connection = mongoose.connect('mongodb://localhost:27017/example', null, (err) => { + if (err) { + console.error(err.message); + console.error('Failed to connect to database on startup.'); + process.exit(); + } +}); +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; +const ModelSchema = new Schema({ title: String, price: Number }); +const Model = mongoose.model('books', ModelSchema); + +server.mongoEntity('books', Model); server.listen(3000); ``` @@ -27,11 +38,12 @@ Registers the following routes: ``` GET /books -GET /books(:id) +GET /books(':id') POST /books -PUT /books(:id) -DELETE /books(:id) +PUT /books(':id') +DELETE /books(':id') GET /books/$metadata +GET /books/$count ``` Use the following OData query: @@ -43,22 +55,524 @@ GET /books?$top=3&$skip=2 GET /books?$orderby=price desc GET /books?$filter=price gt 10 GET /books/$metadata +GET /books/$count GET ... ``` ### Further options -The odata constructor takes 3 arguments: ```odata(, , );``` +The odata constructor takes 2 arguments: ```odata(, );``` The options object currently only supports one parameter: ```expressRequestLimit```, this will be parsed to the express middelware as the "limit" option, which allows for configuring express to support larger requests. It can be either a number or a string like "50kb", 20mb", etc. +# How to + +## With MongoDB + +For MongoDB, the entity and singleton operations have been implemented, so they require very little code to provide collections via OData. The database is decoupled from the OData implementation, so you need to inject the database connection first. This happens as follows: + +```JavaScript +const mongoose = require('mongoose'); +const connection = mongoose.connect('mongodb://localhost:27017/example', null, (err) => { + if (err) { + console.error(err.message); + console.error('Failed to connect to database on startup.'); + process.exit(); + } +}); +const odata = require('node.odata'); +const server = odata(); + +server.addBefore((req, res, next) => { + req.$odata = { + ...req.$odata, + mongo: connection + }; + next(); +}); +``` +You then have to define the collection as usual. + +```JavaScript +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; +const ModelSchema = new Schema(...); +const Model = mongoose.model(...); +``` + +Afterwards, providing the collections is very easy. + +```JavaScript +server.entity('book', Model); + +// or singleton +server.singleton('config', Model); +``` + +For inserting code before or after the standard operations, you can use [Hooks](#hooks). In the after hook you find the result of the standard operation in res.$odata.result. + +## Custom implementation + +If the standard implementation cannot be used, you have the option of implementing an entity or singleton yourself. If you have injected the database as stated above, it will be available in the middlewares in req.$odata.mongo. The following things should be taken into account when implementing your own implementations: + +- The result must be written to res.$odata.result +- An http status must be written in req.$odata.status +- the next callback must be called at the end +- The response process should not be terminated. +- No data should be written to the response +- The status of the response should not be set + +### Entities + +With entities you can provide a kind of virtual table via the OData service. The following operations can be implemented on an entity: + - list: Returns one or more items from the list. The result array must be encapsulated in a property named "value". e.g.({value: []}) + - get: Returns exactly one item + - post: Creates a new Item + - put: Updates an existing item + - delete: Deletes an exsiting item + - patch: Merges properties of an existing items with incomming attributes + - count: Returns a count of items in the list + +Here an example of an entity implementation. To define an entity, you must call the server.entity method. Pass the name of the entity as the first parameter. The second parameter allows you to pass the implementation for each operation. If you do not pass a handler for an operation, calling that operation returns "Not Implemented". With the third parameter you pass the description of your entity. An object with the $Key property in which you list the names of all key columns. The other properties of the object describe the properties of your entity. + +```JavaScript +const odata = require('node-odata'); +const server = odata(); + +server.complexType('fullName', { + first: { + $Type: 'Edm.String' + }, + last: { + $Type: 'Edm.String' + } +}); + +const entity = server.entity('user', { + list: (req, res, next) => { + try { + res.$odata.status = 200; + res.$odata.result = { + value: [{ + id: '1', + name: { first: 'Max', last: 'Mustermann' } + }] + }; + + next(); + + } catch(error) { + next(error); + } + + }, + count: async (req, res) => { + try { + res.$odata.status = 200; + res.$odata.result = 1; + + next(); + + } catch(error) { + next(error); + } + } +}, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + name: { + $Type: 'node.odata.fullName' + }, + email: { + $Type: 'Edm.String' + } +}); +``` + +### Singleton + +With a Singleton entity, you don't provide a collection via OData, but rather a single object. Compared to Entity, Singleton does not support list and count operations. The difference lies in the URL of get requests too. This is what the requests for the currentUser singleton would look like. + +``` +GET current-user +POST current-user +PUT current-user +DELETE current-user +``` + +Singleton can be defined standalone. + +```JavaScript +const odata = require('node-odata'); +const server = odata(); + +const entity = server.singleton('user', { + get: (req, res, next) => { + try { + res.$odata.status = req.user ? 200 : 403; + res.$odata.result = req.user; + + next(); + + } catch(error) { + next(error); + } + + } +}, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + email: { + $Type: 'Edm.String' + } +}); +``` + +Or a singleton can be created for an existing entity. + +```JavaScript +const odata = require('node-odata'); +const server = odata(); + +... + +const user = server.mongoEntity('user', Model); +server.singletonFrom('current-user', { + get: (req, res, next) => { + res.$odata.status = req.user ? 200 : 403; + res.$odata.result = req.user; + + next(); + } +}, user); +``` + +## Actions + +### Unbound Actions + +Unbound Action will be defined over server directly. + +```JavaScript +server.action('login', async function(req, res) { + try { + // in req.$odata.mongo is your db instance + + res.$odata.result = await req.$odata.mongo.user.findOne({ + email: req.body.email + }); + + next(); + + } catch(error) { + next(error); + } +}); +``` + +Calling an unbound action + +``` +POST /node.odata.login +``` + +### Bound Actions + +Bound Action are defined over entity. An action can be bound to single entity or to collection of entities. For the bound action, the first parameter of the bound entity type is specified in the metadata. + +#### Entity Actions + +```JavaScript +entity.action('bound-action', (req, res) => { + ... +}, { binding: 'entity' }); +``` + +will be called + +``` +POST /book('01234')/bound-action +``` + +#### Collection Actions + +```JavaScript +entity.action('bound-action', (req, res) => { + ... +}, { binding: 'collection' }); +``` + +will be called + +``` +POST /book/bound-action +``` + +### Implementation of an action + +The interface of the passed function must correspond to the nodejs express middleware. You should assign the result to the res.$odata.result attribute. An error can be thrown and it can contain the status attribute. + +```JavaScript +server.action('login', async function(req, res) { + try { + // in req.$odata.mongo is your db instance + + res.$odata.result = { + user: await req.$odata.mongo.user.findOne({ + email: req.body.email + }) + }; + + if (!res.$odata.result) { + const err = new Error('Login failed'); + + err.status = 403; + throw err; + } + + next(); + + } catch(error) { + next(error); + } +}); +``` + + +### Parameter + +Parameters can be defined for the action. These will be output in the metadata. + +```JavaScript +server.action('login', async function(req, res, next) { + ... +}, { + $Parameter: [{ + $Type: 'Edm.String', + $Name: 'email' + }, { + $Type: 'Edm.String', + $Name: 'password' + }] +}); +``` +The following attributes can be specified for parameters: + +- $Type Build-In Types(Edm.\*) or custom defined types(node.odata.\*) +- $Collection true/false +- $Nullable true/false +- $MaxLength Number bigger than zero +- $DefaultValue any text +- $Unicode true/false +- $SRID not negative Number + + +## Hooks + +It is possible to specify nodejs express middlewares for the actions or entities to be performed before or after the action. Any data assigned to req.$odata or res.$odata will be available on action implementation and subsequent hooks. An error thrown in the hook interrupts further processing. it is possible to provide a name of hook for tracing. You can use a [passportjs](https://www.passportjs.org/) middleware as before hook for authentication. + +```JavaScript +const action = server.action('login', ...); + +action.addBefore((req, res, next) => { + ... + res.$odata.result = { result: 'any' }; // client receives: { result: 'any' } + next(); +}); + +action.addBefore((req, res, next) => { + if (!req.user) { + const err = new Error(); + + err.status = 401; + next(err); + } +}); + +action.addAfter(async (req, res, next) => { + ... +}); +``` + +## Batch request + +node-odata is able to process a collected request. This means the client can send multiple operations with one query. The request must be sent to the $batch Url with a POST request. + +``` +POST $batch +``` + +With such body + +```Json +{ + requests: [{ + id: "1", + method: "post", + url: "/book", + body: { + title: "Guide of War and Peace" + } + }, { + id: "2", + method: "get", + url: "/book?$filter=contains(title, 'Guide')&$select=title" + }] +} +``` + +The answer could look like this + +```JSON +{ + responses: [{ + id: "1", + status: 201, + statusText: "Created", + headers: { + 'OData-Version': "4.0", + 'content-type': "application/json" + }, + body: { + id: "AFFE", + title: "Guide of War and Peace" + } + }, { + id: "2", + status: 200, + statusText: "OK", + headers: { + 'OData-Version': "4.0", + 'content-type': "application/json" + }, + body: { + value: [{ + title: "Guide of War and Peace" + }] + } + } +} +``` + +## Annotations + +At the different levels of the service, you can extend the metadata using annotations. Before an annotation can be applied, it must first be defined. Here we defined a simple annotation called 'readonly' of type 'boolean'. The scope of annotation is limited to the properties of entities and singletons. + +```Javascript +const vocabulary = server.vocabulary(); + +vocabulary.define('readonly', 'boolean', ['Property']); +``` + +The metadata can be annotated directly in your definition + +```Javascript +server.entity('book', null, { + $Key: ['id'], + id: { + ... + }, + author: { + $Type: 'Edm.String', + ...vocabulary.annotate('readonly', 'Property', true) + } +}); +``` + +or later. This variant has the advantage that the name of the property can be validated against the metadata of the entity. + +```Javascript +const book = server.entity('book', null, { + $Key: ['id'], + id: { + ... + }, + author: { + $Type: 'Edm.String' + } +}); + +book.annotateProperty('author', 'readonly', true); +``` + +The parameters of the actions can also be annotated. + +```Javascript +vocabulary.define('readonly', 'boolean', ['Parameter']); + +const action = server.action('changePassword', + (req, res, next) => { }, { + $Parameter: [{ + $Type: 'Edm.String', + $Name: 'newPassword' + }, { + ... + }] +}); + +action.annotateParameter('newPassword', 'readonly', true); +``` +In addition, complex annotations can be defined. This allows entities, singletons and actions to be annotated. The passed list is validated against the properties or parameters. + +```Javascript +const vocabulary = server.vocabulary(); + +vocabulary.define('filterable', { + item: ['property'], // property for Entities and Singletons, parameter for Actions + type: 'string' +}, ['Entity Type']); // Entiy Type, Singleton, Action + +const entity = server.entity('book', null, { + $Key: ['id'], + id: { + ... + }, + author: { + $Type: 'Edm.String' + }, + title: { + $Type: 'Edm.String' + } +}); + +entity.annotate('filterable', ['author', 'title']); +``` + +## Client support + +Clients are supported via the custom parameter ```sap-client```. Querying an entity with client support could look like this: + +``` +books?sap-client=99 +``` + + Client support is built in for Mongo Entity and Singleton. If you implement the entity handler yourself, the passed client is available to you in ```req.$odata.client```. To activate tenant support for an entity or singleton, all you need to do is specify the name of the corresponding property in the collection. + +```Javascript +const BookSchema = new Schema({ + MANDT: String + author: String +}); + +const BookModel = mongoose.model('Book', BookSchema); + + const entity = server.entity('book', BookModel); + + entity.clientField = 'MANDT'; + ``` ## Current State node-odata is currently at an beta stage, it is stable but not 100% feature complete. node-odata is written by ECMAScript 6 then compiled by [babel](https://babeljs.io/). -It currently have to dependent on MongoDB yet. -The current target is to add more features (eg. $metadata) and make to support other database. (eg. MySQL, PostgreSQL). +It currently supports MongoDB only. +The current target is to add more features and make to support other database. (eg. MySQL, PostgreSQL). ## Installation @@ -142,11 +656,14 @@ npm install node-odata * [x] $orderby * [ ] $expand * [x] $metadata generation +* [X] Batch request +* [X] Singleton +* [X] Annotations ## CONTRIBUTING -We always welcome contributions to help make node-odata better. Please feel free to contribute to this project. The package-lock.json file was last created with node version 16.14.2. +We always welcome contributions to help make node-odata better. Please feel free to contribute to this project. The package-lock.json file was last created with node version 18.17.0. Current implementation ist tested with MongoDB version 4.4.4. ## LICENSE diff --git a/examples/complex-resource/index.js b/examples/complex-resource/index.js deleted file mode 100644 index 3edb622..0000000 --- a/examples/complex-resource/index.js +++ /dev/null @@ -1,24 +0,0 @@ -var odata = require('../../'); - -server = odata('mongodb://localhost/odata-test'); - -var order = { - custom: { - id: String, - name: String - }, - orderItems: [{ - quantity: Number, - product: { - id: String, - name: String, - price: Number - } - }] -}; - -server.resource('orders', order); - -server.listen(3000, function(){ - console.log('OData services has started, you can visit by http://localhost:3000/orders'); -}); diff --git a/examples/db.js b/examples/db.js new file mode 100644 index 0000000..818e7f0 --- /dev/null +++ b/examples/db.js @@ -0,0 +1,28 @@ +const mongoose = require('mongoose'); +const server = require('./server'); + +server.addBefore(async (req, res, next) => { + try { + req.$odata = { + ...req.$odata, + mongo: await mongoose.connect(process.env.DATABASE || 'mongodb://localhost:27017/odata-test') + }; + + next(); + + } catch(err) { + console.error(err.message); + console.error('Failed to connect to database on startup.'); + process.exit(); + } + +}); + +// provide a event listener to handle not able to connect DB. +// events +mongoose.connection.on('connected', function () { + console.log('MongoDB connected!'); +}); +mongoose.connection.on('disconnected', function () { + console.log('MongoDB disconnected!'); +}); \ No newline at end of file diff --git a/examples/entities/book/50off.js b/examples/entities/book/50off.js new file mode 100644 index 0000000..ba09388 --- /dev/null +++ b/examples/entities/book/50off.js @@ -0,0 +1,10 @@ +module.exports = function(req, res, next){ + req.$odata.mongo.Books.findById(req.$odata.$Key.id, function(err, book){ + book.price = +(book.price / 2).toFixed(2); + book.save(function(err){ + res.$odata.result = book.toObject(); + res.$odata.status = 200; + next(); + }); + }); +}; \ No newline at end of file diff --git a/examples/entities/book/db.js b/examples/entities/book/db.js new file mode 100644 index 0000000..a066d2a --- /dev/null +++ b/examples/entities/book/db.js @@ -0,0 +1,25 @@ +const mongoose = require('mongoose'); + +const Schema = mongoose.Schema; + +const data = { + author: String, + description: String, + genre: String, + price: Number, + publish_date: Date, + title: String +}; + +const ModelSchema = new Schema(data, + { + timestamps: true, + toObject: { + virtuals: true, + }, + toJSON: { + virtuals: true, + }, + }); + +module.exports = mongoose.model('Books', ModelSchema); \ No newline at end of file diff --git a/examples/entities/book/index.js b/examples/entities/book/index.js new file mode 100644 index 0000000..1647551 --- /dev/null +++ b/examples/entities/book/index.js @@ -0,0 +1,8 @@ +const bookModel = require('./db'); +const server = require('../../server'); +const _50off = require('./50off'); +const bookEntity = server.mongoEntity('book', bookModel); + +bookEntity.action('50off', _50off, { + binding: 'entity' +}); \ No newline at end of file diff --git a/examples/entities/complex-resource/db.js b/examples/entities/complex-resource/db.js new file mode 100644 index 0000000..4825131 --- /dev/null +++ b/examples/entities/complex-resource/db.js @@ -0,0 +1,31 @@ +const mongoose = require('mongoose'); + +const Schema = mongoose.Schema; + +const data = { + custom: { + id: String, + name: String + }, + orderItems: [{ + quantity: Number, + product: { + id: String, + name: String, + price: Number + } + }] +}; + +const ModelSchema = new Schema(data, + { + timestamps: true, + toObject: { + virtuals: true, + }, + toJSON: { + virtuals: true, + }, + }); + +module.exports = mongoose.model('ComplexResource', ModelSchema); \ No newline at end of file diff --git a/examples/entities/complex-resource/index.js b/examples/entities/complex-resource/index.js new file mode 100644 index 0000000..5c790fa --- /dev/null +++ b/examples/entities/complex-resource/index.js @@ -0,0 +1,4 @@ +const server = require('../../server'); +const comlexResource = require('./db'); + +server.mongoEntity('complex-resource', comlexResource); \ No newline at end of file diff --git a/examples/entities/user/db.js b/examples/entities/user/db.js new file mode 100644 index 0000000..ef4138a --- /dev/null +++ b/examples/entities/user/db.js @@ -0,0 +1,24 @@ +const mongoose = require('mongoose'); + +const Schema = mongoose.Schema; + +const data = { + name: String, + password: { + type: String, + select: false + } +}; + +const ModelSchema = new Schema(data, + { + timestamps: true, + toObject: { + virtuals: true, + }, + toJSON: { + virtuals: true, + }, + }); + +module.exports = mongoose.model('Users', ModelSchema); \ No newline at end of file diff --git a/examples/entities/user/index.js b/examples/entities/user/index.js new file mode 100644 index 0000000..b00a370 --- /dev/null +++ b/examples/entities/user/index.js @@ -0,0 +1,4 @@ +const server = require('../../server'); +const user = require('./db'); + +server.mongoEntity('user', user); \ No newline at end of file diff --git a/examples/functions/license.js b/examples/functions/license.js new file mode 100644 index 0000000..abd568a --- /dev/null +++ b/examples/functions/license.js @@ -0,0 +1,9 @@ +const server = require('../server'); + +server.function('license', function(req, res, next) { + res.$odata.result = { license: 'MIT' }; + res.$odata.status = 200; + next(); +}); + + diff --git a/examples/functions/server-time.js b/examples/functions/server-time.js new file mode 100644 index 0000000..0200c21 --- /dev/null +++ b/examples/functions/server-time.js @@ -0,0 +1,9 @@ +const server = require('../server'); + +server.function('server-time', function(req, res, next) { + res.$odata.result = { date: new Date() }; + res.$odata.status = 200; + next(); +}); + + diff --git a/examples/hidden-field/index.js b/examples/hidden-field/index.js deleted file mode 100644 index 6844faa..0000000 --- a/examples/hidden-field/index.js +++ /dev/null @@ -1,16 +0,0 @@ -var odata = require('../../'); - -server = odata('mongodb://localhost/odata-test'); - -server.resource('users', { - name: String, - password: { - type: String, - select: false - } -}); - -server.listen(3000, function(){ - console.log('OData services has started, you can visit by http://localhost:3000/users'); -}); - diff --git a/examples/index.js b/examples/index.js new file mode 100644 index 0000000..fc71ff0 --- /dev/null +++ b/examples/index.js @@ -0,0 +1,26 @@ +require('./db'); // database connection +require('./entities/complex-resource'); +require('./entities/book'); +require('./entities/user'); +require('./functions/license'); +require('./functions/server-time'); + +const server = require('./server'); +const bookModel = require('./entities/book/db'); + +// add some test data +const data = require('../test/support/books.json'); +bookModel.deleteMany({}).then(function() { + data.forEach(function(item) { + const parseditem = JSON.parse(JSON.stringify(item)); + + delete parseditem.id; + entity = new bookModel(parseditem); + entity.save(); + }); +}); + +// server start +server.listen(3000, function(){ + console.log('OData services has started, you can visit by http://localhost:3000/'); +}); \ No newline at end of file diff --git a/examples/multi-resource/functions/license.js b/examples/multi-resource/functions/license.js deleted file mode 100644 index 7481149..0000000 --- a/examples/multi-resource/functions/license.js +++ /dev/null @@ -1,10 +0,0 @@ -var func = require('../../../').Function; - -var router = func(); - -router.get('/license', function(req, res, next) { - res.jsonp({ license: 'MIT' }); -}); - -module.exports = router; - diff --git a/examples/multi-resource/functions/server-time.js b/examples/multi-resource/functions/server-time.js deleted file mode 100644 index 7d2844d..0000000 --- a/examples/multi-resource/functions/server-time.js +++ /dev/null @@ -1,11 +0,0 @@ -var func = require('../../../').Function; - -var router = func(); - -router.get('/server-time', function(req, res, next) { - res.jsonp({ date: new Date() }); -}); - -module.exports = router; - - diff --git a/examples/multi-resource/index.js b/examples/multi-resource/index.js deleted file mode 100644 index 6685c8f..0000000 --- a/examples/multi-resource/index.js +++ /dev/null @@ -1,16 +0,0 @@ -var odata = require('../../'); - -var server = odata('mongodb://localhost/odata-test'); - -// init resources -server.use(requiere('./resources/book')); -server.use(requiere('./resources/user')); - -// init functions -server.use(requiere('./functions/license')); -server.use(requiere('./functions/server-time')); - -server.listen(3000, function(){ - console.log('OData services has started, you can visit by http://localhost:3000'); -}); - diff --git a/examples/multi-resource/resources/book.js b/examples/multi-resource/resources/book.js deleted file mode 100644 index a3d4279..0000000 --- a/examples/multi-resource/resources/book.js +++ /dev/null @@ -1,10 +0,0 @@ -var Resource = require('../../../').Resource; - -module.exports = Resource('book', { - author: String, - description: String, - genre: String, - price: Number, - publish_date: Date, - title: String -}); diff --git a/examples/multi-resource/resources/user.js b/examples/multi-resource/resources/user.js deleted file mode 100644 index 7eaa314..0000000 --- a/examples/multi-resource/resources/user.js +++ /dev/null @@ -1,6 +0,0 @@ -var Resource = require('../../../').Resource; - -module.exports = Resource('user', { - name: String, - password: String -}); diff --git a/examples/server.js b/examples/server.js new file mode 100644 index 0000000..dbe6e22 --- /dev/null +++ b/examples/server.js @@ -0,0 +1,3 @@ +const odata = require('../'); + +module.exports = odata(); \ No newline at end of file diff --git a/examples/simple-with-data/index.js b/examples/simple-with-data/index.js deleted file mode 100644 index f1f17c0..0000000 --- a/examples/simple-with-data/index.js +++ /dev/null @@ -1,11 +0,0 @@ -var server = require('../simple/'); -var data = require("../../test/support/books.json"); - -model = server._db.model('book'); - -model.remove({}, function(err, result) { - data.map(function(item) { - entity = new model(item); - entity.save(); - }); -}); diff --git a/examples/simple/index.js b/examples/simple/index.js deleted file mode 100644 index 109ca03..0000000 --- a/examples/simple/index.js +++ /dev/null @@ -1,39 +0,0 @@ -var odata = require('../../'); - -var server = odata('mongodb://localhost/odata-test'); - -var bookInfo = { - author: String, - description: String, - genre: String, - price: Number, - publish_date: Date, - title: String -}; - -server.resource('book', bookInfo) - .action('/50off', function(req, res, next){ - server.repository('book').findById(req.params.id, function(err, book){ - book.price = +(book.price / 2).toFixed(2); - book.save(function(err){ - res.jsonp(book); - }); - }); - }); - -server.get('/license', function(req, res, next){ - res.jsonp({license:'MIT'}); -}); - -server.on('connected', function() { - console.log('MongoDB connected!'); -}); -server.on('disconnected', function() { - console.log('MongoDB disconnected!'); -}); - -server.listen(3000, function(){ - console.log('OData services has started, you can visit by http://localhost:3000/book'); -}); - -module.exports = server; diff --git a/package-lock.json b/package-lock.json index 5b22247..325be1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,61 +1,70 @@ { "name": "node-odata", - "version": "0.7.16", + "version": "0.1.0-alpha.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "node-odata", - "version": "0.7.16", + "version": "0.1.0-alpha.0", "license": "MIT", "dependencies": { - "body-parser": "^1.20.0", + "body-parser": "^1.20.2", "cors": "2.8.5", - "express": "^4.18.1", + "express": "^4.18.2", "method-override": "3.0.0", - "mongoose": "6.6.5", + "mongoose": "7.4.2", "uuid": "9.0.0" }, "devDependencies": { - "@babel/cli": "^7.19.3", - "@babel/core": "^7.19.3", - "@babel/eslint-parser": "^7.19.1", - "@babel/helpers": "^7.19.0", - "@babel/plugin-proposal-class-properties": "^7.0.0", - "@babel/plugin-proposal-decorators": "^7.0.0", - "@babel/plugin-proposal-do-expressions": "^7.0.0", - "@babel/plugin-proposal-export-default-from": "^7.0.0", - "@babel/plugin-proposal-export-namespace-from": "^7.0.0", - "@babel/plugin-proposal-function-bind": "^7.0.0", - "@babel/plugin-proposal-function-sent": "^7.0.0", - "@babel/plugin-proposal-json-strings": "^7.0.0", - "@babel/plugin-proposal-logical-assignment-operators": "^7.0.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0", - "@babel/plugin-proposal-numeric-separator": "^7.0.0", - "@babel/plugin-proposal-optional-chaining": "^7.0.0", - "@babel/plugin-proposal-pipeline-operator": "^7.0.0", - "@babel/plugin-proposal-throw-expressions": "^7.0.0", - "@babel/plugin-syntax-dynamic-import": "^7.0.0", - "@babel/plugin-syntax-import-meta": "^7.0.0", - "@babel/preset-env": "^7.19.3", - "@babel/register": "^7.18.9", - "@babel/runtime": "^7.19.0", - "babel-loader": "8.2.5", - "eslint": "8.24.0", + "@babel/cli": "^7.22.9", + "@babel/core": "^7.22.9", + "@babel/eslint-parser": "^7.22.9", + "@babel/helpers": "^7.22.6", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-decorators": "^7.22.7", + "@babel/plugin-proposal-do-expressions": "^7.22.5", + "@babel/plugin-proposal-export-default-from": "^7.22.5", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-function-bind": "^7.22.5", + "@babel/plugin-proposal-function-sent": "^7.22.5", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.20.7", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.21.0", + "@babel/plugin-proposal-pipeline-operator": "^7.22.5", + "@babel/plugin-proposal-throw-expressions": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/preset-env": "^7.22.9", + "@babel/register": "^7.22.5", + "@babel/runtime": "^7.22.6", + "babel-loader": "9.1.3", + "eslint": "8.46.0", "eslint-config-airbnb": "19.0.4", "eslint-plugin-babel": "5.3.1", - "eslint-plugin-import": "^2.26.0", + "eslint-plugin-import": "^2.28.0", "istanbul": "1.1.0-alpha.1", - "mocha": "10.0.0", + "mocha": "10.2.0", "should": "13.2.3", "should-sinon": "0.0.6", - "sinon": "14.0.1", - "supertest": "6.3.0" + "sinon": "15.2.0", + "supertest": "6.3.3" }, "engines": { "node": ">=0.12" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", @@ -70,12 +79,12 @@ } }, "node_modules/@babel/cli": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.19.3.tgz", - "integrity": "sha512-643/TybmaCAe101m2tSVHi9UKpETXP9c/Ff4mD2tAwkdP6esKIfaauZFc67vGEM6r9fekbEGid+sZhbEnSe3dg==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.22.9.tgz", + "integrity": "sha512-nb2O7AThqRo7/E53EGiuAkMaRbb7J5Qp3RvN+dmua1U+kydm0oznkhqbTEG15yk26G/C3yL6OdZjzgl+DMXVVA==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.8", + "@jridgewell/trace-mapping": "^0.3.17", "commander": "^4.0.1", "convert-source-map": "^1.1.0", "fs-readdir-recursive": "^1.1.0", @@ -139,47 +148,47 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.3.tgz", - "integrity": "sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz", - "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", - "@babel/helper-compilation-targets": "^7.19.3", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.3", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.3", - "@babel/types": "^7.19.3", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", + "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.8", + "@babel/types": "^7.22.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" + "json5": "^2.2.2", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -206,18 +215,6 @@ } } }, - "node_modules/@babel/core/node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@babel/core/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -225,23 +222,23 @@ "dev": true }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/eslint-parser": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", - "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.22.9.tgz", + "integrity": "sha512-xdMkt39/nviO/4vpVdrEYPwXCsYIXSSAr6mC7WQsNIlGnuxKyKE7GZjalcnbSWiC4OXGNNN3UQPeHfjSC6sTDA==", "dev": true, "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || >=14.0.0" @@ -261,22 +258,23 @@ } }, "node_modules/@babel/eslint-parser/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz", - "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", + "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", "dev": true, "dependencies": { - "@babel/types": "^7.19.3", + "@babel/types": "^7.22.5", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "engines": { @@ -310,40 +308,40 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", - "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.5.tgz", + "integrity": "sha512-m1EP3lVOPptR+2DwD125gziZNcmoNSHGmJROKoy87loWUQyJaVXDgpmruWqDARZSmtYQ+Dl25okU8+qhVzuykw==", "dev": true, "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.18.6", - "@babel/types": "^7.18.9" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", - "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz", + "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.19.3", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.5", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -353,27 +351,29 @@ } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", - "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.9.tgz", + "integrity": "sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.9", - "@babel/helper-split-export-declaration": "^7.18.6" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -382,14 +382,24 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", - "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.9.tgz", + "integrity": "sha512-+svjVa/tFwsNSG4NEy1h85+HQ5imbT92Q5/bgtS7P0GTQlP8WuFdqsiABmQouhiFGyV66oGxZFpeYHza1rNsKw==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "regexpu-core": "^5.1.0" + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -398,21 +408,29 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz", + "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" + "resolve": "^1.14.2" }, "peerDependencies": { - "@babel/core": "^7.4.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { @@ -438,135 +456,113 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", - "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", "dev": true, "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", - "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz", + "integrity": "sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==", "dev": true, "dependencies": { - "@babel/types": "^7.18.9" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", + "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", - "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz", + "integrity": "sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-wrap-function": "^7.18.9", - "@babel/types": "^7.18.9" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-wrap-function": "^7.22.9" }, "engines": { "node": ">=6.9.0" @@ -576,120 +572,120 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", - "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz", + "integrity": "sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", - "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", "dev": true, "dependencies": { - "@babel/types": "^7.18.9" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", - "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.9.tgz", + "integrity": "sha512-sZ+QzfauuUEfxSEjKFmi3qDSHgLsTPK/pEpoD/qonZKOtTPTLbf59oabPQ4rKekt9lFcj/hTZaOhWwFYrgjk+Q==", "dev": true, "dependencies": { - "@babel/helper-function-name": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz", + "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==", "dev": true, "dependencies": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.6", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.22.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -751,9 +747,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", + "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -763,12 +759,12 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", - "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz", + "integrity": "sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -778,14 +774,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", - "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz", + "integrity": "sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", - "@babel/plugin-proposal-optional-chaining": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -794,24 +790,6 @@ "@babel/core": "^7.13.0" } }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz", - "integrity": "sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-proposal-class-properties": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", @@ -828,34 +806,17 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", - "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.19.3.tgz", - "integrity": "sha512-MbgXtNXqo7RTKYIXVchVJGPvaVufQH3pxvQyfbGvNw1DObIhph+PesYXJTcd8J4DdWibvf6Z2eanOyItX8WnJg==", + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.22.7.tgz", + "integrity": "sha512-omXqPF7Onq4Bb7wHxXjM3jSMSJvUUbvDvmmds7KI5n9Cq6Ln5I05I1W2nRlRof1rGdiUxJrxwe285WF96XlBXQ==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-replace-supers": "^7.19.1", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/plugin-syntax-decorators": "^7.19.0" + "@babel/helper-create-class-features-plugin": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/plugin-syntax-decorators": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -865,29 +826,13 @@ } }, "node_modules/@babel/plugin-proposal-do-expressions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-do-expressions/-/plugin-proposal-do-expressions-7.18.6.tgz", - "integrity": "sha512-ddToGCONJhCuL+l4FhtGnKl5ZYCj9fDVFiqiCdQDpeIbVn/NvMeSib+7T1/rk08jRafae4qNiP8OnJyuqlsuYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-do-expressions": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-do-expressions/-/plugin-proposal-do-expressions-7.22.5.tgz", + "integrity": "sha512-Qh6Sbkt6xCRbHykDc709db/EQB4RJlmaW3ENuvzzi7G6GKeDNQHx81P0OdI9oEXhhHEJvLRzIr08m8HNCJWS8g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-do-expressions": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -897,13 +842,13 @@ } }, "node_modules/@babel/plugin-proposal-export-default-from": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.18.10.tgz", - "integrity": "sha512-5H2N3R2aQFxkV4PIBUR/i7PUSwgTZjouJKzI8eKswfIjT0PhvzkPn0t0wIS5zn6maQuvtT0t1oHtMUz61LOuow==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.22.5.tgz", + "integrity": "sha512-UCe1X/hplyv6A5g2WnQ90tnHRvYL29dabCWww92lO7VdfMVTVReBTRrhiMrKQejHD9oVkdnRdwYuzUZkBVQisg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-default-from": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-default-from": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -929,13 +874,13 @@ } }, "node_modules/@babel/plugin-proposal-function-bind": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-function-bind/-/plugin-proposal-function-bind-7.18.9.tgz", - "integrity": "sha512-9RfxqKkRBCCT0xoBl9AqieCMscJmSAL9HYixGMWH549jUpT9csWWK/HEYZEx9t9iW/PRSXgX95x9bDlgtAJGFA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-function-bind/-/plugin-proposal-function-bind-7.22.5.tgz", + "integrity": "sha512-ckAugfDtdcrXKP49z7K7JI7QkA8SRidmsKxLizH8mg0UWOvcmvEd9/VDLzFcWlZqchvLDPUYpwuXNGAYjsscrw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-function-bind": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-function-bind": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -945,14 +890,14 @@ } }, "node_modules/@babel/plugin-proposal-function-sent": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-function-sent/-/plugin-proposal-function-sent-7.18.6.tgz", - "integrity": "sha512-UdaOKPOLPt0O+Xu26tnw6oAZMLXhk+yMrXOzn6kAzTHBnWHJsoN1hlrgxFAQ+FRLS0ql1oYIQ2phvoFzmN3GMw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-function-sent/-/plugin-proposal-function-sent-7.22.5.tgz", + "integrity": "sha512-YFEE5KDhaNCCD0I1j9vqPp5bpPuoDAPD+4Adk0QXdrL9TbmZluCuznuYvmlYqr14zfXCBGAZivfiLb6WI4GhSw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-wrap-function": "^7.18.6", - "@babel/plugin-syntax-function-sent": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-wrap-function": "^7.22.5", + "@babel/plugin-syntax-function-sent": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -978,12 +923,12 @@ } }, "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", - "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", + "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { @@ -1025,49 +970,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz", - "integrity": "sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.18.8", - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.18.8" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", - "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { @@ -1078,29 +988,13 @@ } }, "node_modules/@babel/plugin-proposal-pipeline-operator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-pipeline-operator/-/plugin-proposal-pipeline-operator-7.18.9.tgz", - "integrity": "sha512-Pc33e6m8f4MJhRXVCUwiKZNtEm+W2CUPHIL0lyJNtkp+w6d75CLw3gsBKQ81VAMUgT9jVPIEU8gwJ5nJgmJ1Ag==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-pipeline-operator": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-pipeline-operator/-/plugin-proposal-pipeline-operator-7.22.5.tgz", + "integrity": "sha512-nSgHJB3uP+DORxBVhQgjub0qtU/LGj/mBDz2kQEGy1EUDy3f92VWDeB3J3/41ZjVLWmkNWOd6yjdNb4a5wDfZQ==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-pipeline-operator": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1110,16 +1004,10 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", - "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, "engines": { "node": ">=6.9.0" }, @@ -1128,13 +1016,13 @@ } }, "node_modules/@babel/plugin-proposal-throw-expressions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-throw-expressions/-/plugin-proposal-throw-expressions-7.18.6.tgz", - "integrity": "sha512-WHOrJyhGoGrdtW480L79cF7Iq/gZDZ/z6OqK7mVyFR5I37dTpog/wNgb6hmaM3HYZtULEJl++7VaMWkNZsOcHg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-throw-expressions/-/plugin-proposal-throw-expressions-7.22.5.tgz", + "integrity": "sha512-34kY5YjNKDhjXbj2oNDkxl0xNl2+yQTEsWu8Ia6kCTb6wz76bBCd4DzmeZokfr6g68yneu3eg8qAyYgKbyesFg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-throw-expressions": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-throw-expressions": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1199,12 +1087,12 @@ } }, "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz", - "integrity": "sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.22.5.tgz", + "integrity": "sha512-avpUOBS7IU6al8MmF1XpAyj9QYeLPuSDJI5D4pVMSMdL7xQokKqJPYQC67RCT0aCTashUXPiGwMJ0DEXXCEmMA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1214,12 +1102,12 @@ } }, "node_modules/@babel/plugin-syntax-do-expressions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-do-expressions/-/plugin-syntax-do-expressions-7.18.6.tgz", - "integrity": "sha512-kTogvOsjBTVOSZtkkziiXB5hwGXqwhq2gBXDaiWVruRLDT7C2GqfbsMnicHJ7ePq2GE8UJeWS34YbNP6yDhwUA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-do-expressions/-/plugin-syntax-do-expressions-7.22.5.tgz", + "integrity": "sha512-60pOTgQGY00/Kiozrtu286Aqg50IxDy/jIHhlMzXjYTs1Q8lbeOgqC9NLidtqfBNwdX6bZCT6FJ2i5xzt+JKzw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1241,12 +1129,12 @@ } }, "node_modules/@babel/plugin-syntax-export-default-from": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.18.6.tgz", - "integrity": "sha512-Kr//z3ujSVNx6E9z9ih5xXXMqK07VVTuqPmqGe6Mss/zW5XPeLZeSDZoP9ab/hT4wPKqAgjl2PnhPrcpk8Seew==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.22.5.tgz", + "integrity": "sha512-ODAqWWXB/yReh/jVQDag/3/tl6lgBueQkk/TcfW/59Oykm4c8a55XloX0CTk2k2VJiFWMgHby9xNX29IbCv9dQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1268,12 +1156,12 @@ } }, "node_modules/@babel/plugin-syntax-function-bind": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-function-bind/-/plugin-syntax-function-bind-7.18.6.tgz", - "integrity": "sha512-wZN0Aq/AScknI9mKGcR3TpHdASMufFGaeJgc1rhPmLtZ/PniwjePSh8cfh8tXMB3U4kh/3cRKrLjDtedejg8jQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-function-bind/-/plugin-syntax-function-bind-7.22.5.tgz", + "integrity": "sha512-Sjy7XIhHF9L++0Mk/3Y4H4439cjI//wc/jE8Ly3+qGPkTUYYEhe4rzMv/JnyZpekfOBL22X6DAq42I7GM/3KzA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1283,12 +1171,12 @@ } }, "node_modules/@babel/plugin-syntax-function-sent": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-function-sent/-/plugin-syntax-function-sent-7.18.6.tgz", - "integrity": "sha512-f3OJHIlFIkg+cP1Hfo2SInLhsg0pz2Ikmgo7jMdIIKC+3jVXQlHB0bgSapOWxeWI0SU28qIWmfn5ZKu1yPJHkg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-function-sent/-/plugin-syntax-function-sent-7.22.5.tgz", + "integrity": "sha512-tKOWGUAVv+JGJ1tcOIFdCqxUX97lgAUnmLpWt/9JtEkgk9WQ5OolN+y9rWj6mtLM+d0kAzTGLu/kRQqr5/PEsA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1298,12 +1186,27 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", - "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz", + "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz", + "integrity": "sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1409,12 +1312,12 @@ } }, "node_modules/@babel/plugin-syntax-pipeline-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-pipeline-operator/-/plugin-syntax-pipeline-operator-7.18.6.tgz", - "integrity": "sha512-pFtIdQomJtkTHWcNsGXhjJ5YUkL+AxJnP4G+Ol85UO6uT2fpHTPYLLE5bBeRA9cxf25qa/VKsJ3Fi67Gyqe3rA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-pipeline-operator/-/plugin-syntax-pipeline-operator-7.22.5.tgz", + "integrity": "sha512-7yuGXd+h8gpR14FnPDTTCd5TfC/1B9njNZJT29GJ7UFF/WVbzkZy7728DynrENqgImqj5xyPTQAo8si9n3QVJQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1439,12 +1342,12 @@ } }, "node_modules/@babel/plugin-syntax-throw-expressions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-throw-expressions/-/plugin-syntax-throw-expressions-7.18.6.tgz", - "integrity": "sha512-rp1CqEZXGv1z1YZ3qYffBH3rhnOxrTwQG8fh2yqulTurwv9zu3Gthfd+niZBLSOi1rY6146TgF+JmVeDXaX4TQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-throw-expressions/-/plugin-syntax-throw-expressions-7.22.5.tgz", + "integrity": "sha512-oCyfA7rDVcQIydA7ZOmnHCQTzz5JvG9arY++Z+ASL/q5q+mJLblaRNHoK6ggV54X2c14wCK/lQi7z1DujmEmZA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1468,30 +1371,29 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-arrow-functions": { + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", - "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", - "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz", + "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-remap-async-to-generator": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1500,13 +1402,16 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", - "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.7.tgz", + "integrity": "sha512-7HmE7pk/Fmke45TODvxvkxRMV9RazV+ZZzhOL9AG8G29TLrr3jkjwF7uJfxZ30EoXpO+LJkq4oA8NjO2DTnEDg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5", + "@babel/plugin-syntax-async-generators": "^7.8.4" }, "engines": { "node": ">=6.9.0" @@ -1515,13 +1420,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz", - "integrity": "sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw==", + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz", + "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1530,21 +1437,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", - "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-replace-supers": "^7.18.9", - "@babel/helper-split-export-declaration": "^7.18.6", - "globals": "^11.1.0" + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz", + "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1553,22 +1452,13 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", - "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz", + "integrity": "sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1577,13 +1467,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.18.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.13.tgz", - "integrity": "sha512-TodpQ29XekIsex2A+YJPj5ax2plkGa8YYY6mFjCohk/IG9IY42Rtuj1FuDeemfg2ipxIFLzPeA83SIBnlhSIow==", + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz", + "integrity": "sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1592,29 +1483,125 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", - "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz", + "integrity": "sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.12.0" } }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", - "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "node_modules/@babel/plugin-transform-classes": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz", + "integrity": "sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", + "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz", + "integrity": "sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz", + "integrity": "sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz", + "integrity": "sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz", + "integrity": "sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1624,13 +1611,29 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", - "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz", + "integrity": "sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==", "dev": true, "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz", + "integrity": "sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1640,12 +1643,12 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", - "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz", + "integrity": "sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1655,14 +1658,30 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", - "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz", + "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz", + "integrity": "sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1672,12 +1691,28 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", - "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz", + "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz", + "integrity": "sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" }, "engines": { "node": ">=6.9.0" @@ -1687,12 +1722,12 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", - "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz", + "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1702,14 +1737,13 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz", - "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz", + "integrity": "sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1719,15 +1753,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz", - "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz", + "integrity": "sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1737,16 +1770,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.0.tgz", - "integrity": "sha512-x9aiR0WXAWmOWsqcsnrzGR+ieaTMVyGyffPVA7F8cXAGt/UxefYv6uSHZLkAFChN5M5Iy1+wjE+xJuPt22H39A==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz", + "integrity": "sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ==", "dev": true, "dependencies": { - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-validator-identifier": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1756,13 +1788,13 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", - "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz", + "integrity": "sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1772,13 +1804,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", - "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1788,12 +1820,63 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", - "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz", + "integrity": "sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz", + "integrity": "sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz", + "integrity": "sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz", + "integrity": "sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1803,13 +1886,46 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", - "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz", + "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz", + "integrity": "sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.6.tgz", + "integrity": "sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "engines": { "node": ">=6.9.0" @@ -1819,12 +1935,46 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", - "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz", + "integrity": "sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz", + "integrity": "sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz", + "integrity": "sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" }, "engines": { "node": ">=6.9.0" @@ -1834,12 +1984,12 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", - "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz", + "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1849,13 +1999,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", - "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz", + "integrity": "sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "regenerator-transform": "^0.15.0" + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.1" }, "engines": { "node": ">=6.9.0" @@ -1865,12 +2015,12 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", - "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz", + "integrity": "sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1880,12 +2030,12 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", - "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz", + "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1895,13 +2045,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", - "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz", + "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1911,12 +2061,12 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", - "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz", + "integrity": "sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1926,12 +2076,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", - "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz", + "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1941,12 +2091,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", - "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz", + "integrity": "sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1956,12 +2106,28 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", - "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz", + "integrity": "sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz", + "integrity": "sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1971,13 +2137,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", - "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz", + "integrity": "sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -1986,39 +2152,43 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz", + "integrity": "sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/preset-env": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.3.tgz", - "integrity": "sha512-ziye1OTc9dGFOAXSWKUqQblYHNlBOaDl8wzqf2iKXJAltYiR3hKHUKmkt+S9PppW7RQpq4fFCrwwpIDj/f5P4w==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.19.3", - "@babel/helper-compilation-targets": "^7.19.3", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-async-generator-functions": "^7.19.1", - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.18.6", - "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.18.9", - "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.18.6", - "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.9.tgz", + "integrity": "sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.5", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.18.6", + "@babel/plugin-syntax-import-assertions": "^7.22.5", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -2028,45 +2198,62 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.18.6", - "@babel/plugin-transform-async-to-generator": "^7.18.6", - "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.18.9", - "@babel/plugin-transform-classes": "^7.19.0", - "@babel/plugin-transform-computed-properties": "^7.18.9", - "@babel/plugin-transform-destructuring": "^7.18.13", - "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.9", - "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.8", - "@babel/plugin-transform-function-name": "^7.18.9", - "@babel/plugin-transform-literals": "^7.18.9", - "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.18.6", - "@babel/plugin-transform-modules-commonjs": "^7.18.6", - "@babel/plugin-transform-modules-systemjs": "^7.19.0", - "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", - "@babel/plugin-transform-new-target": "^7.18.6", - "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.18.8", - "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.18.6", - "@babel/plugin-transform-reserved-words": "^7.18.6", - "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.19.0", - "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.9", - "@babel/plugin-transform-typeof-symbol": "^7.18.9", - "@babel/plugin-transform-unicode-escapes": "^7.18.10", - "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.22.5", + "@babel/plugin-transform-async-generator-functions": "^7.22.7", + "@babel/plugin-transform-async-to-generator": "^7.22.5", + "@babel/plugin-transform-block-scoped-functions": "^7.22.5", + "@babel/plugin-transform-block-scoping": "^7.22.5", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-class-static-block": "^7.22.5", + "@babel/plugin-transform-classes": "^7.22.6", + "@babel/plugin-transform-computed-properties": "^7.22.5", + "@babel/plugin-transform-destructuring": "^7.22.5", + "@babel/plugin-transform-dotall-regex": "^7.22.5", + "@babel/plugin-transform-duplicate-keys": "^7.22.5", + "@babel/plugin-transform-dynamic-import": "^7.22.5", + "@babel/plugin-transform-exponentiation-operator": "^7.22.5", + "@babel/plugin-transform-export-namespace-from": "^7.22.5", + "@babel/plugin-transform-for-of": "^7.22.5", + "@babel/plugin-transform-function-name": "^7.22.5", + "@babel/plugin-transform-json-strings": "^7.22.5", + "@babel/plugin-transform-literals": "^7.22.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.22.5", + "@babel/plugin-transform-member-expression-literals": "^7.22.5", + "@babel/plugin-transform-modules-amd": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.22.5", + "@babel/plugin-transform-modules-systemjs": "^7.22.5", + "@babel/plugin-transform-modules-umd": "^7.22.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.22.5", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.5", + "@babel/plugin-transform-numeric-separator": "^7.22.5", + "@babel/plugin-transform-object-rest-spread": "^7.22.5", + "@babel/plugin-transform-object-super": "^7.22.5", + "@babel/plugin-transform-optional-catch-binding": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.6", + "@babel/plugin-transform-parameters": "^7.22.5", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.5", + "@babel/plugin-transform-property-literals": "^7.22.5", + "@babel/plugin-transform-regenerator": "^7.22.5", + "@babel/plugin-transform-reserved-words": "^7.22.5", + "@babel/plugin-transform-shorthand-properties": "^7.22.5", + "@babel/plugin-transform-spread": "^7.22.5", + "@babel/plugin-transform-sticky-regex": "^7.22.5", + "@babel/plugin-transform-template-literals": "^7.22.5", + "@babel/plugin-transform-typeof-symbol": "^7.22.5", + "@babel/plugin-transform-unicode-escapes": "^7.22.5", + "@babel/plugin-transform-unicode-property-regex": "^7.22.5", + "@babel/plugin-transform-unicode-regex": "^7.22.5", + "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.19.3", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "core-js-compat": "^3.25.1", - "semver": "^6.3.0" + "@babel/types": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.4", + "babel-plugin-polyfill-corejs3": "^0.8.2", + "babel-plugin-polyfill-regenerator": "^0.5.1", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -2076,9 +2263,9 @@ } }, "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -2101,9 +2288,9 @@ } }, "node_modules/@babel/register": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.18.9.tgz", - "integrity": "sha512-ZlbnXDcNYHMR25ITwwNKT88JiaukkdVj/nG7r3wnuXkOTHc60Uy05PwMCPre0hSkY68E6zK3xz+vUJSP2jWmcw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.22.5.tgz", + "integrity": "sha512-vV6pm/4CijSQ8Y47RH5SopXzursN35RQINfGJkmOlcpAtGuf94miFvIPhCKGQN7WGIcsgG1BHEX2KVdTYwTwUQ==", "dev": true, "dependencies": { "clone-deep": "^4.0.1", @@ -2228,13 +2415,19 @@ "node": ">=6" } }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, "node_modules/@babel/runtime": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz", - "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", "dev": true, "dependencies": { - "regenerator-runtime": "^0.13.4" + "regenerator-runtime": "^0.13.11" }, "engines": { "node": ">=6.9.0" @@ -2255,33 +2448,33 @@ } }, "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz", - "integrity": "sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.3", - "@babel/types": "^7.19.3", + "version": "7.22.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", + "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.7", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/types": "^7.22.5", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -2322,13 +2515,13 @@ "dev": true }, "node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", + "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2344,16 +2537,40 @@ "node": ">=4" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", + "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", - "integrity": "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", + "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", + "espree": "^9.6.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -2391,9 +2608,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -2417,33 +2634,30 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@eslint/eslintrc/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/@eslint/js": { + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz", + "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { - "version": "0.10.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", - "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" @@ -2472,16 +2686,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -2565,13 +2769,13 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "node_modules/@nicolo-ribaudo/chokidar-2": { @@ -2648,34 +2852,43 @@ } }, "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", "dev": true, "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.7.0" + "@sinonjs/commons": "^3.0.0" } }, "node_modules/@sinonjs/samsam": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.1.1.tgz", - "integrity": "sha512-cZ7rKJTLiE7u7Wi/v9Hc2fs3Ucc3jrWeMgPHbbTCeVAB2S0wOBbYlkJVeNSL04i7fdhT8wIbDq1zhC/PXTD2SA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.6.0", + "@sinonjs/commons": "^2.0.0", "lodash.get": "^4.4.2", "type-detect": "^4.0.8" } }, + "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, "node_modules/@sinonjs/text-encoding": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", @@ -2742,12 +2955,6 @@ "@types/webidl-conversions": "*" } }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, "node_modules/@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -2942,9 +3149,9 @@ } }, "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -2963,6 +3170,15 @@ "acorn": "^8" } }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2979,11 +3195,51 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, "node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, + "peer": true, "peerDependencies": { "ajv": "^6.9.1" } @@ -3072,21 +3328,34 @@ "node": ">=6.0" } }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, "node_modules/array-includes": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", - "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", - "get-intrinsic": "^1.1.1", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", "is-string": "^1.0.7" }, "engines": { @@ -3096,24 +3365,34 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "node_modules/array.prototype.findlastindex": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.2.tgz", + "integrity": "sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==", "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/array.prototype.flat": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", - "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -3124,15 +3403,14 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", - "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -3142,6 +3420,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -3170,6 +3468,18 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/axe-core": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz", @@ -3215,66 +3525,20 @@ } }, "node_modules/babel-loader": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", - "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", "dev": true, "dependencies": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^2.0.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" }, "engines": { - "node": ">= 8.9" + "node": ">= 14.15.0" }, "peerDependencies": { - "@babel/core": "^7.0.0", - "webpack": ">=2" - } - }, - "node_modules/babel-loader/node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/babel-loader/node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/babel-loader/node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/babel-loader/node_modules/loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" + "@babel/core": "^7.12.0", + "webpack": ">=5" } }, "node_modules/babel-messages": { @@ -3286,61 +3550,52 @@ "babel-runtime": "^6.22.0" } }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "dependencies": { - "object.assign": "^4.1.0" - } - }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz", + "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.2", + "semver": "^6.3.1" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz", + "integrity": "sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" + "@babel/helper-define-polyfill-provider": "^0.4.2", + "core-js-compat": "^3.31.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz", + "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3" + "@babel/helper-define-polyfill-provider": "^0.4.2" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-runtime": { @@ -3410,46 +3665,27 @@ "babylon": "bin/babylon.js" } }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, "node_modules/body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.10.3", - "raw-body": "2.5.1", + "qs": "6.11.0", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -3487,9 +3723,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", "dev": true, "funding": [ { @@ -3499,13 +3735,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" }, "bin": { "browserslist": "cli.js" @@ -3515,37 +3755,11 @@ } }, "node_modules/bson": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz", - "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==", - "dependencies": { - "buffer": "^5.6.0" - }, + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.4.0.tgz", + "integrity": "sha512-WRZ5SQI5GfUuKnPTNmAYPiKIof3ORXAF4IRU5UcgmivNIon01rWQlw5RUH954dpu8yGL8T59YShVddIPaU/gFA==", "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/bson/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "node": ">=14.20.1" } }, "node_modules/buffer-from": { @@ -3584,9 +3798,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001416", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001416.tgz", - "integrity": "sha512-06wzzdAkCPZO+Qm4e/eNghZBDfVNDsCgw33T27OwBH9unE9S478OYw//Q2L7Npf/zBzs7rjZOszIFQkwQKAEqA==", + "version": "1.0.30001519", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz", + "integrity": "sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg==", "dev": true, "funding": [ { @@ -3596,6 +3810,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -3764,6 +3982,12 @@ "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -3819,9 +4043,9 @@ ] }, "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "engines": { "node": ">= 0.6" } @@ -3849,9 +4073,9 @@ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, "node_modules/cookiejar": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", - "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", "dev": true }, "node_modules/core-js": { @@ -3863,12 +4087,12 @@ "hasInstallScript": true }, "node_modules/core-js-compat": { - "version": "3.25.5", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.5.tgz", - "integrity": "sha512-ovcyhs2DEBUIE0MGEKHP4olCUW/XYte3Vroyxuh38rD1wAO4dHohsovUC4eAOuzFxE6b+RXvBU3UZ9o0YhUTkA==", + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.0.tgz", + "integrity": "sha512-7a9a3D1k4UCVKnLhrgALyFcP7YCsLOQIxPd0dKjf/6GuPcgyiGP70ewWdCGrSK7evyhymi0qO4EqCmSJofDeYw==", "dev": true, "dependencies": { - "browserslist": "^4.21.4" + "browserslist": "^4.21.9" }, "funding": { "type": "opencollective", @@ -3979,9 +4203,9 @@ } }, "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", "dev": true, "dependencies": { "has-property-descriptors": "^1.0.0", @@ -4003,14 +4227,6 @@ "node": ">=0.4.0" } }, - "node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", - "engines": { - "node": ">=0.10" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -4041,9 +4257,9 @@ } }, "node_modules/dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha512-K7i4zNfT2kgQz3GylDw40ot9GAE47sFZ9EXHFSPP6zONLgH6kWXE0KWJchkbQJLBkRazq4APwZ4OwiFFlT95OQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", "dev": true, "dependencies": { "asap": "^2.0.0", @@ -4059,18 +4275,6 @@ "node": ">=0.3.1" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -4089,9 +4293,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.272", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.272.tgz", - "integrity": "sha512-KS6gPPGNrzpVv9HzFVq+Etd0AjZEPr5pvaTBn2yD6KV4+cKW4I0CJoJNgmTG6gUQPAMZ4wIPtcOuoou3qFAZCA==", + "version": "1.4.484", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.484.tgz", + "integrity": "sha512-nO3ZEomTK2PO/3TUXgEx0A97xZTpKVf4p427lABHuCpT1IQ2N+njVh29DkQkCk6Q4m2wjU+faK4xAcfFndwjvw==", "dev": true }, "node_modules/emoji-regex": { @@ -4124,35 +4328,50 @@ } }, "node_modules/es-abstract": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.3.tgz", - "integrity": "sha512-AyrnaKVpMzljIdwjzrj+LxGmj8ik2LckwXacHqrJJ/jxz6dDDBcZ7I7nlHM0FvEW8MfbWJwOd+yT2XzYW49Frw==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", "dev": true, "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", + "get-intrinsic": "^1.2.1", "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.6", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", + "object-inspect": "^1.12.3", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.10" }, "engines": { "node": ">= 0.4" @@ -4168,6 +4387,20 @@ "dev": true, "peer": true }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -4218,49 +4451,47 @@ } }, "node_modules/eslint": { - "version": "8.24.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.24.0.tgz", - "integrity": "sha512-dWFaPhGhTAiPcCgm3f6LI2MBWbogMnTJzFBbhXVRQDJPkr9pGZvVjlVfXd+vyDcWPA2Ic9L2AXPIQM0+vk/cSQ==", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz", + "integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.2", - "@humanwhocodes/config-array": "^0.10.5", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.1", + "@eslint/js": "^8.46.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", - "ajv": "^6.10.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.2", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-sdsl": "^4.1.4", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -4323,13 +4554,14 @@ } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, "dependencies": { "debug": "^3.2.7", - "resolve": "^1.20.0" + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { @@ -4342,9 +4574,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", "dev": true, "dependencies": { "debug": "^3.2.7" @@ -4383,24 +4615,29 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.0.tgz", + "integrity": "sha512-B8s/n+ZluN7sxj9eUf7/pRFERX0r5bnFA2dCaLHy2ZeaQEAz0k+ZZkFWRFHJAqxfxQDx6KLv9LeIki7cFdwW+Q==", "dev": true, "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.6", + "array.prototype.findlastindex": "^1.2.2", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.8.0", "has": "^1.0.3", - "is-core-module": "^2.8.1", + "is-core-module": "^2.12.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" + "object.fromentries": "^2.0.6", + "object.groupby": "^1.0.0", + "object.values": "^1.1.6", + "resolve": "^1.22.3", + "semver": "^6.3.1", + "tsconfig-paths": "^3.14.2" }, "engines": { "node": ">=4" @@ -4409,6 +4646,15 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/eslint-plugin-import/node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -4421,16 +4667,13 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "bin": { + "semver": "bin/semver.js" } }, "node_modules/eslint-plugin-jsx-a11y": { @@ -4461,19 +4704,6 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" } }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -4539,19 +4769,6 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/eslint-plugin-react/node_modules/resolve": { "version": "2.0.0-next.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", @@ -4590,9 +4807,9 @@ } }, "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -4600,42 +4817,21 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz", + "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/ansi-regex": { @@ -4760,9 +4956,9 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -4795,18 +4991,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/eslint/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4847,14 +5031,14 @@ } }, "node_modules/espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -4863,15 +5047,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/espree/node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -4886,9 +5061,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -4946,13 +5121,13 @@ } }, "node_modules/express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.0", + "body-parser": "1.20.1", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", @@ -4971,7 +5146,7 @@ "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.10.3", + "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.18.0", @@ -4986,6 +5161,43 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/express/node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/express/node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -5011,35 +5223,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/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", @@ -5059,9 +5242,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -5130,21 +5313,93 @@ "node": ">= 0.8" } }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dev": true, + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, "engines": { - "node": ">=8" + "node": ">=12.20" }, "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/flat": { @@ -5190,6 +5445,15 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -5205,32 +5469,20 @@ } }, "node_modules/formidable": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz", - "integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", + "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", "dev": true, "dependencies": { - "dezalgo": "1.0.3", - "hexoid": "1.0.0", - "once": "1.4.0", - "qs": "6.9.3" + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" }, "funding": { "url": "https://ko-fi.com/tunnckoCore/commissions" } }, - "node_modules/formidable/node_modules/qs": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz", - "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==", - "dev": true, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -5301,12 +5553,13 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3" }, "funding": { @@ -5377,33 +5630,31 @@ "node": ">=0.10.0" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", "dev": true, "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "define-properties": "^1.1.3" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globby/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/graceful-fs": { @@ -5413,10 +5664,10 @@ "dev": true, "peer": true }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "node_modules/handlebars": { @@ -5502,6 +5753,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -5577,29 +5839,10 @@ "node": ">=0.10.0" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, "engines": { "node": ">= 4" @@ -5647,12 +5890,12 @@ "dev": true }, "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.0", + "get-intrinsic": "^1.2.0", "has": "^1.0.3", "side-channel": "^1.0.4" }, @@ -5682,6 +5925,20 @@ "node": ">= 0.10" } }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", @@ -5723,9 +5980,9 @@ } }, "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -5818,6 +6075,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -5906,6 +6172,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -5936,6 +6217,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -6113,12 +6400,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/js-sdsl": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", - "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", - "dev": true - }, "node_modules/js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -6166,6 +6447,18 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", @@ -6187,9 +6480,12 @@ "dev": true }, "node_modules/kareem": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.4.1.tgz", - "integrity": "sha512-aJ9opVoXroQUPfovYP5kaj2lM7Jn02Gw13bL0lg9v0V7SaUc0qavPs0Eue7d2DcC3NjqI6QAUElXNsuZSeM+EA==" + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", + "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==", + "engines": { + "node": ">=12.0.0" + } }, "node_modules/language-subtag-registry": { "version": "0.3.22", @@ -6369,39 +6665,12 @@ } }, "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "yallist": "^3.0.2" } }, "node_modules/media-typer": { @@ -6430,15 +6699,6 @@ "dev": true, "peer": true }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/method-override": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/method-override/-/method-override-3.0.0.tgz", @@ -6505,9 +6765,9 @@ } }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -6535,12 +6795,11 @@ } }, "node_modules/mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", "dev": true, "dependencies": { - "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", "chokidar": "3.5.3", @@ -6855,46 +7114,69 @@ } }, "node_modules/mongodb": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.9.1.tgz", - "integrity": "sha512-ZhgI/qBf84fD7sI4waZBoLBNJYPQN5IOC++SBCiPiyhzpNKOxN/fi0tBHvH2dEC42HXtNEbFB0zmNz4+oVtorQ==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.7.0.tgz", + "integrity": "sha512-zm82Bq33QbqtxDf58fLWBwTjARK3NSvKYjyz997KSy6hpat0prjeX/kxjbPVyZY60XYPDNETaHkHJI2UCzSLuw==", "dependencies": { - "bson": "^4.7.0", - "denque": "^2.1.0", - "mongodb-connection-string-url": "^2.5.3", - "socks": "^2.7.0" + "bson": "^5.4.0", + "mongodb-connection-string-url": "^2.6.0", + "socks": "^2.7.1" }, "engines": { - "node": ">=12.9.0" + "node": ">=14.20.1" }, "optionalDependencies": { "saslprep": "^1.0.3" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.201.0", + "@mongodb-js/zstd": "^1.1.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=2.3.0 <3", + "snappy": "^7.2.2" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + } } }, "node_modules/mongodb-connection-string-url": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.4.tgz", - "integrity": "sha512-SeAxuWs0ez3iI3vvmLk/j2y+zHwigTDKQhtdxTgt5ZCOQQS5+HW4g45/Xw5vzzbn7oQXCNQ24Z40AkJsizEy7w==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", "dependencies": { "@types/whatwg-url": "^8.2.1", "whatwg-url": "^11.0.0" } }, "node_modules/mongoose": { - "version": "6.6.5", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.6.5.tgz", - "integrity": "sha512-iA/oDpWOc+K2QYzA4Eq7Z1oUBQOz9FGDmUwPLgw872Bfs/qizA5Db+gJorAn+TnnGu3VoCK8iP4Y+TECUelwjA==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.4.2.tgz", + "integrity": "sha512-sNolW2hyncwvWmZjIEIwAckjaSKtC1SE86zE1v2TKm3vPTRogZfBQf+3zLYYdrgrVTzoaoICieVpct9hjcn3EQ==", "dependencies": { - "bson": "^4.6.5", - "kareem": "2.4.1", - "mongodb": "4.9.1", + "bson": "^5.4.0", + "kareem": "2.5.1", + "mongodb": "5.7.0", "mpath": "0.9.0", - "mquery": "4.0.3", + "mquery": "5.0.0", "ms": "2.1.3", - "sift": "16.0.0" + "sift": "16.0.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.20.1" }, "funding": { "type": "opencollective", @@ -6910,14 +7192,14 @@ } }, "node_modules/mquery": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz", - "integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", "dependencies": { "debug": "4.x" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/mquery/node_modules/debug": { @@ -6979,18 +7261,27 @@ "dev": true }, "node_modules/nise": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.1.tgz", - "integrity": "sha512-yr5kW2THW1AkxVmCnKEh4nbYkJdB3I7LUkiUgOvEkOp414mc2UMaHMA7pjq1nYowhdoJZGwEKGaQVbxfpWj10A==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz", + "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.8.3", - "@sinonjs/fake-timers": ">=5", + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^10.0.2", "@sinonjs/text-encoding": "^0.7.1", "just-extend": "^4.0.2", "path-to-regexp": "^1.7.0" } }, + "node_modules/nise/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, "node_modules/nise/node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -7007,9 +7298,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, "node_modules/nopt": { @@ -7042,9 +7333,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -7091,15 +7382,14 @@ } }, "node_modules/object.fromentries": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", - "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "engines": { "node": ">= 0.4" @@ -7108,6 +7398,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object.groupby": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.0.tgz", + "integrity": "sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.21.2", + "get-intrinsic": "^1.2.1" + } + }, "node_modules/object.hasown": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz", @@ -7123,14 +7425,14 @@ } }, "node_modules/object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, "engines": { "node": ">= 0.4" @@ -7160,17 +7462,17 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "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" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -7235,6 +7537,15 @@ "node": ">= 0.8" } }, + "node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -7264,15 +7575,6 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -7301,76 +7603,18 @@ } }, "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "dev": true, + "dependencies": { + "find-up": "^6.3.0" + }, "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/prelude-ls": { @@ -7406,10 +7650,18 @@ "node": ">= 0.10" } }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dependencies": { "side-channel": "^1.0.4" }, @@ -7458,9 +7710,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -7497,29 +7749,29 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", "dev": true }, "node_modules/regenerator-transform": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", - "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", + "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", "dev": true, "dependencies": { "@babel/runtime": "^7.8.4" } }, "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" }, "engines": { "node": ">= 0.4" @@ -7528,41 +7780,23 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/regexpu-core": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", - "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", "dev": true, "dependencies": { + "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.1.0", - "regjsgen": "^0.7.1", "regjsparser": "^0.9.1", "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" + "unicode-match-property-value-ecmascript": "^2.1.0" }, "engines": { "node": ">=4" } }, - "node_modules/regjsgen": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", - "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", - "dev": true - }, "node_modules/regjsparser": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", @@ -7605,13 +7839,22 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz", + "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==", "dev": true, "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.12.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -7676,6 +7919,24 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -7714,23 +7975,58 @@ } }, "node_modules/schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { - "node": ">= 8.9.0" + "node": ">= 12.13.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" } }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, "node_modules/semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", @@ -7910,21 +8206,21 @@ } }, "node_modules/sift": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.0.tgz", - "integrity": "sha512-ILTjdP2Mv9V1kIxWMXeMTIRbOBrqKc4JAXmFMnFq3fKeyQ2Qwa3Dw1ubcye3vR+Y6ofA0b9gNDr/y2t6eUeIzQ==" + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", + "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" }, "node_modules/sinon": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-14.0.1.tgz", - "integrity": "sha512-JhJ0jCiyBWVAHDS+YSjgEbDn7Wgz9iIjA1/RK+eseJN0vAAWIWiXBdrnb92ELPyjsfreCYntD1ORtLSfIrlvSQ==", + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.2.0.tgz", + "integrity": "sha512-nPS85arNqwBXaIsFCkolHjGIkFo+Oxu9vbgmBJizLAhqe6P2o3Qmj3KCUoRkfhHtvgDhZdWD3risLHAUJ8npjw==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.8.3", - "@sinonjs/fake-timers": "^9.1.2", - "@sinonjs/samsam": "^6.1.1", - "diff": "^5.0.0", - "nise": "^5.1.1", + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^10.3.0", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.4", "supports-color": "^7.2.0" }, "funding": { @@ -7932,6 +8228,15 @@ "url": "https://opencollective.com/sinon" } }, + "node_modules/sinon/node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/sinon/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -8046,29 +8351,46 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8108,22 +8430,21 @@ } }, "node_modules/superagent": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.2.tgz", - "integrity": "sha512-QtYZ9uaNAMexI7XWl2vAXAh0j4q9H7T0WVEI/y5qaUB3QLwxo+voUgCQ217AokJzUTIVOp0RTo7fhZrwhD7A2Q==", - "deprecated": "Please use v8.0.0 until https://github.com/visionmedia/superagent/issues/1743 is resolved", + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.9.tgz", + "integrity": "sha512-4C7Bh5pyHTvU33KpZgwrNKh/VQnvgtCSqPRfJAUdmrtSYePVzVg4E4OzsrbkhJj9O7SO6Bnv75K/F8XVZT8YHA==", "dev": true, "dependencies": { "component-emitter": "^1.3.0", - "cookiejar": "^2.1.3", + "cookiejar": "^2.1.4", "debug": "^4.3.4", "fast-safe-stringify": "^2.1.1", "form-data": "^4.0.0", - "formidable": "^2.0.1", + "formidable": "^2.1.2", "methods": "^1.1.2", "mime": "2.6.0", "qs": "^6.11.0", - "semver": "^7.3.7" + "semver": "^7.3.8" }, "engines": { "node": ">=6.4.0 <13 || >=14" @@ -8146,6 +8467,18 @@ } } }, + "node_modules/superagent/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/superagent/node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -8164,25 +8497,10 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/superagent/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/superagent/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -8194,14 +8512,20 @@ "node": ">=10" } }, + "node_modules/superagent/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/supertest": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.0.tgz", - "integrity": "sha512-QgWju1cNoacP81Rv88NKkQ4oXTzGg0eNZtOoxp1ROpbS4OHY/eK5b8meShuFtdni161o5X0VQvgo7ErVyKK+Ow==", + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.3.tgz", + "integrity": "sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==", "dev": true, "dependencies": { "methods": "^1.1.2", - "superagent": "^8.0.0" + "superagent": "^8.0.5" }, "engines": { "node": ">=6.4.0" @@ -8345,14 +8669,6 @@ "node": ">=12" } }, - "node_modules/tr46/node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "engines": { - "node": ">=6" - } - }, "node_modules/trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", @@ -8363,21 +8679,21 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", "dev": true, "dependencies": { "@types/json5": "^0.0.29", - "json5": "^1.0.1", + "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { "minimist": "^1.2.0" @@ -8431,6 +8747,71 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/uglify-js": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", @@ -8496,9 +8877,9 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", "dev": true, "engines": { "node": ">=4" @@ -8522,9 +8903,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", "dev": true, "funding": [ { @@ -8534,6 +8915,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { @@ -8541,7 +8926,7 @@ "picocolors": "^1.0.0" }, "bin": { - "browserslist-lint": "cli.js" + "update-browserslist-db": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" @@ -8556,15 +8941,6 @@ "punycode": "^2.1.0" } }, - "node_modules/uri-js/node_modules/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, - "engines": { - "node": ">=6" - } - }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -8752,13 +9128,23 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/wordwrap": { @@ -8780,9 +9166,9 @@ "dev": true }, "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, "node_modules/yargs-unparser": { @@ -8838,6 +9224,12 @@ } }, "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, "@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", @@ -8849,12 +9241,12 @@ } }, "@babel/cli": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.19.3.tgz", - "integrity": "sha512-643/TybmaCAe101m2tSVHi9UKpETXP9c/Ff4mD2tAwkdP6esKIfaauZFc67vGEM6r9fekbEGid+sZhbEnSe3dg==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.22.9.tgz", + "integrity": "sha512-nb2O7AThqRo7/E53EGiuAkMaRbb7J5Qp3RvN+dmua1U+kydm0oznkhqbTEG15yk26G/C3yL6OdZjzgl+DMXVVA==", "dev": true, "requires": { - "@jridgewell/trace-mapping": "^0.3.8", + "@jridgewell/trace-mapping": "^0.3.17", "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3", "chokidar": "^3.4.0", "commander": "^4.0.1", @@ -8896,41 +9288,41 @@ } }, "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dev": true, "requires": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.5" } }, "@babel/compat-data": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.3.tgz", - "integrity": "sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", "dev": true }, "@babel/core": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz", - "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", - "@babel/helper-compilation-targets": "^7.19.3", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helpers": "^7.19.0", - "@babel/parser": "^7.19.3", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.3", - "@babel/types": "^7.19.3", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz", + "integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.8", + "@babel/types": "^7.22.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" + "json5": "^2.2.2", + "semver": "^6.3.1" }, "dependencies": { "debug": { @@ -8942,12 +9334,6 @@ "ms": "2.1.2" } }, - "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -8955,22 +9341,22 @@ "dev": true }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } }, "@babel/eslint-parser": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", - "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.22.9.tgz", + "integrity": "sha512-xdMkt39/nviO/4vpVdrEYPwXCsYIXSSAr6mC7WQsNIlGnuxKyKE7GZjalcnbSWiC4OXGNNN3UQPeHfjSC6sTDA==", "dev": true, "requires": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "dependencies": { "eslint-visitor-keys": { @@ -8980,21 +9366,22 @@ "dev": true }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } }, "@babel/generator": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.3.tgz", - "integrity": "sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", + "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", "dev": true, "requires": { - "@babel/types": "^7.19.3", + "@babel/types": "^7.22.5", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "dependencies": { @@ -9018,81 +9405,99 @@ } }, "@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", - "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.5.tgz", + "integrity": "sha512-m1EP3lVOPptR+2DwD125gziZNcmoNSHGmJROKoy87loWUQyJaVXDgpmruWqDARZSmtYQ+Dl25okU8+qhVzuykw==", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "^7.18.6", - "@babel/types": "^7.18.9" + "@babel/types": "^7.22.5" } }, "@babel/helper-compilation-targets": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", - "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz", + "integrity": "sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw==", "dev": true, "requires": { - "@babel/compat-data": "^7.19.3", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.5", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } }, "@babel/helper-create-class-features-plugin": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", - "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.9.tgz", + "integrity": "sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.9", - "@babel/helper-split-export-declaration": "^7.18.6" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", - "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.9.tgz", + "integrity": "sha512-+svjVa/tFwsNSG4NEy1h85+HQ5imbT92Q5/bgtS7P0GTQlP8WuFdqsiABmQouhiFGyV66oGxZFpeYHza1rNsKw==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "regexpu-core": "^5.1.0" + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } } }, "@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz", + "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==", "dev": true, "requires": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" + "resolve": "^1.14.2" }, "dependencies": { "debug": { @@ -9109,198 +9514,176 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", - "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" + } } }, + "@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "dev": true + }, "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", "dev": true, "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" } }, "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", - "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz", + "integrity": "sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ==", "dev": true, "requires": { - "@babel/types": "^7.18.9" + "@babel/types": "^7.22.5" } }, "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", + "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", "dev": true, "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.5" } }, "@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", "dev": true }, "@babel/helper-remap-async-to-generator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", - "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz", + "integrity": "sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-wrap-function": "^7.18.9", - "@babel/types": "^7.18.9" + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-wrap-function": "^7.22.9" } }, "@babel/helper-replace-supers": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", - "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz", + "integrity": "sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==", "dev": true, "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5" } }, "@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", - "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", "dev": true, "requires": { - "@babel/types": "^7.18.9" + "@babel/types": "^7.22.5" } }, "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "dev": true }, "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", "dev": true }, "@babel/helper-wrap-function": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", - "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.9.tgz", + "integrity": "sha512-sZ+QzfauuUEfxSEjKFmi3qDSHgLsTPK/pEpoD/qonZKOtTPTLbf59oabPQ4rKekt9lFcj/hTZaOhWwFYrgjk+Q==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.19.0", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" } }, "@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz", + "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==", "dev": true, "requires": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.6", + "@babel/types": "^7.22.5" } }, "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.22.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -9349,41 +9732,29 @@ } }, "@babel/parser": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.3.tgz", - "integrity": "sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==", + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", + "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", "dev": true }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", - "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz", + "integrity": "sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", - "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", - "@babel/plugin-proposal-optional-chaining": "^7.18.9" - } - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz", - "integrity": "sha512-0yu8vNATgLy4ivqMNBIwb1HebCelqN7YX8SL3FDXORv/RqT0zEEWUCH4GH44JsSrvCu6GqnAdR5EBFAPeNBB4Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz", + "integrity": "sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g==", "dev": true, "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-remap-async-to-generator": "^7.18.9", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.5" } }, "@babel/plugin-proposal-class-properties": { @@ -9396,58 +9767,37 @@ "@babel/helper-plugin-utils": "^7.18.6" } }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", - "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - } - }, "@babel/plugin-proposal-decorators": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.19.3.tgz", - "integrity": "sha512-MbgXtNXqo7RTKYIXVchVJGPvaVufQH3pxvQyfbGvNw1DObIhph+PesYXJTcd8J4DdWibvf6Z2eanOyItX8WnJg==", + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.22.7.tgz", + "integrity": "sha512-omXqPF7Onq4Bb7wHxXjM3jSMSJvUUbvDvmmds7KI5n9Cq6Ln5I05I1W2nRlRof1rGdiUxJrxwe285WF96XlBXQ==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-replace-supers": "^7.19.1", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/plugin-syntax-decorators": "^7.19.0" + "@babel/helper-create-class-features-plugin": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/plugin-syntax-decorators": "^7.22.5" } }, "@babel/plugin-proposal-do-expressions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-do-expressions/-/plugin-proposal-do-expressions-7.18.6.tgz", - "integrity": "sha512-ddToGCONJhCuL+l4FhtGnKl5ZYCj9fDVFiqiCdQDpeIbVn/NvMeSib+7T1/rk08jRafae4qNiP8OnJyuqlsuYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-do-expressions": "^7.18.6" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-do-expressions/-/plugin-proposal-do-expressions-7.22.5.tgz", + "integrity": "sha512-Qh6Sbkt6xCRbHykDc709db/EQB4RJlmaW3ENuvzzi7G6GKeDNQHx81P0OdI9oEXhhHEJvLRzIr08m8HNCJWS8g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-do-expressions": "^7.22.5" } }, "@babel/plugin-proposal-export-default-from": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.18.10.tgz", - "integrity": "sha512-5H2N3R2aQFxkV4PIBUR/i7PUSwgTZjouJKzI8eKswfIjT0PhvzkPn0t0wIS5zn6maQuvtT0t1oHtMUz61LOuow==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.22.5.tgz", + "integrity": "sha512-UCe1X/hplyv6A5g2WnQ90tnHRvYL29dabCWww92lO7VdfMVTVReBTRrhiMrKQejHD9oVkdnRdwYuzUZkBVQisg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-default-from": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-default-from": "^7.22.5" } }, "@babel/plugin-proposal-export-namespace-from": { @@ -9461,24 +9811,24 @@ } }, "@babel/plugin-proposal-function-bind": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-function-bind/-/plugin-proposal-function-bind-7.18.9.tgz", - "integrity": "sha512-9RfxqKkRBCCT0xoBl9AqieCMscJmSAL9HYixGMWH549jUpT9csWWK/HEYZEx9t9iW/PRSXgX95x9bDlgtAJGFA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-function-bind/-/plugin-proposal-function-bind-7.22.5.tgz", + "integrity": "sha512-ckAugfDtdcrXKP49z7K7JI7QkA8SRidmsKxLizH8mg0UWOvcmvEd9/VDLzFcWlZqchvLDPUYpwuXNGAYjsscrw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-function-bind": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-function-bind": "^7.22.5" } }, "@babel/plugin-proposal-function-sent": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-function-sent/-/plugin-proposal-function-sent-7.18.6.tgz", - "integrity": "sha512-UdaOKPOLPt0O+Xu26tnw6oAZMLXhk+yMrXOzn6kAzTHBnWHJsoN1hlrgxFAQ+FRLS0ql1oYIQ2phvoFzmN3GMw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-function-sent/-/plugin-proposal-function-sent-7.22.5.tgz", + "integrity": "sha512-YFEE5KDhaNCCD0I1j9vqPp5bpPuoDAPD+4Adk0QXdrL9TbmZluCuznuYvmlYqr14zfXCBGAZivfiLb6WI4GhSw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-wrap-function": "^7.18.6", - "@babel/plugin-syntax-function-sent": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-wrap-function": "^7.22.5", + "@babel/plugin-syntax-function-sent": "^7.22.5" } }, "@babel/plugin-proposal-json-strings": { @@ -9492,12 +9842,12 @@ } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", - "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", + "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, @@ -9521,80 +9871,42 @@ "@babel/plugin-syntax-numeric-separator": "^7.10.4" } }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz", - "integrity": "sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.18.8", - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.18.8" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - } - }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", - "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, "@babel/plugin-proposal-pipeline-operator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-pipeline-operator/-/plugin-proposal-pipeline-operator-7.18.9.tgz", - "integrity": "sha512-Pc33e6m8f4MJhRXVCUwiKZNtEm+W2CUPHIL0lyJNtkp+w6d75CLw3gsBKQ81VAMUgT9jVPIEU8gwJ5nJgmJ1Ag==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-pipeline-operator": "^7.18.6" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-pipeline-operator/-/plugin-proposal-pipeline-operator-7.22.5.tgz", + "integrity": "sha512-nSgHJB3uP+DORxBVhQgjub0qtU/LGj/mBDz2kQEGy1EUDy3f92VWDeB3J3/41ZjVLWmkNWOd6yjdNb4a5wDfZQ==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-pipeline-operator": "^7.22.5" } }, "@babel/plugin-proposal-private-property-in-object": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", - "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - } + "requires": {} }, "@babel/plugin-proposal-throw-expressions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-throw-expressions/-/plugin-proposal-throw-expressions-7.18.6.tgz", - "integrity": "sha512-WHOrJyhGoGrdtW480L79cF7Iq/gZDZ/z6OqK7mVyFR5I37dTpog/wNgb6hmaM3HYZtULEJl++7VaMWkNZsOcHg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-throw-expressions/-/plugin-proposal-throw-expressions-7.22.5.tgz", + "integrity": "sha512-34kY5YjNKDhjXbj2oNDkxl0xNl2+yQTEsWu8Ia6kCTb6wz76bBCd4DzmeZokfr6g68yneu3eg8qAyYgKbyesFg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-throw-expressions": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-throw-expressions": "^7.22.5" } }, "@babel/plugin-proposal-unicode-property-regex": { @@ -9635,21 +9947,21 @@ } }, "@babel/plugin-syntax-decorators": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz", - "integrity": "sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.22.5.tgz", + "integrity": "sha512-avpUOBS7IU6al8MmF1XpAyj9QYeLPuSDJI5D4pVMSMdL7xQokKqJPYQC67RCT0aCTashUXPiGwMJ0DEXXCEmMA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.19.0" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-syntax-do-expressions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-do-expressions/-/plugin-syntax-do-expressions-7.18.6.tgz", - "integrity": "sha512-kTogvOsjBTVOSZtkkziiXB5hwGXqwhq2gBXDaiWVruRLDT7C2GqfbsMnicHJ7ePq2GE8UJeWS34YbNP6yDhwUA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-do-expressions/-/plugin-syntax-do-expressions-7.22.5.tgz", + "integrity": "sha512-60pOTgQGY00/Kiozrtu286Aqg50IxDy/jIHhlMzXjYTs1Q8lbeOgqC9NLidtqfBNwdX6bZCT6FJ2i5xzt+JKzw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-syntax-dynamic-import": { @@ -9662,12 +9974,12 @@ } }, "@babel/plugin-syntax-export-default-from": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.18.6.tgz", - "integrity": "sha512-Kr//z3ujSVNx6E9z9ih5xXXMqK07VVTuqPmqGe6Mss/zW5XPeLZeSDZoP9ab/hT4wPKqAgjl2PnhPrcpk8Seew==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.22.5.tgz", + "integrity": "sha512-ODAqWWXB/yReh/jVQDag/3/tl6lgBueQkk/TcfW/59Oykm4c8a55XloX0CTk2k2VJiFWMgHby9xNX29IbCv9dQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-syntax-export-namespace-from": { @@ -9680,30 +9992,39 @@ } }, "@babel/plugin-syntax-function-bind": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-function-bind/-/plugin-syntax-function-bind-7.18.6.tgz", - "integrity": "sha512-wZN0Aq/AScknI9mKGcR3TpHdASMufFGaeJgc1rhPmLtZ/PniwjePSh8cfh8tXMB3U4kh/3cRKrLjDtedejg8jQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-function-bind/-/plugin-syntax-function-bind-7.22.5.tgz", + "integrity": "sha512-Sjy7XIhHF9L++0Mk/3Y4H4439cjI//wc/jE8Ly3+qGPkTUYYEhe4rzMv/JnyZpekfOBL22X6DAq42I7GM/3KzA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-syntax-function-sent": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-function-sent/-/plugin-syntax-function-sent-7.18.6.tgz", - "integrity": "sha512-f3OJHIlFIkg+cP1Hfo2SInLhsg0pz2Ikmgo7jMdIIKC+3jVXQlHB0bgSapOWxeWI0SU28qIWmfn5ZKu1yPJHkg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-function-sent/-/plugin-syntax-function-sent-7.22.5.tgz", + "integrity": "sha512-tKOWGUAVv+JGJ1tcOIFdCqxUX97lgAUnmLpWt/9JtEkgk9WQ5OolN+y9rWj6mtLM+d0kAzTGLu/kRQqr5/PEsA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-syntax-import-assertions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", - "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz", + "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-syntax-import-attributes": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz", + "integrity": "sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-syntax-import-meta": { @@ -9779,12 +10100,12 @@ } }, "@babel/plugin-syntax-pipeline-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-pipeline-operator/-/plugin-syntax-pipeline-operator-7.18.6.tgz", - "integrity": "sha512-pFtIdQomJtkTHWcNsGXhjJ5YUkL+AxJnP4G+Ol85UO6uT2fpHTPYLLE5bBeRA9cxf25qa/VKsJ3Fi67Gyqe3rA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-pipeline-operator/-/plugin-syntax-pipeline-operator-7.22.5.tgz", + "integrity": "sha512-7yuGXd+h8gpR14FnPDTTCd5TfC/1B9njNZJT29GJ7UFF/WVbzkZy7728DynrENqgImqj5xyPTQAo8si9n3QVJQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-syntax-private-property-in-object": { @@ -9797,12 +10118,12 @@ } }, "@babel/plugin-syntax-throw-expressions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-throw-expressions/-/plugin-syntax-throw-expressions-7.18.6.tgz", - "integrity": "sha512-rp1CqEZXGv1z1YZ3qYffBH3rhnOxrTwQG8fh2yqulTurwv9zu3Gthfd+niZBLSOi1rY6146TgF+JmVeDXaX4TQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-throw-expressions/-/plugin-syntax-throw-expressions-7.22.5.tgz", + "integrity": "sha512-oCyfA7rDVcQIydA7ZOmnHCQTzz5JvG9arY++Z+ASL/q5q+mJLblaRNHoK6ggV54X2c14wCK/lQi7z1DujmEmZA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-syntax-top-level-await": { @@ -9814,58 +10135,101 @@ "@babel/helper-plugin-utils": "^7.14.5" } }, - "@babel/plugin-transform-arrow-functions": { + "@babel/plugin-syntax-unicode-sets-regex": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", - "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" } }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz", + "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-async-generator-functions": { + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.7.tgz", + "integrity": "sha512-7HmE7pk/Fmke45TODvxvkxRMV9RazV+ZZzhOL9AG8G29TLrr3jkjwF7uJfxZ30EoXpO+LJkq4oA8NjO2DTnEDg==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, "@babel/plugin-transform-async-to-generator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", - "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz", + "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-remap-async-to-generator": "^7.18.6" + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", - "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz", + "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz", - "integrity": "sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz", + "integrity": "sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-class-properties": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz", + "integrity": "sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-class-static-block": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz", + "integrity": "sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" } }, "@babel/plugin-transform-classes": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", - "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-compilation-targets": "^7.19.0", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-replace-supers": "^7.18.9", - "@babel/helper-split-export-declaration": "^7.18.6", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz", + "integrity": "sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", "globals": "^11.1.0" }, "dependencies": { @@ -9878,300 +10242,422 @@ } }, "@babel/plugin-transform-computed-properties": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", - "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", + "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.5" } }, "@babel/plugin-transform-destructuring": { - "version": "7.18.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.13.tgz", - "integrity": "sha512-TodpQ29XekIsex2A+YJPj5ax2plkGa8YYY6mFjCohk/IG9IY42Rtuj1FuDeemfg2ipxIFLzPeA83SIBnlhSIow==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz", + "integrity": "sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", - "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz", + "integrity": "sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", - "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz", + "integrity": "sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-dynamic-import": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz", + "integrity": "sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", - "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz", + "integrity": "sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-export-namespace-from": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz", + "integrity": "sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, "@babel/plugin-transform-for-of": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", - "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz", + "integrity": "sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-function-name": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", - "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz", + "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-json-strings": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz", + "integrity": "sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A==", "dev": true, "requires": { - "@babel/helper-compilation-targets": "^7.18.9", - "@babel/helper-function-name": "^7.18.9", - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" } }, "@babel/plugin-transform-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", - "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz", + "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-logical-assignment-operators": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz", + "integrity": "sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", - "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz", + "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz", - "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz", + "integrity": "sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz", - "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz", + "integrity": "sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.0.tgz", - "integrity": "sha512-x9aiR0WXAWmOWsqcsnrzGR+ieaTMVyGyffPVA7F8cXAGt/UxefYv6uSHZLkAFChN5M5Iy1+wjE+xJuPt22H39A==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz", + "integrity": "sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-validator-identifier": "^7.18.6", - "babel-plugin-dynamic-import-node": "^2.3.3" + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", - "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz", + "integrity": "sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", - "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-new-target": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", - "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz", + "integrity": "sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz", + "integrity": "sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-transform-numeric-separator": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz", + "integrity": "sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-transform-object-rest-spread": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz", + "integrity": "sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.22.5" } }, "@babel/plugin-transform-object-super": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", - "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz", + "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5" + } + }, + "@babel/plugin-transform-optional-catch-binding": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz", + "integrity": "sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-transform-optional-chaining": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.6.tgz", + "integrity": "sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, "@babel/plugin-transform-parameters": { - "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", - "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz", + "integrity": "sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-private-methods": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz", + "integrity": "sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-private-property-in-object": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz", + "integrity": "sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } }, "@babel/plugin-transform-property-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", - "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz", + "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-regenerator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", - "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz", + "integrity": "sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "regenerator-transform": "^0.15.0" + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.1" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", - "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz", + "integrity": "sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", - "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz", + "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-spread": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", - "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz", + "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", - "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz", + "integrity": "sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-template-literals": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", - "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz", + "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", - "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz", + "integrity": "sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", - "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz", + "integrity": "sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-property-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz", + "integrity": "sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.9" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", - "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz", + "integrity": "sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-unicode-sets-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz", + "integrity": "sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/preset-env": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.3.tgz", - "integrity": "sha512-ziye1OTc9dGFOAXSWKUqQblYHNlBOaDl8wzqf2iKXJAltYiR3hKHUKmkt+S9PppW7RQpq4fFCrwwpIDj/f5P4w==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.19.3", - "@babel/helper-compilation-targets": "^7.19.3", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-async-generator-functions": "^7.19.1", - "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-class-static-block": "^7.18.6", - "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", - "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.18.9", - "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.9", - "@babel/plugin-proposal-private-methods": "^7.18.6", - "@babel/plugin-proposal-private-property-in-object": "^7.18.6", - "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.9.tgz", + "integrity": "sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.9", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.5", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.5", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.18.6", + "@babel/plugin-syntax-import-assertions": "^7.22.5", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", @@ -10181,51 +10667,68 @@ "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.18.6", - "@babel/plugin-transform-async-to-generator": "^7.18.6", - "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.18.9", - "@babel/plugin-transform-classes": "^7.19.0", - "@babel/plugin-transform-computed-properties": "^7.18.9", - "@babel/plugin-transform-destructuring": "^7.18.13", - "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.9", - "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.8", - "@babel/plugin-transform-function-name": "^7.18.9", - "@babel/plugin-transform-literals": "^7.18.9", - "@babel/plugin-transform-member-expression-literals": "^7.18.6", - "@babel/plugin-transform-modules-amd": "^7.18.6", - "@babel/plugin-transform-modules-commonjs": "^7.18.6", - "@babel/plugin-transform-modules-systemjs": "^7.19.0", - "@babel/plugin-transform-modules-umd": "^7.18.6", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", - "@babel/plugin-transform-new-target": "^7.18.6", - "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.18.8", - "@babel/plugin-transform-property-literals": "^7.18.6", - "@babel/plugin-transform-regenerator": "^7.18.6", - "@babel/plugin-transform-reserved-words": "^7.18.6", - "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.19.0", - "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.9", - "@babel/plugin-transform-typeof-symbol": "^7.18.9", - "@babel/plugin-transform-unicode-escapes": "^7.18.10", - "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.22.5", + "@babel/plugin-transform-async-generator-functions": "^7.22.7", + "@babel/plugin-transform-async-to-generator": "^7.22.5", + "@babel/plugin-transform-block-scoped-functions": "^7.22.5", + "@babel/plugin-transform-block-scoping": "^7.22.5", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-class-static-block": "^7.22.5", + "@babel/plugin-transform-classes": "^7.22.6", + "@babel/plugin-transform-computed-properties": "^7.22.5", + "@babel/plugin-transform-destructuring": "^7.22.5", + "@babel/plugin-transform-dotall-regex": "^7.22.5", + "@babel/plugin-transform-duplicate-keys": "^7.22.5", + "@babel/plugin-transform-dynamic-import": "^7.22.5", + "@babel/plugin-transform-exponentiation-operator": "^7.22.5", + "@babel/plugin-transform-export-namespace-from": "^7.22.5", + "@babel/plugin-transform-for-of": "^7.22.5", + "@babel/plugin-transform-function-name": "^7.22.5", + "@babel/plugin-transform-json-strings": "^7.22.5", + "@babel/plugin-transform-literals": "^7.22.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.22.5", + "@babel/plugin-transform-member-expression-literals": "^7.22.5", + "@babel/plugin-transform-modules-amd": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.22.5", + "@babel/plugin-transform-modules-systemjs": "^7.22.5", + "@babel/plugin-transform-modules-umd": "^7.22.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.22.5", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.5", + "@babel/plugin-transform-numeric-separator": "^7.22.5", + "@babel/plugin-transform-object-rest-spread": "^7.22.5", + "@babel/plugin-transform-object-super": "^7.22.5", + "@babel/plugin-transform-optional-catch-binding": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.6", + "@babel/plugin-transform-parameters": "^7.22.5", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.5", + "@babel/plugin-transform-property-literals": "^7.22.5", + "@babel/plugin-transform-regenerator": "^7.22.5", + "@babel/plugin-transform-reserved-words": "^7.22.5", + "@babel/plugin-transform-shorthand-properties": "^7.22.5", + "@babel/plugin-transform-spread": "^7.22.5", + "@babel/plugin-transform-sticky-regex": "^7.22.5", + "@babel/plugin-transform-template-literals": "^7.22.5", + "@babel/plugin-transform-typeof-symbol": "^7.22.5", + "@babel/plugin-transform-unicode-escapes": "^7.22.5", + "@babel/plugin-transform-unicode-property-regex": "^7.22.5", + "@babel/plugin-transform-unicode-regex": "^7.22.5", + "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.19.3", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "core-js-compat": "^3.25.1", - "semver": "^6.3.0" + "@babel/types": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.4", + "babel-plugin-polyfill-corejs3": "^0.8.2", + "babel-plugin-polyfill-regenerator": "^0.5.1", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -10244,9 +10747,9 @@ } }, "@babel/register": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.18.9.tgz", - "integrity": "sha512-ZlbnXDcNYHMR25ITwwNKT88JiaukkdVj/nG7r3wnuXkOTHc60Uy05PwMCPre0hSkY68E6zK3xz+vUJSP2jWmcw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.22.5.tgz", + "integrity": "sha512-vV6pm/4CijSQ8Y47RH5SopXzursN35RQINfGJkmOlcpAtGuf94miFvIPhCKGQN7WGIcsgG1BHEX2KVdTYwTwUQ==", "dev": true, "requires": { "clone-deep": "^4.0.1", @@ -10337,13 +10840,19 @@ } } }, + "@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, "@babel/runtime": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz", - "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", + "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", "dev": true, "requires": { - "regenerator-runtime": "^0.13.4" + "regenerator-runtime": "^0.13.11" } }, "@babel/runtime-corejs3": { @@ -10358,30 +10867,30 @@ } }, "@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", "dev": true, "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" } }, "@babel/traverse": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.3.tgz", - "integrity": "sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.3", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.3", - "@babel/types": "^7.19.3", + "version": "7.22.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", + "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.7", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.7", + "@babel/types": "^7.22.5", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -10410,13 +10919,13 @@ } }, "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", + "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", "to-fast-properties": "^2.0.0" }, "dependencies": { @@ -10428,16 +10937,31 @@ } } }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", + "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "dev": true + }, "@eslint/eslintrc": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", - "integrity": "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", + "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", + "espree": "^9.6.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -10461,9 +10985,9 @@ } }, "globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -10478,15 +11002,6 @@ "argparse": "^2.0.1" } }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -10495,15 +11010,21 @@ } } }, + "@eslint/js": { + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz", + "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==", + "dev": true + }, "@humanwhocodes/config-array": { - "version": "0.10.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", - "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" }, "dependencies": { "debug": { @@ -10523,12 +11044,6 @@ } } }, - "@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true - }, "@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -10595,13 +11110,13 @@ "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "@nicolo-ribaudo/chokidar-2": { @@ -10665,32 +11180,43 @@ } }, "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", "dev": true, "requires": { "type-detect": "4.0.8" } }, "@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, "requires": { - "@sinonjs/commons": "^1.7.0" + "@sinonjs/commons": "^3.0.0" } }, "@sinonjs/samsam": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.1.1.tgz", - "integrity": "sha512-cZ7rKJTLiE7u7Wi/v9Hc2fs3Ucc3jrWeMgPHbbTCeVAB2S0wOBbYlkJVeNSL04i7fdhT8wIbDq1zhC/PXTD2SA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", "dev": true, "requires": { - "@sinonjs/commons": "^1.6.0", + "@sinonjs/commons": "^2.0.0", "lodash.get": "^4.4.2", "type-detect": "^4.0.8" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + } } }, "@sinonjs/text-encoding": { @@ -10759,12 +11285,6 @@ "@types/webidl-conversions": "*" } }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, "@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -10956,9 +11476,9 @@ } }, "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true }, "acorn-import-assertions": { @@ -10969,6 +11489,13 @@ "peer": true, "requires": {} }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -10981,11 +11508,41 @@ "uri-js": "^4.2.2" } }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "requires": { + "ajv": "^8.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, + "peer": true, "requires": {} }, "ansi-colors": { @@ -11053,55 +11610,85 @@ "@babel/runtime-corejs3": "^7.10.2" } }, + "array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + } + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, "array-includes": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", - "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", - "get-intrinsic": "^1.1.1", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", "is-string": "^1.0.7" } }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true + "array.prototype.findlastindex": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.2.tgz", + "integrity": "sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } }, "array.prototype.flat": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", - "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", "es-shim-unscopables": "^1.0.0" } }, "array.prototype.flatmap": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", - "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", "dev": true, - "peer": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", "es-shim-unscopables": "^1.0.0" } }, + "arraybuffer.prototype.slice": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", + "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + } + }, "asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -11130,6 +11717,12 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, "axe-core": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz", @@ -11172,46 +11765,13 @@ } }, "babel-loader": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", - "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", "dev": true, "requires": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^2.0.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, - "dependencies": { - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true - }, - "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true - }, - "loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - } + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" } }, "babel-messages": { @@ -11223,51 +11783,42 @@ "babel-runtime": "^6.22.0" } }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, "babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz", + "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==", "dev": true, "requires": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.2", + "semver": "^6.3.1" }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } }, "babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz", + "integrity": "sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" + "@babel/helper-define-polyfill-provider": "^0.4.2", + "core-js-compat": "^3.31.0" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz", + "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==", "dev": true, "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3" + "@babel/helper-define-polyfill-provider": "^0.4.2" } }, "babel-runtime": { @@ -11342,26 +11893,21 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, "body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "requires": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.10.3", - "raw-body": "2.5.1", + "qs": "6.11.0", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } @@ -11392,35 +11938,21 @@ "dev": true }, "browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" } }, "bson": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.0.tgz", - "integrity": "sha512-VrlEE4vuiO1WTpfof4VmaVolCVYkYTgB9iWgYNOrVlnifpME/06fhFRmONgBhClD5pFC1t9ZWqFUQEQAzY43bA==", - "requires": { - "buffer": "^5.6.0" - }, - "dependencies": { - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - } - } + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.4.0.tgz", + "integrity": "sha512-WRZ5SQI5GfUuKnPTNmAYPiKIof3ORXAF4IRU5UcgmivNIon01rWQlw5RUH954dpu8yGL8T59YShVddIPaU/gFA==" }, "buffer-from": { "version": "1.1.2", @@ -11449,9 +11981,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001416", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001416.tgz", - "integrity": "sha512-06wzzdAkCPZO+Qm4e/eNghZBDfVNDsCgw33T27OwBH9unE9S478OYw//Q2L7Npf/zBzs7rjZOszIFQkwQKAEqA==", + "version": "1.0.30001519", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz", + "integrity": "sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg==", "dev": true }, "chalk": { @@ -11578,6 +12110,12 @@ "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true }, + "common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -11618,9 +12156,9 @@ } }, "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, "convert-source-map": { "version": "1.8.0", @@ -11642,9 +12180,9 @@ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, "cookiejar": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", - "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", "dev": true }, "core-js": { @@ -11654,12 +12192,12 @@ "dev": true }, "core-js-compat": { - "version": "3.25.5", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.5.tgz", - "integrity": "sha512-ovcyhs2DEBUIE0MGEKHP4olCUW/XYte3Vroyxuh38rD1wAO4dHohsovUC4eAOuzFxE6b+RXvBU3UZ9o0YhUTkA==", + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.0.tgz", + "integrity": "sha512-7a9a3D1k4UCVKnLhrgALyFcP7YCsLOQIxPd0dKjf/6GuPcgyiGP70ewWdCGrSK7evyhymi0qO4EqCmSJofDeYw==", "dev": true, "requires": { - "browserslist": "^4.21.4" + "browserslist": "^4.21.9" } }, "core-js-pure": { @@ -11749,9 +12287,9 @@ } }, "define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", "dev": true, "requires": { "has-property-descriptors": "^1.0.0", @@ -11764,11 +12302,6 @@ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true }, - "denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" - }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -11789,9 +12322,9 @@ } }, "dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha512-K7i4zNfT2kgQz3GylDw40ot9GAE47sFZ9EXHFSPP6zONLgH6kWXE0KWJchkbQJLBkRazq4APwZ4OwiFFlT95OQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", "dev": true, "requires": { "asap": "^2.0.0", @@ -11804,15 +12337,6 @@ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -11828,9 +12352,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "electron-to-chromium": { - "version": "1.4.272", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.272.tgz", - "integrity": "sha512-KS6gPPGNrzpVv9HzFVq+Etd0AjZEPr5pvaTBn2yD6KV4+cKW4I0CJoJNgmTG6gUQPAMZ4wIPtcOuoou3qFAZCA==", + "version": "1.4.484", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.484.tgz", + "integrity": "sha512-nO3ZEomTK2PO/3TUXgEx0A97xZTpKVf4p427lABHuCpT1IQ2N+njVh29DkQkCk6Q4m2wjU+faK4xAcfFndwjvw==", "dev": true }, "emoji-regex": { @@ -11857,35 +12381,50 @@ } }, "es-abstract": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.3.tgz", - "integrity": "sha512-AyrnaKVpMzljIdwjzrj+LxGmj8ik2LckwXacHqrJJ/jxz6dDDBcZ7I7nlHM0FvEW8MfbWJwOd+yT2XzYW49Frw==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", + "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", "dev": true, "requires": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.1", + "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", + "get-intrinsic": "^1.2.1", "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.6", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", + "object-inspect": "^1.12.3", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", + "regexp.prototype.flags": "^1.5.0", + "safe-array-concat": "^1.0.0", "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.10" } }, "es-module-lexer": { @@ -11895,6 +12434,17 @@ "dev": true, "peer": true }, + "es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, "es-shim-unscopables": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", @@ -11933,49 +12483,47 @@ "dev": true }, "eslint": { - "version": "8.24.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.24.0.tgz", - "integrity": "sha512-dWFaPhGhTAiPcCgm3f6LI2MBWbogMnTJzFBbhXVRQDJPkr9pGZvVjlVfXd+vyDcWPA2Ic9L2AXPIQM0+vk/cSQ==", + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz", + "integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.3.2", - "@humanwhocodes/config-array": "^0.10.5", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.1", + "@eslint/js": "^8.46.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", - "ajv": "^6.10.0", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.2", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-sdsl": "^4.1.4", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "dependencies": { @@ -12060,9 +12608,9 @@ } }, "globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -12083,15 +12631,6 @@ "argparse": "^2.0.1" } }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -12156,13 +12695,14 @@ } }, "eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, "requires": { "debug": "^3.2.7", - "resolve": "^1.20.0" + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" }, "dependencies": { "debug": { @@ -12177,9 +12717,9 @@ } }, "eslint-module-utils": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", "dev": true, "requires": { "debug": "^3.2.7" @@ -12206,26 +12746,40 @@ } }, "eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.0.tgz", + "integrity": "sha512-B8s/n+ZluN7sxj9eUf7/pRFERX0r5bnFA2dCaLHy2ZeaQEAz0k+ZZkFWRFHJAqxfxQDx6KLv9LeIki7cFdwW+Q==", "dev": true, "requires": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.6", + "array.prototype.findlastindex": "^1.2.2", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.8.0", "has": "^1.0.3", - "is-core-module": "^2.8.1", + "is-core-module": "^2.12.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" + "object.fromentries": "^2.0.6", + "object.groupby": "^1.0.0", + "object.values": "^1.1.6", + "resolve": "^1.22.3", + "semver": "^6.3.1", + "tsconfig-paths": "^3.14.2" }, "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -12235,14 +12789,11 @@ "esutils": "^2.0.2" } }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true } } }, @@ -12268,16 +12819,6 @@ "semver": "^6.3.0" }, "dependencies": { - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "peer": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -12320,16 +12861,6 @@ "esutils": "^2.0.2" } }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "peer": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, "resolve": { "version": "2.0.0-next.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", @@ -12366,56 +12897,30 @@ "dev": true }, "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "requires": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz", + "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==", "dev": true }, "espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "requires": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "dependencies": { - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - } + "eslint-visitor-keys": "^3.4.1" } }, "esprima": { @@ -12425,9 +12930,9 @@ "dev": true }, "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "requires": { "estraverse": "^5.1.0" @@ -12467,13 +12972,13 @@ "peer": true }, "express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.0", + "body-parser": "1.20.1", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", @@ -12492,7 +12997,7 @@ "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.10.3", + "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.18.0", @@ -12504,6 +13009,36 @@ "vary": "~1.1.2" }, "dependencies": { + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -12517,31 +13052,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - } - } - }, "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", @@ -12561,9 +13071,9 @@ "dev": true }, "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -12623,14 +13133,58 @@ } }, "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", "dev": true, "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + } + }, + "find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "requires": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "dependencies": { + "locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "requires": { + "p-locate": "^6.0.0" + } + }, + "p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "requires": { + "yocto-queue": "^1.0.0" + } + }, + "p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "requires": { + "p-limit": "^4.0.0" + } + }, + "yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true + } } }, "flat": { @@ -12666,6 +13220,15 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, "form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -12678,23 +13241,15 @@ } }, "formidable": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.0.1.tgz", - "integrity": "sha512-rjTMNbp2BpfQShhFbR3Ruk3qk2y9jKpvMW78nJgx8QKtxjDVrwbZG+wvDOmVbifHyOUOQJXxqEy6r0faRrPzTQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", + "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", "dev": true, "requires": { - "dezalgo": "1.0.3", - "hexoid": "1.0.0", - "once": "1.4.0", - "qs": "6.9.3" - }, - "dependencies": { - "qs": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.3.tgz", - "integrity": "sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==", - "dev": true - } + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" } }, "forwarded": { @@ -12749,12 +13304,13 @@ "dev": true }, "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3" } }, @@ -12804,26 +13360,22 @@ "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", "dev": true }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "dependencies": { - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } + "get-intrinsic": "^1.1.3" } }, "graceful-fs": { @@ -12833,10 +13385,10 @@ "dev": true, "peer": true }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "handlebars": { @@ -12898,6 +13450,11 @@ "get-intrinsic": "^1.1.1" } }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -12951,15 +13508,10 @@ "safer-buffer": ">= 2.1.2 < 3" } }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true }, "import-fresh": { @@ -12995,12 +13547,12 @@ "dev": true }, "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", "dev": true, "requires": { - "get-intrinsic": "^1.1.0", + "get-intrinsic": "^1.2.0", "has": "^1.0.3", "side-channel": "^1.0.4" } @@ -13024,6 +13576,17 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + } + }, "is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", @@ -13050,9 +13613,9 @@ "dev": true }, "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", "dev": true, "requires": { "has": "^1.0.3" @@ -13112,6 +13675,12 @@ "has-tostringtag": "^1.0.0" } }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -13172,6 +13741,15 @@ "has-symbols": "^1.0.2" } }, + "is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "requires": { + "which-typed-array": "^1.1.11" + } + }, "is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -13193,6 +13771,12 @@ "call-bind": "^1.0.2" } }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -13359,12 +13943,6 @@ } } }, - "js-sdsl": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", - "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", - "dev": true - }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -13406,6 +13984,12 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, "jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", @@ -13424,9 +14008,9 @@ "dev": true }, "kareem": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.4.1.tgz", - "integrity": "sha512-aJ9opVoXroQUPfovYP5kaj2lM7Jn02Gw13bL0lg9v0V7SaUc0qavPs0Eue7d2DcC3NjqI6QAUElXNsuZSeM+EA==" + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", + "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==" }, "language-subtag-registry": { "version": "0.3.22", @@ -13566,29 +14150,12 @@ } }, "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } + "yallist": "^3.0.2" } }, "media-typer": { @@ -13614,12 +14181,6 @@ "dev": true, "peer": true }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, "method-override": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/method-override/-/method-override-3.0.0.tgz", @@ -13670,9 +14231,9 @@ } }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -13694,12 +14255,11 @@ } }, "mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", "dev": true, "requires": { - "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", "chokidar": "3.5.3", @@ -13930,38 +14490,37 @@ } }, "mongodb": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.9.1.tgz", - "integrity": "sha512-ZhgI/qBf84fD7sI4waZBoLBNJYPQN5IOC++SBCiPiyhzpNKOxN/fi0tBHvH2dEC42HXtNEbFB0zmNz4+oVtorQ==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.7.0.tgz", + "integrity": "sha512-zm82Bq33QbqtxDf58fLWBwTjARK3NSvKYjyz997KSy6hpat0prjeX/kxjbPVyZY60XYPDNETaHkHJI2UCzSLuw==", "requires": { - "bson": "^4.7.0", - "denque": "^2.1.0", - "mongodb-connection-string-url": "^2.5.3", + "bson": "^5.4.0", + "mongodb-connection-string-url": "^2.6.0", "saslprep": "^1.0.3", - "socks": "^2.7.0" + "socks": "^2.7.1" } }, "mongodb-connection-string-url": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.4.tgz", - "integrity": "sha512-SeAxuWs0ez3iI3vvmLk/j2y+zHwigTDKQhtdxTgt5ZCOQQS5+HW4g45/Xw5vzzbn7oQXCNQ24Z40AkJsizEy7w==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", "requires": { "@types/whatwg-url": "^8.2.1", "whatwg-url": "^11.0.0" } }, "mongoose": { - "version": "6.6.5", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.6.5.tgz", - "integrity": "sha512-iA/oDpWOc+K2QYzA4Eq7Z1oUBQOz9FGDmUwPLgw872Bfs/qizA5Db+gJorAn+TnnGu3VoCK8iP4Y+TECUelwjA==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.4.2.tgz", + "integrity": "sha512-sNolW2hyncwvWmZjIEIwAckjaSKtC1SE86zE1v2TKm3vPTRogZfBQf+3zLYYdrgrVTzoaoICieVpct9hjcn3EQ==", "requires": { - "bson": "^4.6.5", - "kareem": "2.4.1", - "mongodb": "4.9.1", + "bson": "^5.4.0", + "kareem": "2.5.1", + "mongodb": "5.7.0", "mpath": "0.9.0", - "mquery": "4.0.3", + "mquery": "5.0.0", "ms": "2.1.3", - "sift": "16.0.0" + "sift": "16.0.1" } }, "mpath": { @@ -13970,9 +14529,9 @@ "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==" }, "mquery": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz", - "integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", "requires": { "debug": "4.x" }, @@ -14021,18 +14580,27 @@ "dev": true }, "nise": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.1.tgz", - "integrity": "sha512-yr5kW2THW1AkxVmCnKEh4nbYkJdB3I7LUkiUgOvEkOp414mc2UMaHMA7pjq1nYowhdoJZGwEKGaQVbxfpWj10A==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.4.tgz", + "integrity": "sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==", "dev": true, "requires": { - "@sinonjs/commons": "^1.8.3", - "@sinonjs/fake-timers": ">=5", + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^10.0.2", "@sinonjs/text-encoding": "^0.7.1", "just-extend": "^4.0.2", "path-to-regexp": "^1.7.0" }, "dependencies": { + "@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -14051,9 +14619,9 @@ } }, "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, "nopt": { @@ -14077,9 +14645,9 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" }, "object-keys": { "version": "1.1.1", @@ -14111,15 +14679,26 @@ } }, "object.fromentries": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", - "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", "dev": true, - "peer": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.groupby": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.0.tgz", + "integrity": "sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.21.2", + "get-intrinsic": "^1.2.1" } }, "object.hasown": { @@ -14134,14 +14713,14 @@ } }, "object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" } }, "on-finished": { @@ -14162,17 +14741,17 @@ } }, "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", "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" + "type-check": "^0.4.0" } }, "p-limit": { @@ -14213,6 +14792,12 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -14236,12 +14821,6 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -14261,57 +14840,12 @@ "dev": true }, "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "dev": true, "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - } + "find-up": "^6.3.0" } }, "prelude-ls": { @@ -14341,10 +14875,15 @@ "ipaddr.js": "1.9.1" } }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" + }, "qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "requires": { "side-channel": "^1.0.4" } @@ -14370,9 +14909,9 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "requires": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -14403,57 +14942,45 @@ } }, "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", "dev": true }, "regenerator-transform": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", - "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", + "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", "dev": true, "requires": { "@babel/runtime": "^7.8.4" } }, "regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" } }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, "regexpu-core": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", - "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", "dev": true, "requires": { + "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.1.0", - "regjsgen": "^0.7.1", "regjsparser": "^0.9.1", "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" + "unicode-match-property-value-ecmascript": "^2.1.0" } }, - "regjsgen": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", - "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", - "dev": true - }, "regjsparser": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", @@ -14486,13 +15013,19 @@ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz", + "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==", "dev": true, "requires": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.12.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -14527,6 +15060,18 @@ "queue-microtask": "^1.2.2" } }, + "safe-array-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", + "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -14559,14 +15104,44 @@ } }, "schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "dev": true, "requires": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } } }, "semver": { @@ -14724,24 +15299,30 @@ } }, "sift": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.0.tgz", - "integrity": "sha512-ILTjdP2Mv9V1kIxWMXeMTIRbOBrqKc4JAXmFMnFq3fKeyQ2Qwa3Dw1ubcye3vR+Y6ofA0b9gNDr/y2t6eUeIzQ==" + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", + "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" }, "sinon": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-14.0.1.tgz", - "integrity": "sha512-JhJ0jCiyBWVAHDS+YSjgEbDn7Wgz9iIjA1/RK+eseJN0vAAWIWiXBdrnb92ELPyjsfreCYntD1ORtLSfIrlvSQ==", + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.2.0.tgz", + "integrity": "sha512-nPS85arNqwBXaIsFCkolHjGIkFo+Oxu9vbgmBJizLAhqe6P2o3Qmj3KCUoRkfhHtvgDhZdWD3risLHAUJ8npjw==", "dev": true, "requires": { - "@sinonjs/commons": "^1.8.3", - "@sinonjs/fake-timers": "^9.1.2", - "@sinonjs/samsam": "^6.1.1", - "diff": "^5.0.0", - "nise": "^5.1.1", + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^10.3.0", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.4", "supports-color": "^7.2.0" }, "dependencies": { + "diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "dev": true + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -14834,26 +15415,37 @@ "side-channel": "^1.0.4" } }, + "string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, "string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" } }, "string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" + "es-abstract": "^1.20.4" } }, "strip-ansi": { @@ -14878,21 +15470,21 @@ "dev": true }, "superagent": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.2.tgz", - "integrity": "sha512-QtYZ9uaNAMexI7XWl2vAXAh0j4q9H7T0WVEI/y5qaUB3QLwxo+voUgCQ217AokJzUTIVOp0RTo7fhZrwhD7A2Q==", + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.9.tgz", + "integrity": "sha512-4C7Bh5pyHTvU33KpZgwrNKh/VQnvgtCSqPRfJAUdmrtSYePVzVg4E4OzsrbkhJj9O7SO6Bnv75K/F8XVZT8YHA==", "dev": true, "requires": { "component-emitter": "^1.3.0", - "cookiejar": "^2.1.3", + "cookiejar": "^2.1.4", "debug": "^4.3.4", "fast-safe-stringify": "^2.1.1", "form-data": "^4.0.0", - "formidable": "^2.0.1", + "formidable": "^2.1.2", "methods": "^1.1.2", "mime": "2.6.0", "qs": "^6.11.0", - "semver": "^7.3.7" + "semver": "^7.3.8" }, "dependencies": { "debug": { @@ -14904,6 +15496,15 @@ "ms": "2.1.2" } }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, "mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -14916,34 +15517,31 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } }, "supertest": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.0.tgz", - "integrity": "sha512-QgWju1cNoacP81Rv88NKkQ4oXTzGg0eNZtOoxp1ROpbS4OHY/eK5b8meShuFtdni161o5X0VQvgo7ErVyKK+Ow==", + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.3.tgz", + "integrity": "sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==", "dev": true, "requires": { "methods": "^1.1.2", - "superagent": "^8.0.0" + "superagent": "^8.0.5" } }, "supports-color": { @@ -15029,13 +15627,6 @@ "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", "requires": { "punycode": "^2.1.1" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - } } }, "trim-right": { @@ -15045,21 +15636,21 @@ "dev": true }, "tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", "dev": true, "requires": { "@types/json5": "^0.0.29", - "json5": "^1.0.1", + "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" }, "dependencies": { "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -15097,6 +15688,53 @@ "mime-types": "~2.1.24" } }, + "typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, "uglify-js": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", @@ -15146,9 +15784,9 @@ } }, "unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", "dev": true }, "unicode-property-aliases-ecmascript": { @@ -15163,9 +15801,9 @@ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, "update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", "dev": true, "requires": { "escalade": "^3.1.1", @@ -15179,14 +15817,6 @@ "dev": true, "requires": { "punycode": "^2.1.0" - }, - "dependencies": { - "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 - } } }, "utils-merge": { @@ -15323,11 +15953,18 @@ "is-symbol": "^1.0.3" } }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true + "which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } }, "wordwrap": { "version": "1.0.0", @@ -15348,9 +15985,9 @@ "dev": true }, "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, "yargs-unparser": { diff --git a/package.json b/package.json index 04bc10a..2d600a0 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "node": ">=0.12" }, "scripts": { + "start": "node ./examples/index.js", "lint": "eslint src/", "prepublish": "make", "test": "make", @@ -28,47 +29,47 @@ ], "license": "MIT", "dependencies": { - "body-parser": "^1.20.0", + "body-parser": "^1.20.2", "cors": "2.8.5", - "express": "^4.18.1", + "express": "^4.18.2", "method-override": "3.0.0", - "mongoose": "6.6.5", + "mongoose": "7.4.2", "uuid": "9.0.0" }, "devDependencies": { - "@babel/cli": "^7.19.3", - "@babel/core": "^7.19.3", - "@babel/eslint-parser": "^7.19.1", - "@babel/helpers": "^7.19.0", - "@babel/plugin-proposal-class-properties": "^7.0.0", - "@babel/plugin-proposal-decorators": "^7.0.0", - "@babel/plugin-proposal-do-expressions": "^7.0.0", - "@babel/plugin-proposal-export-default-from": "^7.0.0", - "@babel/plugin-proposal-export-namespace-from": "^7.0.0", - "@babel/plugin-proposal-function-bind": "^7.0.0", - "@babel/plugin-proposal-function-sent": "^7.0.0", - "@babel/plugin-proposal-json-strings": "^7.0.0", - "@babel/plugin-proposal-logical-assignment-operators": "^7.0.0", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0", - "@babel/plugin-proposal-numeric-separator": "^7.0.0", - "@babel/plugin-proposal-optional-chaining": "^7.0.0", - "@babel/plugin-proposal-pipeline-operator": "^7.0.0", - "@babel/plugin-proposal-throw-expressions": "^7.0.0", - "@babel/plugin-syntax-dynamic-import": "^7.0.0", - "@babel/plugin-syntax-import-meta": "^7.0.0", - "@babel/preset-env": "^7.19.3", - "@babel/register": "^7.18.9", - "@babel/runtime": "^7.19.0", - "babel-loader": "8.2.5", - "eslint": "8.24.0", + "@babel/cli": "^7.22.9", + "@babel/core": "^7.22.9", + "@babel/eslint-parser": "^7.22.9", + "@babel/helpers": "^7.22.6", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-decorators": "^7.22.7", + "@babel/plugin-proposal-do-expressions": "^7.22.5", + "@babel/plugin-proposal-export-default-from": "^7.22.5", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-function-bind": "^7.22.5", + "@babel/plugin-proposal-function-sent": "^7.22.5", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.20.7", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.21.0", + "@babel/plugin-proposal-pipeline-operator": "^7.22.5", + "@babel/plugin-proposal-throw-expressions": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/preset-env": "^7.22.9", + "@babel/register": "^7.22.5", + "@babel/runtime": "^7.22.6", + "babel-loader": "9.1.3", + "eslint": "8.46.0", "eslint-config-airbnb": "19.0.4", "eslint-plugin-babel": "5.3.1", - "eslint-plugin-import": "^2.26.0", + "eslint-plugin-import": "^2.28.0", "istanbul": "1.1.0-alpha.1", - "mocha": "10.0.0", + "mocha": "10.2.0", "should": "13.2.3", "should-sinon": "0.0.6", - "sinon": "14.0.1", - "supertest": "6.3.0" + "sinon": "15.2.0", + "supertest": "6.3.3" } } diff --git a/src/ODataResource.js b/src/ODataResource.js deleted file mode 100644 index 9be87f4..0000000 --- a/src/ODataResource.js +++ /dev/null @@ -1,184 +0,0 @@ -import rest from './rest'; -import { min } from './utils'; - -function hook(resource, pos, fn) { - let method = resource._currentMethod; - if (method === 'all') { - method = ['get', 'post', 'put', 'delete', 'patch', 'list']; - } else { - method = [method]; - } - /*eslint-disable */ - method.map((curr) => { - if (resource._hooks[curr][pos]) { - const _fn = resource._hooks[curr][pos]; - resource._hooks[curr][pos] = (...args) => { - _fn.apply(resource, args); - fn.apply(resource, args); - }; - } else { - resource._hooks[curr][pos] = fn; - } - }); - /* eslint-enable */ -} - -export default class { - constructor(server, name, userModel) { - this._server = server; - this._name = name; - this._url = name; - this._model = userModel; - this._hooks = { - list: {}, - get: {}, - post: {}, - put: {}, - delete: {}, - patch: {}, - }; - this.actions = {}; - this._options = { - maxTop: 10000, - maxSkip: 10000, - orderby: undefined, - }; - } - - getName() { - return this._name; - } - - setModel(model) { - this.model = model; - } - - action(url, fn, options) { - let auth; - let binding; - - if (options) { - auth = options.auth; - binding = options.binding; - } - - this.actions[url] = fn; - this.actions[url].auth = auth; - this.actions[url].binding = binding; - this.actions[url].resource = this._url; - - const resourceUrl = !binding || binding === 'entity' // 'entity' || 'collection' - ? `/${this._url}\\(:id\\)` : `/${this._url}`; - this.actions[url].router = rest.getOperationRouter(resourceUrl, url, fn, auth); - - return this; - } - - maxTop(count) { - this._maxTop = count; - return this; - } - - maxSkip(count) { - this._maxSkip = count; - return this; - } - - orderBy(field) { - this._orderby = field; - return this; - } - - list() { - this._currentMethod = 'list'; - return this; - } - - get() { - this._currentMethod = 'get'; - return this; - } - - post() { - this._currentMethod = 'post'; - return this; - } - - put() { - this._currentMethod = 'put'; - return this; - } - - delete() { - this._currentMethod = 'delete'; - return this; - } - - patch() { - this._currentMethod = 'patch'; - return this; - } - - all() { - this._currentMethod = 'all'; - return this; - } - - before(fn) { - hook(this, 'before', fn); - return this; - } - - after(fn) { - hook(this, 'after', fn); - return this; - } - - auth(fn) { - let method = this._currentMethod; - if (method === 'all') { - method = ['get', 'post', 'put', 'delete', 'patch', 'list']; - } else { - method = [method]; - } - method.map((curr) => { - this._hooks[curr].auth = fn; - return undefined; - }); - return this; - } - - url(url) { - this._url = url; - return this; - } - - _router(setting = {}) { - // remove '/' if url is startwith it. - if (this._url.indexOf('/') === 0) { - this._url = this._url.substr(1); - } - - // not allow contain '/' in url. - if (this._url.indexOf('/') >= 0) { - throw new Error(`Url of resource[${this._name}] can't contain "/",` - + 'it can only be allowed to exist in the beginning.'); - } - - const params = { - url: this._url, - options: { - maxTop: min([setting.maxTop, this._maxTop]), - maxSkip: min([setting.maxSkip, this._maxSkip]), - orderby: this._orderby || setting.orderby, - }, - hooks: this._hooks, - }; - - return rest.getRouter(this.model, params); - } - - find() { - return this.model.find(); - } -} diff --git a/src/db/db.js b/src/db/db.js deleted file mode 100644 index 7978f57..0000000 --- a/src/db/db.js +++ /dev/null @@ -1,39 +0,0 @@ -import mongoose from 'mongoose'; -import Model from './model'; -import id from './idPlugin'; - -mongoose.Promise = global.Promise; - -export default class { - constructor() { - this._models = {}; - } - - createConnection(connection, optionsIn, onError) { - const options = { - ...optionsIn, - server: { reconnectTries: Number.MAX_VALUE }, - }; - - this._connection = mongoose.createConnection(connection, options, onError); - - return this._connection; - } - - on(name, event) { - this._connection.on(name, event); - } - - register(name, model) { - const conf = { - _id: false, - versionKey: false, - collection: name, - }; - const schema = new mongoose.Schema(model, conf); - schema.plugin(id); - const mongooseModel = this._connection.model(name, schema); - this._models[name] = new Model(mongooseModel); - return this._models[name]; - } -} diff --git a/src/db/idPlugin.js b/src/db/idPlugin.js deleted file mode 100644 index 10f6881..0000000 --- a/src/db/idPlugin.js +++ /dev/null @@ -1,55 +0,0 @@ -import * as uuid from 'uuid'; - -/*eslint-disable */ -export default function (schema) { - // add _id to schema. - if (!schema.paths._id) { - schema.add({ - _id: { - type: String, - unique: true, - } - }); - } - - // display value of _id when request id. - if (!schema.paths.id) { - schema.virtual('id').get(function getId() { - return this._id; - }); - schema.set('toObject', { virtuals: true }); - schema.set('toJSON', { virtuals: true }); - } - - // reomove _id when serialization. - if (!schema.options.toObject) { - schema.options.toObject = {}; - } - if (!schema.options.toJSON) { - schema.options.toJSON = {}; - } - const remove = (doc, ret) => { - delete ret._id; - if (!ret.id) { - delete ret.id; - } - return ret; - }; - schema.options.toObject.transform = remove; - schema.options.toJSON.transform = remove; - - // genarate _id. - schema.pre('save', function preSave(next) { - if (this.isNew && !this._id) { - if (this.id) { - // Use a user-defined id to save - this._id = this.id; - } else { - // Use uuid to save - this._id = uuid.v4(); - } - } - return next(); - }); -} -/* eslint-enable */ diff --git a/src/db/model.js b/src/db/model.js deleted file mode 100644 index 0c19bf9..0000000 --- a/src/db/model.js +++ /dev/null @@ -1,34 +0,0 @@ -export default class { - constructor(mongooseModel) { - this.model = mongooseModel; - } - - create(data) { - const MongooseModel = this.model; - return new MongooseModel(data); - } - - find() { - return this.model.find(); - } - - findById(id, callback) { - this.model.findById(id, callback); - } - - findByIdAndUpdate(id, data, callback) { - this.model.findByIdAndUpdate(id, data, callback); - } - - findOne(filter, callback) { - this.model.findOne(filter, callback); - } - - remove(filter, callback) { - this.model.remove(filter, callback); - } - - update(filter, data, callback) { - this.model.update(filter, data, callback); - } -} diff --git a/src/express.js b/src/express.js index cafa642..b593306 100644 --- a/src/express.js +++ b/src/express.js @@ -1,14 +1,13 @@ import express from 'express'; -import bodyParser from 'body-parser'; import methodOverride from 'method-override'; import cors from 'cors'; +import bodyParser from 'body-parser'; export default function orientExpress(options) { const app = express(); const opts = (options && options.expressRequestLimit) ? { limit: options.expressRequestLimit } : {}; - app.use(bodyParser.json(opts)); opts.extended = true; app.use(bodyParser.urlencoded(opts)); app.use(methodOverride()); diff --git a/src/index.js b/src/index.js index 7aa5b7f..8437490 100644 --- a/src/index.js +++ b/src/index.js @@ -1,10 +1,11 @@ import express from 'express'; import Server from './server'; -const server = function server(db, prefix, options) { +export const odata = function server(db, prefix, options) { return new Server(db, prefix, options); }; -server._express = express; +odata._express = express; + +export default odata; -export default server; diff --git a/src/metadata/ODataMetadata.js b/src/metadata/ODataMetadata.js deleted file mode 100644 index 2760ea7..0000000 --- a/src/metadata/ODataMetadata.js +++ /dev/null @@ -1,228 +0,0 @@ -import { Router } from 'express'; -import pipes from '../pipes'; -import Resource from '../ODataResource'; - -export default class Metadata { - constructor(server) { - this._server = server; - this._hooks = { - }; - this._count = 0; - } - - get() { - return this; - } - - before(fn) { - this._hooks.before = fn; - return this; - } - - after(fn) { - this._hooks.after = fn; - return this; - } - - auth(fn) { - this._hooks.auth = fn; - return this; - } - - _router() { - /*eslint-disable */ - const router = Router(); - /* eslint-enable */ - router.get('/\\$metadata', (req, res) => { - pipes.authorizePipe(req, res, this._hooks.auth) - .then(() => pipes.beforePipe(req, res, this._hooks.before)) - .then(() => this.ctrl(req)) - .then((result) => pipes.respondPipe(req, res, result || {})) - .then((data) => pipes.afterPipe(req, res, this._hooks.after, data)) - .catch((err) => pipes.errorPipe(req, res, err)); - }); - - return router; - } - - visitProperty(node, root) { - const result = {}; - - switch (node.instance) { - case 'ObjectId': - result.$Type = 'self.ObjectId'; - break; - - case 'Number': - result.$Type = 'Edm.Double'; - break; - - case 'Date': - result.$Type = 'Edm.DateTimeOffset'; - break; - - case 'String': - result.$Type = 'Edm.String'; - break; - - case 'Array': // node.path = p1; node.schema.paths - result.$Collection = true; - if (node.schema && node.schema.paths) { - this._count += 1; - const notClassifiedName = `${node.path}Child${this._count}`; - // Array of complex type - result.$Type = `self.${notClassifiedName}`; - root(notClassifiedName, this.visitor('ComplexType', node.schema.paths, root)); - } else { - const arrayItemType = this.visitor('Property', { instance: node.options.type[0].name }, root); - - result.$Type = arrayItemType.$Type; - } - break; - - default: - return null; - } - - return result; - } - - visitEntityType(node, root) { - const properties = Object.keys(node) - .filter((path) => path !== '_id') - .reduce((previousProperty, curentProperty) => { - const result = { - ...previousProperty, - [curentProperty]: this.visitor('Property', node[curentProperty], root), - }; - - return result; - }, {}); - - return { - $Kind: 'EntityType', - $Key: ['id'], - id: { - $Type: 'self.ObjectId', - $Nullable: false, - }, - ...properties, - }; - } - - visitComplexType(node, root) { - const properties = Object.keys(node) - .filter((item) => item !== '_id') - .reduce((previousProperty, curentProperty) => { - const result = { - ...previousProperty, - [curentProperty]: this.visitor('Property', node[curentProperty], root), - }; - - return result; - }, {}); - - return { - $Kind: 'ComplexType', - ...properties, - }; - } - - static visitAction(node) { - return { - $Kind: 'Action', - $IsBound: true, - $Parameter: [{ - $Name: node.resource, - $Type: `self.${node.resource}`, - $Collection: node.binding === 'collection' ? true : undefined, - }], - }; - } - - static visitFunction(node) { - return { - $Kind: 'Function', - ...node.params, - }; - } - - visitor(type, node, root) { - switch (type) { - case 'Property': - return this.visitProperty(node, root); - - case 'ComplexType': - return this.visitComplexType(node, root); - - case 'Action': - return Metadata.visitAction(node); - - case 'Function': - return Metadata.visitFunction(node, root); - - default: - return this.visitEntityType(node, root); - } - } - - ctrl() { - const entityTypeNames = Object.keys(this._server.resources); - const entityTypes = entityTypeNames.reduce((previousResource, currentResource) => { - const resource = this._server.resources[currentResource]; - const result = { ...previousResource }; - const attachToRoot = (name, value) => { result[name] = value; }; - - if (resource instanceof Resource) { - const { paths } = resource.model.model.schema; - - result[currentResource] = this.visitor('EntityType', paths, attachToRoot); - const actions = Object.keys(resource.actions); - if (actions && actions.length) { - actions.forEach((action) => { - result[action] = this.visitor('Action', resource.actions[action], attachToRoot); - }); - } - } else { - result[currentResource] = this.visitor('Function', resource, attachToRoot); - } - - return result; - }, {}); - - const entitySetNames = Object.keys(this._server.resources); - const entitySets = entitySetNames.reduce((previousResource, currentResource) => { - const result = { ...previousResource }; - result[currentResource] = this._server.resources[currentResource] instanceof Resource ? { - $Collection: true, - $Type: `self.${currentResource}`, - } : { - $Function: `self.${currentResource}`, - }; - - return result; - }, {}); - - const document = { - $Version: '4.0', - ObjectId: { - $Kind: 'TypeDefinition', - $UnderlyingType: 'Edm.String', - $MaxLength: 24, - }, - ...entityTypes, - $EntityContainer: 'org.example.DemoService', - ['org.example.DemoService']: { // eslint-disable-line no-useless-computed-key - $Kind: 'EntityContainer', - ...entitySets, - }, - }; - - return new Promise((resolve) => { - resolve({ - status: 200, - metadata: document, - }); - }); - } -} diff --git a/src/metadata/xmlWriter.js b/src/metadata/xmlWriter.js deleted file mode 100644 index 34a109b..0000000 --- a/src/metadata/xmlWriter.js +++ /dev/null @@ -1,186 +0,0 @@ -export default class XmlWriter { - visitor(type, node, name) { - switch (type) { - case 'document': - return this.visitDocument(node); - - case 'EntityType': - return this.visitEntityType(node, name); - - case 'Property': - return XmlWriter.visitProperty(node, name); - - case 'EntityContainer': - return this.visitEntityContainter(node); - - case 'EntitySet': - return XmlWriter.visitEntitySet(node, name); - - case 'TypeDefinition': - return XmlWriter.visitTypeDefinition(node, name); - - case 'ComplexType': - return this.visitComplexType(node, name); - - case 'Action': - return XmlWriter.visitAction(node, name); - - case 'Function': - return XmlWriter.visitFunction(node, name); - - case 'FunctionImport': - return XmlWriter.visitFunctionImport(node, name); - - default: - throw new Error(`Type ${type} is not supported`); - } - } - - visitDocument(node) { - let body = ''; - - Object.keys(node).forEach((subnode) => { - if (node[subnode].$Kind) { - body += this.visitor(node[subnode].$Kind, node[subnode], subnode); - } - }); - - return ( - ` - - - ${body} - - - `); - } - - static visitEntitySet(node, name) { - return ``; - } - - visitEntityContainter(node) { - let entitySets = ''; - let functions = ''; - - Object.keys(node) - .filter((item) => item !== '$Kind') - .forEach((item) => { - if (node[item].$Type) { - entitySets += this.visitor('EntitySet', node[item], item); - } else { - functions += this.visitor('FunctionImport', node[item], item); - } - }); - return ( - ` - ${entitySets}${functions} - `); - } - - static visitProperty(node, name) { - let attributes = ''; - - if (node.$Nullable === false) { - attributes += ' Nullable="false"'; - } - if (node.$MaxLength) { - attributes += ` MaxLength="${node.$MaxLength}"`; - } - if (node.$Collection) { - attributes += ' Collection="true"'; - } - - return ``; - } - - visitEntityType(node, name) { - let properties = ''; - - Object.keys(node) - .filter((item) => item !== '$Kind' && item !== '$Key') - .forEach((item) => { - properties += this.visitor('Property', node[item], item); - }); - - return ( - ` - - - - ${properties} - `); - } - - static visitTypeDefinition(node, name) { - let attributes = ''; - - if (node.$MaxLength) { - attributes += ` MaxLength="${node.$MaxLength}"`; - } - - return ( - ` - `); - } - - visitComplexType(node, name) { - let properties = ''; - - Object.keys(node) - .filter((item) => item !== '$Kind') - .forEach((item) => { - properties += this.visitor('Property', node[item], item); - }); - - return (` - - ${properties} - `); - } - - static visitAction(node, name) { - const isBound = node.$IsBound ? ' IsBound="true"' : ''; - const parameter = node.$Parameter.map((item) => { - let type = ''; - - if (item.$Collection) { - type = ` Type="Collection(${item.$Type})"`; - } else if (item.$Type) { - type = ` Type="${item.$Type}"`; - } - - return ``; - }); - - return (` - - ${parameter} - - `); - } - - static visitFunction(node, name) { - const collection = node.$ReturnType.$Collection ? ' Collection="true"' : ''; - - return (` - - - - `); - } - - static visitFunctionImport(node, name) { - return (` - - `); - } - - writeXml(res, data, status, resolve) { - const xml = this.visitor('document', data, '', '').replace(/\s*\s*/g, '>'); - - res.type('application/xml'); - res.status(status).send(xml); - resolve(data); - } -} diff --git a/src/middlewares/error.js b/src/middlewares/error.js new file mode 100644 index 0000000..333fe64 --- /dev/null +++ b/src/middlewares/error.js @@ -0,0 +1,25 @@ +import http from 'http'; +import Console from '../writer/Console'; + +export default function(err, req, res, next) { + const status = err.status || 500; + const result = { + error: { + code: status.toString() + } + }; + + if (status < 500) { + result.error.message = err.message || http.STATUS_CODES[status]; + result.error.target = err.target; + result.error.details = err.details; + + } else { + const cons = new Console(); + + result.error.message = http.STATUS_CODES[status]; + cons.log(err); + + } + res.status(+status).jsonp(result); +} \ No newline at end of file diff --git a/src/middlewares/writer.js b/src/middlewares/writer.js new file mode 100644 index 0000000..bbbab27 --- /dev/null +++ b/src/middlewares/writer.js @@ -0,0 +1,107 @@ +import XmlWriter from '../writer/xmlWriter'; +import JsonWirter from '../writer/jsonWriter'; +import MultipartWriter from '../writer/multipartWriter'; +import MimetypeParser from '../parser/mimetypeParser' + +const xmlWriter = new XmlWriter(); +const jsonWriter = new JsonWirter(); +const multipartWriter = new MultipartWriter(); + +function getContentType(req) { + if (req.headers && req.headers['content-type']) { + const result = req.headers['content-type']; + + return result.indexOf(';') > 0 ? result.split(';')[0] : result; + } +} + +function getWriter(req, res, result) { + const supportedFormats = res.$odata.supportedMimetypes; + let format = req.query.$format; + + let accept; + let requrestContentType; + if (req.headers) { + accept = req.headers.accept ? req.headers.accept : undefined; + requrestContentType = result.responses && getContentType(req) ? getContentType(req) : undefined; + } + + const mimetyeParser = new MimetypeParser(); + const mediaType = mimetyeParser.getmMediaType(format, accept, supportedFormats, requrestContentType); + + res.type(mediaType); + + // xml representation of metadata + switch (mediaType) { + case 'application/json': + return jsonWriter.writeJson.bind(jsonWriter); + + case 'application/xml': + return xmlWriter.writeXml.bind(xmlWriter); + + case 'multipart/mixed': + return multipartWriter.write.bind(multipartWriter); + + case 'text/plain': + return (res, data, status) => { + res.status(status).send(data); + }; + + default: + const error406 = new Error('Not acceptable'); + + error406.status = 406; + throw error406; + } +} + +function writeMessages(res) { + if (res.$odata.messages.length) { + res.$odata.messages.forEach(msg => { + if (!msg.code) { + throw new Error(`Missing 'code' property in message`); + } + if (!msg.message) { + throw new Error(`Missing 'message' property in message`); + } + if (!msg.numericSeverity) { + throw new Error(`Missing 'numericSeverity' property in message`); + } + if ([1,2,3,4].indexOf(msg.numericSeverity) === -1) { + throw new Error(`Value '${msg.numericSeverity}' is invalid for severity`); + } + }); + res.setHeader('sap-messages', JSON.stringify(res.$odata.messages)); + } +} + +export default function writer(req, res) { + writeMessages(res); + + switch (res.$odata.status) { + case 404: + // not found or no handler worked on + const err = new Error('Not found'); + err.status = 404; + throw err; + + case 204:// no content + res.status(res.$odata.status).end(); + return; + + case undefined: + throw new Error('Status not setted'); + + default: + if (res.$odata.result === undefined) { + throw new Error('If status not equal 204 res.$odata.result has to be set'); + } + } + + const status = res.$odata.status; + const writer = getWriter(req, res, res.$odata.result); + + res.setHeader('OData-Version', `4.0`); + writer(res, res.$odata.result, status, req.httpVersion); + +} \ No newline at end of file diff --git a/src/model/idPlugin.js b/src/model/idPlugin.js deleted file mode 100644 index 10f6881..0000000 --- a/src/model/idPlugin.js +++ /dev/null @@ -1,55 +0,0 @@ -import * as uuid from 'uuid'; - -/*eslint-disable */ -export default function (schema) { - // add _id to schema. - if (!schema.paths._id) { - schema.add({ - _id: { - type: String, - unique: true, - } - }); - } - - // display value of _id when request id. - if (!schema.paths.id) { - schema.virtual('id').get(function getId() { - return this._id; - }); - schema.set('toObject', { virtuals: true }); - schema.set('toJSON', { virtuals: true }); - } - - // reomove _id when serialization. - if (!schema.options.toObject) { - schema.options.toObject = {}; - } - if (!schema.options.toJSON) { - schema.options.toJSON = {}; - } - const remove = (doc, ret) => { - delete ret._id; - if (!ret.id) { - delete ret.id; - } - return ret; - }; - schema.options.toObject.transform = remove; - schema.options.toJSON.transform = remove; - - // genarate _id. - schema.pre('save', function preSave(next) { - if (this.isNew && !this._id) { - if (this.id) { - // Use a user-defined id to save - this._id = this.id; - } else { - // Use uuid to save - this._id = uuid.v4(); - } - } - return next(); - }); -} -/* eslint-enable */ diff --git a/src/model/index.js b/src/model/index.js deleted file mode 100644 index 5cbb21b..0000000 --- a/src/model/index.js +++ /dev/null @@ -1,15 +0,0 @@ -import mongoose from 'mongoose'; -import id from './idPlugin'; - -const register = (_db, name, model) => { - const conf = { - _id: false, - versionKey: false, - collection: name, - }; - const schema = new mongoose.Schema(model, conf); - schema.plugin(id); - return _db.model(name, schema); -}; - -export default { register }; diff --git a/src/mongo/Entity.js b/src/mongo/Entity.js new file mode 100644 index 0000000..b5ae4c7 --- /dev/null +++ b/src/mongo/Entity.js @@ -0,0 +1,307 @@ +import list from './rest/list'; +import post from './rest/post'; +import put from './rest/put'; +import del from './rest/delete'; +import patch from './rest/patch'; +import get from './rest/get'; +import count from './rest/count'; +import { validate, validateIdentifier } from '../odata/validator'; + +export default class MongoEntity { + constructor(name, model, annotations) { + this.name = name; + this.model = model; + this.annotations = annotations; + + this.complexTypes = {}; + this.count = 0; + this._mapping = { + id: { + intern: '_id', + attributes: { + $Type: 'Edm.String', + $MaxLength: 24, + $Nullable: true + } + } + }; + + } + + getHandler() { + const rest = { + post, + put, + patch, + delete: del, + get, + count, + list + }; + const routes = Object.keys(rest); + let handler = {}; + + routes.forEach((route) => { + handler[route] = async (req, res, next) => { + try { + req.$odata = { + ...req.$odata, + Model: this.model + }; + await rest[route](req, res, next); + + } catch (err) { + next(err); + } + }; + }); + + return handler; + } + + getMetadata() { + if (!this.metadata) { + const { paths } = this.model.schema; + + this.metadata = this.visitor('EntityType', paths); + } + + return this.metadata; + } + + get mapping() { + return this._mapping; + } + + set mapping(value) { + // update types of properties + Object.keys(value).forEach(name => { + //TODO: validation + if (this.metadata[name]?.$Type != value[name]?.attributes?.$Type) { + delete this.complexType[this.metadata[name].$Type]; + this.metadata[name].$Type = value[name].attributes.$Type; + } + }); + this._mapping = value; + } + + getComplexTypes() { + if (!this.metadata) { + this.getMetadata(); + } + + return this.complexTypes; + } + + visitor(type, node) { + switch (type) { + case 'Property': + return this.visitProperty(node); + + case 'ComplexType': + return this.visitComplexType(node); + + default: + return this.visitEntityType(node); + } + } + + visitProperty(node) { + let result = {}; + + if (node.selected === false) {// hidden field + return; + } + + if (!node.isRequired) { + result.$Nullable = true; + } + + if ('Array ObjectID'.indexOf(node.instance) === -1 && node.defaultValue) { + result.$DefaultValue = node.defaultValue; + } + + switch (node.instance) { + case 'Boolean': + result.$Type = 'Edm.Boolean'; + break; + + case 'Number': + result.$Type = 'Edm.Double'; + break; + + case 'Date': + // annotate generated timestamps as readonly + const { createdAt, updatedAt } = this.model.schema.$timestamps; + + if ((node.path === createdAt || node.path === updatedAt) + && this.annotations.isDefined('readonly')) { + result = { + ...result, + ...this.annotations.annotate('readonly', 'Property', true) + }; + } + + result.$Type = 'Edm.DateTimeOffset'; + break; + + case 'String': + result.$Type = 'Edm.String'; + if (node.options?.maxLength) { + result.$MaxLength = node.options.maxLength; + } + break; + + case 'Array': + result.$Collection = true; + if (node.schema && node.schema.paths) { + // Array of complex type + result.$Type = this.complexType(node); + } else { + const arrayItemType = this.visitor('Property', { + instance: node.options.type[0].name || node.options.type[0].type.name //Enums have an object with enum and type + }); + + if (!arrayItemType) { // hidden properties returns undefined + return; + } + + result.$Type = arrayItemType.$Type; + } + break; + + default: + return null; + } + + return result; + } + + complexType(node) { + const mapping = Object.keys(this.mapping).find(item => this.mapping[item].intern === node.path); + + if (mapping && this.mapping[mapping].attributes?.$Type) { + return this.mapping[mapping].attributes?.$Type; + } + + this.count += 1; + + const notClassifiedName = `${this.name}${node.path}Child${this.count}`; + const properties = this.visitor('ComplexType', node.schema.paths); + + if (this.complexTypes[notClassifiedName]) { + throw new Error(`Complex type with name ${notClassifiedName} allready exists`); + } + + validateIdentifier(notClassifiedName); + + const typeObject = { + $Kind: 'ComplexType', + ...properties + }; + validate(typeObject); + + this.complexTypes[notClassifiedName] = typeObject; + + return `node.odata.${notClassifiedName}`; + } + + visitComplexType(node) { + return this.reduceProperties(node); + } + + reduceProperties(node) { + const keys = Object.keys(node); + const simpleProperties = keys.filter((path) => path !== '__v' && path.indexOf('.') === -1) + .reduce((previousProperty, curentProperty) => { + let result; + let propertyName = Object.keys(this.mapping) + .find(name => this.mapping[name]?.intern === curentProperty); + + if (propertyName && this.mapping[propertyName].attributes) { + result = { + ...previousProperty, + [propertyName]: this.mapping[propertyName].attributes + }; + + } else { + propertyName = curentProperty.replace(/\./g, '-'); + if (propertyName !== curentProperty) { + this.addMapping(curentProperty, propertyName); + } + + const property = this.visitor('Property', node[curentProperty]); + + result = property ? { + ...previousProperty, + [propertyName]: property + } : previousProperty; + + } + + return result; + }, {}); + + const deepNodes = keys.filter(key => { + if (key.indexOf('.') >= 0) { + return true; + } + }) + .reduce((previousProperty, curentProperty) => { + const nameParts = curentProperty.split('.'); + const objName = nameParts[0]; + const propertyName = curentProperty.substring(objName.length + 1); + + if (!previousProperty[objName]) { + // not first property of an object + previousProperty[objName] = { + path: objName, + schema: { + paths: {} + } + }; + } + + previousProperty[objName].schema.paths[propertyName] = { + ...node[curentProperty], + path: propertyName + }; + + return previousProperty; + }, {}); + + const deepProperties = Object.keys(deepNodes) + .reduce((previousProperty, curentProperty) => { + previousProperty[curentProperty] = { + $Type: this.complexType(deepNodes[curentProperty]) + }; + + return previousProperty; + }, {}); + + return { + ...simpleProperties, + ...deepProperties + } + } + + visitEntityType(node) { + const properties = this.reduceProperties(node); + + return { + $Key: ['id'], + ...properties, + }; + } + + addMapping(mongoProperty, odataProperty) { + if (this.mapping[odataProperty]) { + throw new Error(`Mapping for property '${odataProperty}' is already set`); + } + + this.mapping[odataProperty] = { + intern: mongoProperty + }; + } + +} diff --git a/src/mongo/Singleton.js b/src/mongo/Singleton.js new file mode 100644 index 0000000..359e638 --- /dev/null +++ b/src/mongo/Singleton.js @@ -0,0 +1,60 @@ +import MongoEntity from "./Entity"; +import post from './rest/post'; +import put from './rest/put'; +import del from './rest/delete'; +import getSingleton from "./rest/getSingleton"; +import patchSingleton from "./rest/patchSingleton"; + +export default class MongoSingleton { + constructor(name, model, annotations) { + this.name = name; + this._entity = new MongoEntity(name, model, annotations); + + } + + get entity () { + return this._entity; + } + + set entity(value) { + this._entity = value; + } + + get mapping() { + return this.entity.mapping; + } + + set mapping(value) { + this.entity.mapping = value; + } + + getHandler() { + const rest = { + post, + put, + patch: patchSingleton, + delete: del, + get: getSingleton + }; + const routes = Object.keys(rest); + let handler = {}; + + routes.forEach((route) => { + handler[route] = async (req, res, next) => { + try { + req.$odata = { + ...req.$odata, + Model: this.entity.model + }; + await rest[route](req, res, next); + + } catch (err) { + next(err); + } + }; + }); + + return handler; + } + +} \ No newline at end of file diff --git a/src/mongo/applyClient.js b/src/mongo/applyClient.js new file mode 100644 index 0000000..5901786 --- /dev/null +++ b/src/mongo/applyClient.js @@ -0,0 +1,7 @@ +export default function applyClient(req, entity) { + if (!req.$odata.clientField) { + return; + } + + entity[req.$odata.clientField] = req.$odata.client; +} \ No newline at end of file diff --git a/src/mongo/middlewares/error.js b/src/mongo/middlewares/error.js new file mode 100644 index 0000000..9251ddf --- /dev/null +++ b/src/mongo/middlewares/error.js @@ -0,0 +1,24 @@ +import error from '../../middlewares/error'; + +export default function(err, req, res, next) { + let mappedError = err; + + if (err.name === 'ValidationError') { + const details = Object.keys(err.errors).map(name => { + return { + code: '400', + target: name, + message: err.errors[name].message, + '@com.sap.vocabularies.Common.v1.numericSeverity': 4 + }; + }); + mappedError = new Error(details[0].message); + mappedError.target = details[0].target; + mappedError.status = '400'; + if (details.lenght > 1) { + mappedError.details = details.slice(1); + } + } + + error(mappedError, req, res, next); +} \ No newline at end of file diff --git a/src/mongo/parser/filterParser.js b/src/mongo/parser/filterParser.js new file mode 100644 index 0000000..fcf4456 --- /dev/null +++ b/src/mongo/parser/filterParser.js @@ -0,0 +1,71 @@ +// Operator Description Example +// Comparison Operators +// eq Equal Address/City eq 'Redmond' +// ne Not equal Address/City ne 'London' +// gt Greater than Price gt 20 +// ge Greater than or equal Price ge 10 +// lt Less than Price lt 20 +// le Less than or equal Price le 100 +// has Has flags Style has Sales.Color'Yellow' #todo +// Logical Operators +// and Logical and Price le 200 and Price gt 3.5 +// or Logical or Price le 3.5 or Price gt 200 #todo +// not Logical negation not endswith(Description,'milk') #todo + +// eg. +// http://host/service/Products?$filter=Price lt 10.00 +// http://host/service/Categories?$filter=Products/$count lt 10 + +import functions from './functionsParser'; + +function parse($filter) { + // returns a valid monggose filter object + // odata functions are to be replaced + if (!$filter) { + return; + } + + const keys = Object.keys($filter); + + keys.forEach(name => { + if ($filter[name].$function) { + const func = { + ...functions[$filter[name].$function.$name](name, $filter[name].$function) + }; + + $filter[name] = func; + } + + // parsing rekursion + if(Array.isArray($filter[name])) { + $filter[name].forEach(subCondition => parse(subCondition)); + } + + if ($filter[name].eq === null) { + $filter[name].$exists = false; + delete $filter[name].eq; + } + + if ($filter[name].ne === null) { + $filter[name].$exists = true; + delete $filter[name].ne; + + } + + }); + + return $filter; + +}; + +export default ($filter, $odata) => { + let result = parse($filter); + + if ($odata.clientField) { + const clientCondition = { [$odata.clientField]: { $eq: $odata.client } }; + + result = result ? { $and: [ clientCondition, result ] } : clientCondition + } + + return result; +}; \ No newline at end of file diff --git a/src/mongo/parser/functionsParser.js b/src/mongo/parser/functionsParser.js new file mode 100644 index 0000000..2c9710a --- /dev/null +++ b/src/mongo/parser/functionsParser.js @@ -0,0 +1,85 @@ +const convertToOperator = (odataOperator) => { + let operator; + switch (odataOperator) { + case 'eq': + operator = '=='; + break; + case 'ne': + operator = '!='; + break; + case 'gt': + operator = '>'; + break; + case 'ge': + operator = '>='; + break; + case 'lt': + operator = '<'; + break; + case 'le': + operator = '<='; + break; + default: + throw new Error('Invalid operator code, expected one of ["==", "!=", ">", ">=", "<", "<="].'); + } + return operator; +}; + +// contains(CompanyName,'icrosoft') +const contains = (name, $filter) => ({ + $where: `this.${name}.indexOf('${$filter.$parameter}') != -1` +}); + +// indexof(CompanyName,'X') eq 1 +const indexof = (name, $filter) => { + const { $parameter, $operator, $value } = $filter; + const operator = convertToOperator($operator); + + return { + $where: `this.${name}.indexOf('${$parameter}') ${operator} ${$value}` + }; +}; + +// year(publish_date) eq 2000 +const year = (name, $filter) => { + const result = {}; + const { $value, $operator } = $filter; + + const start = new Date(+$value, 0, 1); + const end = new Date(+$value + 1, 0, 1); + + switch ($operator) { + case 'eq': + result.$gte = start; + result.$lt = end; + break; + case 'ne': { + result = { + $or: [{ + $lt: start + }, { + $gte: end + }] + } ; + break; + } + case 'gt': + result.$gte = end; + break; + case 'ge': + result.$gte = start; + break; + case 'lt': + result.$lt = start; + break; + case 'le': + result.$lt = end; + break; + default: + throw new Error('Invalid operator code, expected one of ["==", "!=", ">", ">=", "<", "<="].'); + } + + return result; +}; + +export default { indexof, year, contains }; diff --git a/src/parser/orderbyParser.js b/src/mongo/parser/orderbyParser.js similarity index 100% rename from src/parser/orderbyParser.js rename to src/mongo/parser/orderbyParser.js diff --git a/src/mongo/parser/selectParser.js b/src/mongo/parser/selectParser.js new file mode 100644 index 0000000..58c7742 --- /dev/null +++ b/src/mongo/parser/selectParser.js @@ -0,0 +1,19 @@ +export default (query, $select) => new Promise((resolve) => { + if (!$select?.length) { + resolve(); + return; + } + + const list = $select; + + const selectFields = { _id: 0 }; + list.forEach(item => selectFields[item] = 1 ); + + if (Object.keys(selectFields).length === 1 && selectFields._id === 0) { + resolve(); + return; + } + + query.select(selectFields); + resolve(); +}); diff --git a/src/mongo/parser/skipParser.js b/src/mongo/parser/skipParser.js new file mode 100644 index 0000000..d2ac25a --- /dev/null +++ b/src/mongo/parser/skipParser.js @@ -0,0 +1,9 @@ +// ?$skip=10 +// -> +// query.skip(10) +export default (query, skip) => new Promise((resolve) => { + if (skip > 0) { + query.skip(skip); + } + resolve(); +}); diff --git a/src/mongo/parser/topParser.js b/src/mongo/parser/topParser.js new file mode 100644 index 0000000..01edcd3 --- /dev/null +++ b/src/mongo/parser/topParser.js @@ -0,0 +1,9 @@ +// ?$top=10 +// -> +// query.top(10) +export default (query, top) => new Promise((resolve) => { + if (top > 0) { + query.limit(top); + } + resolve(); +}); diff --git a/src/mongo/rest/count.js b/src/mongo/rest/count.js new file mode 100644 index 0000000..dc2d677 --- /dev/null +++ b/src/mongo/rest/count.js @@ -0,0 +1,18 @@ +export default async (req, res, next) => { + try { + const filter = req.$odata.clientField && req.$odata.client ? { // special client filter + [req.$odata.clientField]: req.$odata.client + } : undefined; + const query = req.$odata.Model.find(filter); + const count = await query.count(); + + res.$odata.result = count.toString(); + res.$odata.supportedMimetypes = ['text/plain']; + + next(); + + } catch(err) { + next(err); + } + +}; diff --git a/src/mongo/rest/delete.js b/src/mongo/rest/delete.js new file mode 100644 index 0000000..289c196 --- /dev/null +++ b/src/mongo/rest/delete.js @@ -0,0 +1,34 @@ +export default async (req, res, next) => { + try { + if (req.$odata.clientField) { + const entity = await req.$odata.Model.findById(req.$odata.$Key._id); + + if (!entity || entity[req.$odata.clientField] !== req.$odata.client) { + const error = new Error('Not Found'); + + error.status = 404; + throw error; + } + + await entity.deleteOne(); + + } else { + const result = await req.$odata.Model.deleteOne({ _id: req.$odata.$Key._id }); + + if (JSON.parse(result).n === 0) { + const error = new Error('Not Found'); + + error.status = 404; + throw error; + } + + } + + res.$odata.status = 204; + next(); + + } catch(err) { + next(err); + } + +}; diff --git a/src/mongo/rest/get.js b/src/mongo/rest/get.js new file mode 100644 index 0000000..3809f16 --- /dev/null +++ b/src/mongo/rest/get.js @@ -0,0 +1,28 @@ +function throwNotFound() { + const result = new Error('Not Found'); + + result.status = 404; + throw result; +} +export default async (req, res, next) => { + try { + let entity = await req.$odata.Model.findById(req.$odata.$Key._id); + + if (!entity) { + throwNotFound(); + } + + entity = entity.toObject(); + + if (req.$odata.clientField && entity[req.$odata.clientField] !== req.$odata.client) { // client check + throwNotFound(); + } + + res.$odata.result = entity; + next(); + + } catch (err) { + next(err); + } + +}; diff --git a/src/mongo/rest/getSingleton.js b/src/mongo/rest/getSingleton.js new file mode 100644 index 0000000..19c0511 --- /dev/null +++ b/src/mongo/rest/getSingleton.js @@ -0,0 +1,41 @@ +import selectParser from "../parser/selectParser"; + +export default async (req, res, next) => { + try { + const param = req.$odata.clientField ? { [req.$odata.clientField]: req.$odata.client } : undefined; + const query = req.$odata.Model.findOne(param); + + await selectParser(query, req.$odata.$select); + + let entity = await query.exec(); + let transient = false; + + if (!entity) { + // return default properties of singleton + entity = new req.$odata.Model(); + transient = true; + } + + res.$odata.result = entity.toObject(); + if (transient) { + res.$odata.result._id = null; + if (req.$odata.clientField) { + res.$odata.result[req.$odata.clientField] = req.$odata.client; + } + } + + if (req.$odata.$select) { + Object.keys(res.$odata.result) + .forEach(item => { + if (req.$odata.$select.indexOf(item) === -1) { + delete res.$odata.result[item]; + } + }); + } + next(); + + } catch(err) { + next(err); + } + +}; diff --git a/src/mongo/rest/list.js b/src/mongo/rest/list.js new file mode 100644 index 0000000..8dd4291 --- /dev/null +++ b/src/mongo/rest/list.js @@ -0,0 +1,36 @@ +import filterParser from '../parser/filterParser'; +import skipParser from '../parser/skipParser'; +import topParser from '../parser/topParser'; +import selectParser from '../parser/selectParser'; + +export default async (req, res, next) => { + + try { + // TODO expand: req.$odata.$expand, + // TODO search: req.$odata.$search, + const filter = filterParser(req.$odata.$filter, req.$odata); + const query = req.$odata.Model.find(filter); + + if (req.$odata.$orderby) { + query.sort(req.$odata.$orderby); + } + + await skipParser(query, req.$odata.$skip); + await topParser(query, req.$odata.$top); + await selectParser(query, req.$odata.$select); + + const data = await query.exec(); + const result = { value: data.map(item => item.toObject()) }; + + res.$odata.result = { + ...res.$odata.result, + ...result + }; + + next(); + + } catch (err) { + next(err); + } + +}; diff --git a/src/mongo/rest/patch.js b/src/mongo/rest/patch.js new file mode 100644 index 0000000..2545236 --- /dev/null +++ b/src/mongo/rest/patch.js @@ -0,0 +1,35 @@ +import applyClient from "../applyClient"; + +export default async (req, res, next) => { + try { + const entity = (await req.$odata.Model.findById(req.$odata.$Key._id)).toObject(); + + if (req.$odata.clientField) { + if (entity[req.$odata.clientField] !== req.$odata.client) { + const error1 = new Error('Not found'); + + error1.status = 404; + throw error1; + } + + const bodyClient = req.$odata.body[req.$odata.clientField]; + if (bodyClient && bodyClient !== req.$odata.client) { + const error2 = new Error('Client value in custom parameter differs from client value in body'); + + error2.status = 400; + throw error2; + } + } + + const patched = { ...entity, ...req.$odata.body }; + + applyClient(req, patched); + + await req.$odata.Model.updateOne({ _id: req.$odata.$Key._id }, patched); + res.$odata.result = patched; + next(); + + } catch (err) { + next(err); + } +} \ No newline at end of file diff --git a/src/mongo/rest/patchSingleton.js b/src/mongo/rest/patchSingleton.js new file mode 100644 index 0000000..39e4a62 --- /dev/null +++ b/src/mongo/rest/patchSingleton.js @@ -0,0 +1,47 @@ +import applyClient from "../applyClient"; + +export default async (req, res, next) => { + try { + const filter = req.$odata.clientField ? { [req.$odata.clientField]: req.$odata.client } : undefined; + let entity = await req.$odata.Model.findOne(filter); + + if (req.$odata.clientField) { + const bodyClient = req.$odata.body[req.$odata.clientField]; + + if (bodyClient && bodyClient !== req.$odata.client) { + const error = new Error('Client value in custom parameter differs from client value in body'); + + error.status = 400; + throw error; + } + } + + if (entity) { + const patched = { ...entity.toObject(), ...req.$odata.body }; + + applyClient(req, patched); + + await req.$odata.Model.updateOne({ _id: entity._id }, patched); + res.$odata.result = patched; + + } else { + entity = new req.$odata.Model(); + + Object.keys(req.$odata.body).forEach(property => + entity[property] = req.$odata.body[property] + ); + applyClient(req, entity); + + await entity.save({ + validateBeforeSave: true, + validateModifiedOnly: true + }); + res.$odata.result = entity.toObject(); + + } + next(); + + } catch (err) { + next(err); + } +} \ No newline at end of file diff --git a/src/mongo/rest/post.js b/src/mongo/rest/post.js new file mode 100644 index 0000000..133e02b --- /dev/null +++ b/src/mongo/rest/post.js @@ -0,0 +1,39 @@ +import applyClient from "../applyClient"; + +export default async (req, res, next) => { + try { + if (!Object.keys(req.body).length) { + const error = new Error(); + + error.status = 422; + throw error; + + } + if (req.$odata.clientField) { + const bodyField = req.body[req.$odata.clientField]; + + if (bodyField && bodyField !== req.$odata.client) { + const error = new Error('Client value in custom parameter differs from client value in body'); + + error.status = 400; + throw error; + } + + } + + const entity = new req.$odata.Model(req.body); + + applyClient(req, entity); + + await entity.save({ + validateBeforeSave: true, + validateModifiedOnly: true + }); + res.$odata.result = entity.toObject(); + res.$odata.status = 201; + next(); + + } catch (err) { + next(err); + } +}; diff --git a/src/mongo/rest/put.js b/src/mongo/rest/put.js new file mode 100644 index 0000000..9950fb0 --- /dev/null +++ b/src/mongo/rest/put.js @@ -0,0 +1,60 @@ +import applyClient from "../applyClient"; + +export default async (req, res, next) => { + try { + const entity = await req.$odata.Model.findOne({ _id: req.$odata.$Key._id }); + + if (req.$odata.clientField) { + if (entity && entity.client !== req.$odata.client) { + const error1 = new Error('Not found'); + + error1.status = 404; + throw error1; + } + + const bodyClient = req.$odata.body[req.$odata.clientField]; + + if (bodyClient && bodyClient !== req.$odata.client) { + const error2 = new Error('Client value in custom parameter differs from client value in body'); + + error2.status = 400; + throw error2; + } + } + + if (entity) { + const newEntity = req.$odata.body; + + applyClient(req, newEntity); + await req.$odata.Model.findByIdAndUpdate(entity._id, req.$odata.body); + + newEntity._id = entity._id; + res.$odata.result = newEntity; + + } else { + const uuidReg = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; + + if (!uuidReg.test(req.$odata.$Key._id)) { + const err = new Error('Id is invalid.'); + + err.status = 400; + return next(err); + } + const newEntity = new req.$odata.Model(req.$odata.body); + + newEntity._id = req.$odata.$Key._id; + await newEntity.save({ + validateBeforeSave: true, + validateModifiedOnly: true + }); + + res.$odata.result = newEntity.toObject(); + res.$odata.status = 201; + } + + next(); + + } catch (err) { + next(err); + } +}; diff --git a/src/odata/Action.js b/src/odata/Action.js new file mode 100644 index 0000000..8d4e2a1 --- /dev/null +++ b/src/odata/Action.js @@ -0,0 +1,238 @@ +import { Router } from 'express'; +import Hooks from './Hooks'; +import { validateParameters, validateIdentifier } from './validator'; +import parseValue from './parser/value'; + +export default class Action { + constructor(name, fn, annotations, options) { + + this.name = name; + this.fn = async (req, res, next) => { + try { + res.$odata.status = 200; + + const result = fn(req, res, next); + + if (result || res.$odata.status === 204) { + if (result?.then) { + await result; + } + + next(); + } + + } catch (error) { + next(error); + } + } + this.hooks = new Hooks(); + + if (options) { + Object.keys(options).forEach(name => { + if (['binding', 'resource', '$Parameter'].indexOf(name) === -1) { + throw new Error(`Option '${name}' is not supported`); + } + }); + } + + this.binding = options?.binding; + this.resource = options?.resource; + this.$Parameter = options?.$Parameter || []; + this.annotations = annotations; + + if (this.binding === 'entity') { + this.addBefore(this.resource.getNavigation().beforeHooks); + } + + this.addBefore(this.parseParameter.bind(this)); + } + + annotate(anno, value) { + if (!anno) { + throw new Error('Name of annotation term should be given'); + } + + const term = `@${anno}`; + const list = this.annotations.items[anno]; + + this.getMetadata(); + + if (list?.item?.indexOf('parameter') >= 0) { + if (!Array.isArray(value) || !value.length) { + throw new Error('List of parameter names was expected'); + } + + value.forEach(param => { + if (!this.metadata.$Parameter.find(item => item.$Name === param)) { + throw new Error(`Unknown parameter with name '${param}'`); + } + }); + } + + this.metadata[term] = this.annotations.annotate(anno, 'Action', value)[term]; + } + + annotateParameter(name, anno, value) { + if (!name) { + throw new Error('Parameter name should be given'); + } + if (!anno) { + throw new Error('Name of annotation term should be given'); + } + const term = `@${anno}`; + + this.getMetadata(); + + const param = this.metadata.$Parameter.find(item => item.$Name === name); + + if (!param) { + throw new Error(`Entity '${this.name}' doesn't have parameter named '${name}'`); + } + + if (param[term]) { + throw new Error(`Parameter '${name}' is allready annotated with term '${anno}'`); + } + + param[term] = this.annotations.annotate(anno, 'Parameter', value)[term]; + } + + addBefore(fn, name) { + this.hooks.addBefore(fn, name); + } + + addAfter(fn, name) { + this.hooks.addAfter(fn, name); + } + + match(method, url) { + const regex = this.getPath(true); + + if (method === 'post' && url.match(regex)) { + return this.getMiddlewares(); + } + } + + getRouter() { + if (!this.router) { + const path = this.getPath(); + + this.router = Router(); + this.router.post(path, ...this.getMiddlewares()); + } + + return this.router; + } + + getMetadata() { + if (!this.metadata) { + const result = { + $Kind: 'Action' + }; + + if (this.binding) { + result.$IsBound = true; + result.$Parameter = [{ + $Name: this.resource.name, + $Type: `node.odata.${this.resource.name}`, + $Collection: this.binding === 'collection' ? true : undefined, + }]; + } + + if (this.$Parameter.length) { + if (!result.$Parameter) { + result.$Parameter = []; + } + + this.$Parameter.forEach(para => { + const item = para; + + if (para.$Type.search(/^edm/i) === -1) { + item.$Type = `${para.$Type}`; + } + + result.$Parameter.push(item); + }); + result.$Parameter = result.$Parameter ? result.$Parameter.concat() : this.$Parameter; + } + + this.metadata = result; + } + + return this.metadata; + } + + getPath(asRegex) { + let path; + + switch (this.binding) { + case 'entity': + if (!this.resource) { + throw new Error(`Binding '${this.binding}' require a resource`) + } + path = asRegex ? new RegExp(`\/?${this.resource.name}\\('?[A-Fa-f0-9]*'?\\)\/${this.name}$`) : `${this.resource.getNavigation().url}/${this.name}`; + break; + case 'collection': + if (!this.resource) { + throw new Error(`Binding '${this.binding}' require a resource`) + } + path = asRegex ? new RegExp(`\/?${this.resource.name}\/${this.name}$`) : `/${this.resource.name}/${this.name}`; + break; + default: + if (this.binding) { + throw new Error(`Invalid binding '${this.binding}'`); + } else { + if (this.resource) { + throw new Error(`Use of the unbound action '${this.name}' by a resource '${this.resource.name}' is not intended`) + } + path = asRegex ? new RegExp(`(node\.odata)?\/?${this.name}$`) : `/node.odata.${this.name}`; + } + break; + } + return path; + } + + getMiddlewares() { + if (!this.midddlewares) { + validateIdentifier(this.name); + + if (this.$Parameter.length) { + validateParameters(this.$Parameter); + } + + this.midddlewares = [...this.hooks.before, this.fn, ...this.hooks.after]; + } + + return this.midddlewares; + } + + parseParameter(req, res, next) { + try { + if (req.body) { + req.$odata.$Parameter = {}; + } + + this.$Parameter.forEach(param => { + if (req.body && req.body[param.$Name]) { + if (param.$Type.indexOf('node.odata') === -1) { + req.$odata.$Parameter[param.$Name] = parseValue(req.body[param.$Name], param); + } else { + req.$odata.$Parameter[param.$Name] = req.body[param.$Name]; + } + + } else if (!param.$Nullable && (!req.body || !req.body[param.$Name])) { + const error = new Error(`Obligatory parameter '${param.$Name}' not given`); + + error.status = 400; + + throw error; + } + }); + + next(); + + } catch (err) { + next(err); + } + } + +} \ No newline at end of file diff --git a/src/odata/Batch.js b/src/odata/Batch.js new file mode 100644 index 0000000..4839a8b --- /dev/null +++ b/src/odata/Batch.js @@ -0,0 +1,235 @@ +import { Router } from 'express'; +import error from '../middlewares/error'; +import { STATUS_CODES } from 'http'; + +export default class Batch { + constructor(server) { + this._server = server; + this._url = '/\\$batch'; + } + + post() { + return this; + } + + middleware = async (req, res, next) => { + try { + res.$odata.result = await this.ctrl(req, res, error => { + if (error instanceof Error) { + throw error; + } + }); + res.$odata.supportedMimetypes = ['multipart/mixed', 'application/json']; + res.$odata.status = 200; + + next(); + + } catch (err) { + next(err); + } + }; + + match(method, url) { + if (method === 'post' + && url === url.indexOf(this._url.replace(/\\/g, '') === 0)) { + return this.middleware; + } + return undefined; + } + + _router() { + /*eslint-disable */ + const router = Router(); + /* eslint-enable */ + router.post(this._url, this.middleware); + + return router; + } + + static mapToQuery(url) { + const match = url.match(/\?([^#]+)/); + + if (!match || !match.length) { + return {}; + } + + const queryString = match[1]; + const parameters = queryString.split('&').map((parameter) => { + const keyValue = parameter.split('='); + const result = { + key: decodeURIComponent(keyValue[0]), + }; + + if (keyValue.length > 1) { + result.value = decodeURIComponent(keyValue[1]); + } + return result; + }); + + return parameters.filter((parameter) => parameter.value) + .reduce((previous, current) => { + const result = { + ...previous, + }; + + result[current.key] = current.value; + + return result; + }, {}); + } + + async executeSingleRequest(handler, req, res) { + try { + let promise = null; + + for (let i = 0; i < this._server.hooks.before.length; ++i) { + const hook = this._server.hooks.before[i]; + + if (promise) { + promise = promise.then(() => { + return hook(req, res, err => { + if (err) { + throw err; + } + }); + }); + } else { + promise = hook(req, res, err => { + if (err) { + throw err; + } + }); + } + + } + + for (let i = 0; i < handler.length; ++i) { + const handlerOrHook = handler[i]; + + if (promise) { + promise = promise.then(() => { + return handlerOrHook(req, res, err => { + if (err) { + throw err; + } + }); + }); + } else { + promise = handlerOrHook(req, res, err => { + if (err) { + throw err; + } + }); + } + } + + for(let i = 0; i < this._server.hooks.after.length; ++i) { + const hook = this._server.hooks.after[i]; + + if (hook !== error) { + if (promise) { + promise = promise.then(() => { + return hook(req, res, err => { + if (err) { + throw err; + } + }); + }); + } else { + promise = hook(req, res, err => { + if (err) { + throw err; + } + }); + } + } + } + + await promise; + + } catch (err) { + error(err, req, res); + } + } + + async ctrl(req, res, next) { + const responses = req.body.requests.map(async function (request) { + const handler = Object.keys(this._server.resources) + .map((name) => this._server.resources[name].match(request.method, request.url)) + .concat(Object.keys(this._server.actions) + .map(name => this._server.actions[name].match(request.method, request.url))) + .find((ctrl) => ctrl); + let result = { + }; + if (request.id) { + result.id = request.id; + } + const currentRequest = { + headers: request.headers || {}, + method: request.method, + query: Batch.mapToQuery(request.url), + body: request.body, + $odata: res.$odata + }; + + const paramsMatch = request.url.match(/^\/?[^#?(]+\('(\w+)'\)/); + + if (paramsMatch && paramsMatch.length > 1) { + currentRequest.params = { + id: paramsMatch[1], + }; + } + + if (!handler) { + result.status = 404; + result.statusText = STATUS_CODES[404]; + result.body = STATUS_CODES[404]; + } else { + function appendHeader(name, value) { + if (!result.headers) { + result.headers = { + 'OData-Version': '4.0' + }; + } + result.headers[name] = value; + } + + function jsonp(body) { + result.body = body; + appendHeader('content-type', 'application/json'); + }; + + const currentResponse = { + end: (message) => { throw new Error(message); }, + type: (mimetype) => { + appendHeader('content-type', mimetype); + }, + setHeader: appendHeader, + jsonp, + status: (status) => { + result.status = status; + result.statusText = STATUS_CODES[status]; + + return { + jsonp, + end: () => { }, + send: (body) => { + result.body = body; + } + }; + } + }; + + await this.executeSingleRequest(handler, currentRequest, currentResponse); + + } + return result; + }.bind(this)); + + return Promise.all(responses).then((results) => { + return { + responses: results + }; + }); + } +} diff --git a/src/odata/Hooks.js b/src/odata/Hooks.js new file mode 100644 index 0000000..fa22c3b --- /dev/null +++ b/src/odata/Hooks.js @@ -0,0 +1,67 @@ +export default class Hooks { + constructor() { + this.before = []; + this.after = []; + } + + addBefore(fn, name) { + if (!fn) { + throw new Error(`Parameter 'fn' should be given`); + } + + if (Array.isArray(fn)) { + this.before = this.before.concat(fn.map(item => this.suppressNext(item, name))); + + } else { + this.before.push(this.suppressNext(fn, name)); + } + } + + suppressNext(fn, name, isFinal) { + return async (req, res, next) => { + try { + const combine = new Promise(async (resolve, reject) => { + try { + const prom = fn(req, res, err => { + if (err) { + reject(err); + } + resolve(); + }); + + if (prom && prom.then) { + await prom; + resolve(); + } else if (isFinal) { + resolve(); + } + + } catch (err) { + reject(err); + } + }); + + await combine; + if (!isFinal) { + next(); + } + + } catch (err) { + next(err); + } + }; + } + + addAfter(fn, name, isFinal) { + if (!fn) { + throw new Error(`Parameter 'fn' should be given`); + } + + if (Array.isArray(fn)) { + this.after = fn.map(item => this.suppressNext(item, name, isFinal)).concat(this.after); + } else { + this.after.unshift(this.suppressNext(fn, name, isFinal)); + } + } + +} \ No newline at end of file diff --git a/src/odata/Metadata.js b/src/odata/Metadata.js new file mode 100644 index 0000000..6fac6c7 --- /dev/null +++ b/src/odata/Metadata.js @@ -0,0 +1,172 @@ +import { Router } from 'express'; +import Entity from './entity/Entity'; +import Function from '../ODataFunction'; +import { validate, validateIdentifier } from './validator'; +import Singleton from './entity/Singleton'; + +export default class Metadata { + constructor(server) { + this._server = server; + this._path = '/\\$metadata'; + + this.complexTypes = {}; + } + + match(method, url) { + if (method === 'get' + && url.indexOf(this._path.replace(/\\/g, '')) === 0) { + return this.middleware; + } + return undefined; + } + + middleware = async (req, res, next) => { + try { + res.$odata.result = await this.ctrl(req); + res.$odata.status = 200; + res.$odata.supportedMimetypes = ['application/xml', 'application/json']; + next(); + + } catch (err) { + next(err); + } + } + + _router() { + /*eslint-disable */ + const router = Router(); + /* eslint-enable */ + router.get(this._path, this.middleware.bind(this)); + + return router; + } + + static visitFunction(node) { + return { + $Kind: 'Function', + ...node.params, + }; + } + + visitor(type, node, model) { + return Metadata.visitFunction(node); + } + + complexType(name, properties) { + if (this.complexTypes[name]) { + throw new Error(`Complex type with name ${name} allready exists`); + } + + if (!properties) { // get call + const returnType = name.replace('node.odata.', ''); + + if (!this.complexTypes[returnType]) { + throw new Error(`Complex type with name ${name} does not exists`); + } + + return this.complexTypes[returnType]; + } + + validateIdentifier(name); + + const typeObject = { + $Kind: 'ComplexType', + ...properties + }; + validate(typeObject); + + this.complexTypes[name] = typeObject; + + return this.complexTypes[name]; + } + + ctrl() { + const entityTypeNames = Object.keys(this._server.resources); + const entityTypes = entityTypeNames.reduce((previousResource, currentResource) => { + const resource = this._server.resources[currentResource]; + const result = { ...previousResource }; + + if (resource instanceof Entity) { + result[currentResource] = resource.getMetadata(); + const actions = Object.keys(resource.actions); + if (actions && actions.length) { + actions.forEach((action) => { + result[action] = resource.actions[action].getMetadata(); + }); + } + + } if (resource instanceof Singleton && resource.name === resource.entity.name) { + result[currentResource] = resource.getMetadata(); + + } else if (resource instanceof Function) { + result[currentResource] = this.visitor('Function', resource); + } + + return result; + }, {}); + + const entitySetNames = Object.keys(this._server.resources); + const entitySets = entitySetNames.reduce((previousResource, currentResource) => { + const result = { ...previousResource }; + const resource = this._server.resources[currentResource]; + + if (resource instanceof Entity) { + result[currentResource] = { + $Type: `node.odata.${currentResource}`, + $Collection: true + }; + + } else if (resource instanceof Singleton) { + const singletonType = resource.name === resource.entity.name ? currentResource : resource.entity.name; + + result[currentResource] = { + $Type: `node.odata.${singletonType}` + }; + + } else if (resource instanceof Function) { + result[currentResource] = { + $Function: `node.odata.${currentResource}`, + }; + } + + return result; + }, {}); + + const actionNames = Object.keys(this._server.actions); + const actionImports = actionNames.reduce((previousAction, currentAction) => { + const result = { ...previousAction }; + + result[`${currentAction}-import`] = { + $Action: `node.odata.${currentAction}` + }; + + return result; + }, {}) + const unboundActions = actionNames.reduce((previousAction, currentAction) => { + const result = { ...previousAction }; + const action = this._server.actions[currentAction]; + + result[currentAction] = action.getMetadata(); + + return result; + }, {}) + + const document = { + $Version: '4.0', + ...this._server.annotations.getMetadata(), + ...this.complexTypes, + ...entityTypes, + ...unboundActions, + $EntityContainer: 'node.odata', + ['node.odata']: { // eslint-disable-line no-useless-computed-key + $Kind: 'EntityContainer', + ...entitySets, + ...actionImports + } + }; + + return new Promise((resolve) => { + resolve(document); + }); + } +} diff --git a/src/odata/ServiceDocument.js b/src/odata/ServiceDocument.js new file mode 100644 index 0000000..5b5647f --- /dev/null +++ b/src/odata/ServiceDocument.js @@ -0,0 +1,65 @@ +import { Router } from 'express'; +import Entity from './entity/Entity'; +import Singleton from './entity/Singleton'; + +export default class Metadata { + constructor(server) { + this._server = server; + this._path = '/'; + } + + get() { + return this; + } + + match(methods, url) { + if (methods === 'get' + && url.indexOf(this._path) === 0) { + return this.middleware; + } + return undefined; + } + + middleware = async (req, res, next) => { + try { + res.$odata.result = await this.ctrl(req); + res.$odata.status = 200; + + next(); + + } catch (err) { + next(err); + } + }; + + _router() { + /*eslint-disable */ + const router = Router(); + /* eslint-enable */ + router.get(this._path, this.middleware); + + return router; + } + + ctrl(req) { + const entityTypeNames = Object.keys(this._server.resources); + const entitySets = entityTypeNames + .filter((item) => + this._server.resources[item] instanceof Entity + || this._server.resources[item] instanceof Singleton ) + .map((item) => ({ + name: item, + kind: this._server.resources[item] instanceof Singleton ? 'Singleton' : 'EntitySet', + url: item, + })); + + const document = { + '@context': `${req.protocol}://${req.get('host')}${this._server.get('prefix')}/$metadata`, + value: entitySets, + }; + + return new Promise((resolve) => { + resolve(document); + }); + } +} diff --git a/src/odata/Vocabulary.js b/src/odata/Vocabulary.js new file mode 100644 index 0000000..1207e59 --- /dev/null +++ b/src/odata/Vocabulary.js @@ -0,0 +1,122 @@ +export default class Vocabulary { + constructor() { + this.terms = {}; + this.enumerations = {}; + this.items = {}; + } + + getMetadata() { + const result = {}; + const names = Object.keys(this.terms) + .forEach(name => { + result[name] = { + $Kind: 'Term', + ...this.terms[name] + } + }); + + return result; + } + + isDefined(name) { + return this.terms[name] ? true : false; + } + + define(name, prototype, scope) { + if (this.terms[name]) { + throw new Error(`Annotation with name '${name}' is allready defined`); + } + + const isEnum = Array.isArray(prototype); + + if (isEnum) { + if (!prototype.length) { + throw new Error('For enumeration array at least one item is required'); + } + this.enumerations[name] = prototype; + } + + const type = isEnum ? this.getTypeOf(prototype[0]) : this.getType(prototype); + const supportedTargets = [ 'Action', 'Action Import', 'Complex Type', 'Entity Container', + 'Entity Set', 'Entity Type', 'Enumeration Type', 'Enumeration Type Member', 'Function', + 'Function Import', 'Navigation Property', 'Parameter', 'Property', 'Return Type', + 'Singleton', 'Type Definition' ]; + + if (scope && scope.length) { + scope.forEach(target => { + if (supportedTargets.indexOf(target) === -1) { + throw new Error(`Target '${target}' is not supported`); + } + }); + } + + this.terms[name] = { + $AppliesTo: scope && scope.length ? scope : supportedTargets + }; + + if (type) { + this.terms[name].$Type = type; + } + + if (prototype.item) { + this.terms[name].$Collection = true; + this.items[name] = prototype.item; + } + } + + annotate(name, destination, value) { + const anno = this.terms[name]; + const enumeration = this.enumerations[name]; + + if (!anno) { + throw new Error(`Annotation with name '${name}' is not defined`); + } + + const currentType = this.getTypeOf(value); + if (currentType !== anno.$Type) { + throw new Error(`Annotation '${name}' requires type '${anno.$Type}'. Given '${currentType}'`); + } + + if (!destination) { + throw new Error(`Parameter 'destination' should be given`); + } + + if (anno.$AppliesTo.indexOf(destination) === -1) { + throw new Error(`Annotation '${name}' can not assigned to '${destination}'`); + } + + if (enumeration && enumeration.indexOf(value) === -1) { + throw new Error(`Annotation value '${value}' can not be used as '${name}'`); + } + + return { + [`@${name}`]: value + } + } + + getTypeOf(value) { + const type = Array.isArray(value) && value.length > 0 ? typeof value[0] : typeof value; + + return this.getType(type); + } + + getType(prototype) { + if (prototype.item) { + return this.getType(prototype.type); + } + + switch (prototype) { + case 'number': + return 'Edm.Double'; + + case 'string': + return undefined; //Edm.String is default + + case 'boolean': + return 'Edm.Boolean'; + + default: + throw Error(`Type '${prototype}' is not supported`); + } + } +} \ No newline at end of file diff --git a/src/odata/entity/Entity.js b/src/odata/entity/Entity.js new file mode 100644 index 0000000..95860d1 --- /dev/null +++ b/src/odata/entity/Entity.js @@ -0,0 +1,466 @@ +import { validateIdentifier, validate } from "../validator"; +import { Router } from 'express'; +import Hooks from "../Hooks"; +import Action from '../Action'; +import parseSelect from './parser/select'; +import parseKeys from './parser/keys'; +import parseCount from './parser/count'; +import parseFilter from './parser/filter'; +import parseOrderBy from "./parser/orderby"; +import parseClient from './parser/client'; +import { parseSkip, parseTop } from "./parser/skiptop"; + +export default class Entity { + + get mapping() { + return this._mapping; + } + + set mapping(value) { + // update types of properties + Object.keys(value).forEach(name => { + //TODO: validation + if (this.metadata[name]?.$Type != value[name]?.attributes?.$Type) { + this.metadata[name].$Type = value[name].attributes.$Type; + } + }); + + this._mapping = value; + } + + get clientField() { + return this._clientField; + } + + set clientField(value) { + if (!this.metadata[value]) { + throw new Error(`Entity '${this.name}' does'nt have property named '${value}'`); + } + this._clientField = value; + } + + constructor(name, handler, metadata, settings, annotations) { + const notImplemented = op => (req, res) => { + const error = new Error(`Operation '${op}' is not implemented'`); + + error.status = 501; + throw error; + }; + + this.name = name; + this.handler = { + list: notImplemented('list'), + get: notImplemented('get'), + post: notImplemented('post'), + put: notImplemented('put'), + delete: notImplemented('delete'), + patch: notImplemented('patch'), + count: notImplemented('count'), + ...handler + }; + this.metadata = { + $Kind: 'EntityType', + ...metadata + }; + + this.actions = {}; + this.hooks = new Hooks(); + + this.options = { + ...settings + }; + + this.annotations = annotations; + this._mapping = {}; + } + + addBefore(fn, name) { + this.hooks.addBefore(fn, name); + } + + addAfter(fn, name) { + this.hooks.addAfter(fn, name); + } + + action(name, fn, options) { + this.actions[name] = new Action(name, fn, this.annotations, + { + ...options, + resource: this + }); + + return this.actions[name]; + } + + match(method, url) { + validateIdentifier(this.name); + + const action = Object.keys(this.actions) + .map(name => this.actions[name].match(method, url)) + .find(ctrl => ctrl); + if (action) { + return action + } + + const routes = this.getRoutes(); + const route = routes.find((item) => { + if (item.method === method) { + const match = url.match(item.regex); + + return match; + } + }); + + return route && [ + this.parsingMiddleware.bind(this), + ...this.hooks.before, + this.ctrl(route.name, this.handler[route.name]), + ...this.hooks.after, + this.adaptResultAccordingMetadata.bind(this) + ]; + + + } + + // convert DattimeOffset to valid value + adaptResultAccordingMetadata(req, res, next) { + if (res.$odata.result?.value && Array.isArray(res.$odata.result?.value)) { + // list of entities + res.$odata.result.value.forEach(entity => this.adaptEntityAccordingMetadata(entity, req, res)); + } else if (res.$odata.result) { + this.adaptEntityAccordingMetadata(res.$odata.result, req, res); + } + next(); + } + + get(key) { + if (value) { + if (Number.isNaN(+value) || +value < 0) { + throw new Error(`Max-Skip value should be a positive number`); + } + this.options.maxSkip = value; + } + + return this.options[key]; + } + + set(key, value) { + const positiveOnly = value => { + if (value && (Number.isNaN(+value) || +value < 0)) { + throw new Error(`'${key}' value should be a positive number`); + } + }; + + switch (key) { + case 'maxSkip': + case 'maxTop': + positiveOnly(value); + this.options[key] = value; + break; + } + + } + + parsingMiddleware(req, res, next) { + try { + req.$odata = { + ...req.$odata, + $Key: parseKeys(req, this.name, this.metadata, this.mapping), + $select: parseSelect(req, this.name, this.metadata, this.mapping), + $filter: parseFilter(req, this.name, this.metadata, this.mapping), + $count: parseCount(req, this.name, this.metadata), + $orderby: parseOrderBy(req, this.name, this.metadata, this.mapping, this.options.orderby), + $skip: parseSkip(req, this.options.maxSkip), + $top: parseTop(req, this.options.maxTop), + clientField: this.clientField, + client: parseClient(req, this.name, this.metadata, this.clientField), + body: req.body, + $expand: req.query.$expand, // TODO : implement expand + $search: req.query.$search // TODO : implement search + }; + + next(); + + } catch (err) { + next(err); + } + } + + getPropertyMetadata(member) { + const entityMetadata = this.getMetadata(); + const result = { + propertyMetadata: null, + mapping: null + } + + if (entityMetadata[member]) { + result.propertyMetadata = entityMetadata[member]; + + } else { + const keys = Object.keys(this.mapping); + result.mapping = keys.find(name => this.mapping[name].intern === member); + + if (result.mapping) { + result.propertyMetadata = this.mapping[result.mapping].attributes; + } + + } + + return result; + } + + adaptEntityAccordingMetadata(entity, req, res) { + const entityMetadata = this.getMetadata(); + const keys = Object.keys(entity); + + if (req.$odata.$count || res.$odata.status === 204) { + // no classic body + return; + } + + keys.forEach(member => { + const { propertyMetadata, mapping } = this.getPropertyMetadata(member); + + if (!entityMetadata[member]) { + if (mapping) { + entity[mapping] = entity[member]; + } + + delete entity[member]; // hide attributes not exposed in metadata + + } + + if (!propertyMetadata) { + return; + } + + if (propertyMetadata.$Type === "Edm.DateTimeOffset" + && Object.prototype.toString.call(entity[member]) === '[object Date]') { + entity[member] = entity[member].toISOString().replace(/\.[0-9]{3}/, '') + } + + }); + + const nullables = Object.keys(entityMetadata) + .filter(item => item != '$Key' && item != '$Kind' && !entity[item]); + + nullables.forEach(member => { + const { propertyMetadata } = this.getPropertyMetadata(member); + + if (req.$odata.$select && req.$odata.$select.indexOf(member) === -1) { + // explizit projection doesn't include current field + return; + } + + if (propertyMetadata.$Nullable && entity[member] === undefined) { + entity[member] = null; + } + }) + } + + getRouter() { + validateIdentifier(this.name); + validate(this.metadata); + + const actions = Object.keys(this.actions) + .map(name => this.actions[name].getRouter()); + + const router = Router(); + const routes = this.getRoutes(); + + routes.forEach((route) => { + const { + name, method, url + } = route; + const hooksAfter = name === 'count' ? [...this.hooks.after] : [ + this.adaptResultAccordingMetadata.bind(this), + ...this.hooks.after + ]; + + router[method](url, + this.parsingMiddleware.bind(this), + ...this.hooks.before, + this.ctrl(name, this.handler[name]), + ...hooksAfter); + }); + + return [actions, router]; + } + + getNavigation() { + return { + url: this.getResourceUrl(), + beforeHooks: [this.parsingMiddleware.bind(this)] + }; + } + + ctrl(name, handler) { + return async (req, res, next) => { + try { + res.$odata.status = 200; + + if (name === 'list' && req.$odata.$count) { + const countResponse = { + $odata: {} + }; + + this.handler.count(req, countResponse, async err => { + if (err) { + next(err); + return; + } + + res.$odata.result = { + ['@odata.count']: countResponse.$odata.result + }; + await handler(req, res, next); + }); + + } else { + await handler(req, res, next); + + } + + } catch (err) { + next(err); + } + }; + } + + getMetadata() { + return this.metadata; + } + + annotate(anno, value) { + if (!anno) { + throw new Error('Name of annotation term should be given'); + } + + const term = `@${anno}`; + const list = this.annotations.items[anno]; + + this.getMetadata(); + + if (list?.item?.indexOf('property') >= 0) { + if (!Array.isArray(value) || !value.length) { + throw new Error('List of property names was expected'); + } + + value.forEach(prop => { + if (!this.metadata[prop]) { + throw new Error(`Unknown property with name '${prop}'`); + } + }); + } + + this.metadata[term] = this.annotations.annotate(anno, 'Entity Type', value)[term]; + } + + annotateProperty(prop, anno, value) { + if (!prop) { + throw new Error('Property name should be given'); + } + if (!anno) { + throw new Error('Name of annotation term should be given'); + } + const term = `@${anno}`; + + if (!this.metadata[prop]) { + throw new Error(`Entity '${this.name}' doesn't have property named '${prop}'`); + } + + if (this.metadata[prop][term]) { + throw new Error(`property '${prop}' is allready annotated with term '${anno}'`); + } + + this.metadata[prop] = { + ...this.metadata[prop], + ...this.annotations.annotate(anno, 'Property', value) + }; + } + + getKeyParam(type, name) { + switch (type) { + case 'Edm.String': + return `%27:${name}%27`; + + default: + return `:${name}`; + } + } + + getResourceUrl(name) { + const entityName = name || this.name; + const resourceListURL = `/${entityName}`; + + if (this.metadata.$Key.length === 1) { + const value = this.getKeyParam(this.metadata[this.metadata.$Key[0]].$Type, this.metadata.$Key[0]); + + return `${resourceListURL}\\(${value}\\)`; + + } else { + let result = this.metadata.$Key.reduce((previous, current, index) => { + const key = this.metadata[current]; + const value = this.getKeyParam(this.metadata[current].$Type, current); + + return !index ? `${previous}${key}=${value}` : `${previous},${key}=${value}`; + }, `${resourceListURL}\\(`); + + return `${result}\\)`; + } + } + + getRoutes(name) { + const entityName = name || this.name; + const resourceListURL = `/${entityName}`; + const resourceListRegex = new RegExp(`(^\/?${entityName}[?#])|(^\/?${entityName}$)`); + const resourceURL = this.getResourceUrl(name); + const resourceRegex = new RegExp(`^\/?${entityName}\\([^)]+\\)`); + + return [ + { + name: 'post', + method: 'post', + url: resourceListURL, + regex: resourceListRegex + }, + { + name: 'put', + method: 'put', + url: resourceURL, + regex: resourceRegex + }, + { + name: 'patch', + method: 'patch', + url: resourceURL, + regex: resourceRegex + }, + { + name: 'delete', + method: 'delete', + url: resourceURL, + regex: resourceRegex + }, + { + name: 'get', + method: 'get', + url: resourceURL, + regex: resourceRegex + }, + { + name: 'count', + method: 'get', + url: resourceListURL + '/([\$])count', + regex: new RegExp(`(^\/?${entityName}\/\\$count[?]?)|(^\/?${entityName}\/\\$count$)`) + }, + { + name: 'list', + method: 'get', + url: resourceListURL, + regex: resourceListRegex + } + ]; + } + +} \ No newline at end of file diff --git a/src/odata/entity/Singleton.js b/src/odata/entity/Singleton.js new file mode 100644 index 0000000..4bdf0e5 --- /dev/null +++ b/src/odata/entity/Singleton.js @@ -0,0 +1,143 @@ +import Entity from "./Entity"; +import { validate, validateIdentifier } from "../validator"; +import Hooks from "../Hooks"; +import { Router } from 'express'; + +export default class Singleton { + constructor(name, handler, metadata, annotations) { + const notSupported = (req, res) => { + const error = new Error(); + + error.status = 405; + throw error; + }; + + this.name = name; + this._entity = metadata instanceof Entity ? metadata : new Entity(name, handler, metadata, null, annotations); + + this.handler = { + ...this.entity.handler, // get, post, put, delete, patch + list: notSupported, + count: notSupported, + ...handler + }; + + this.hooks = new Hooks(); + + } + + get entity () { + return this._entity; + } + + set entity(value) { + this._entity = value; + } + + get mapping() { + return this.entity.mapping; + } + + set mapping(value) { + this.entity.mapping = value; + } + + get clientField() { + return this.entity.clientField; + } + + set clientField(value) { + this.entity.clientField = value; + } + + addBefore(fn, name) { + this.hooks.addBefore(fn, name); + } + + addAfter(fn, name) { + this.hooks.addAfter(fn, name); + } + + getMetadata() { + return this.entity.getMetadata(); + } + + match(method, url) { + validateIdentifier(this.name); + + const routes = this.getRoutes() + const route = routes.find((item) => { + if (item.method === method) { + const match = url.match(item.regex); + + return match; + } + }); + + return route && [ + this.entity.parsingMiddleware.bind(this.entity), + ...this.hooks.before, + this.ctrl(route.name, this.handler[route.name]), + ...this.hooks.after, + this.entity.adaptResultAccordingMetadata.bind(this.entity) + ]; + + + } + + getRouter() { + validateIdentifier(this.name); + validate(this.entity.metadata); + + const router = Router(); + const routes = this.getRoutes(); + + routes.forEach((route) => { + const { + name, method, url + } = route; + + router[method](url, + this.entity.parsingMiddleware.bind(this.entity), + ...this.hooks.before, + this.ctrl(name, this.handler[name]), + this.entity.adaptResultAccordingMetadata.bind(this.entity), + ...this.hooks.after); + }); + + return [router]; + } + + ctrl(name, handler) { + return async (req, res, next) => { + try { + res.$odata.status = 200; + await handler(req, res, next); + + } catch(err) { + next(err); + } + }; + } + + getRoutes() { + const name = this.name === this.entity.name ? undefined : this.name; + const listRoute = this.entity.getRoutes(name).find(item => item.name === 'list'); + + return [ 'post', 'put', 'patch', 'delete', 'get'].map(item => ({ + name: item, + method: item, + url: listRoute.url, + regex: listRoute.regex + })); + } + + + annotate(anno, value) { + this.entity.annotate(anno, value); + } + + annotateProperty(prop, anno, value) { + this.entity.annotateProperty(prop, anno, value); + } +} \ No newline at end of file diff --git a/src/odata/entity/parser/client.js b/src/odata/entity/parser/client.js new file mode 100644 index 0000000..3d90c4f --- /dev/null +++ b/src/odata/entity/parser/client.js @@ -0,0 +1,14 @@ +import parseValue from '../../parser/value'; + +module.exports = function parseClient(req, name, metadata, target) { + if (req.query['sap-client']) { + return parseValue(req.query['sap-client'], metadata[target]); + + } else if (target) { + const err = new Error(`For entity '${name}' you must send a client value`); + + err.status = 400; + throw err; + + } +} \ No newline at end of file diff --git a/src/odata/entity/parser/count.js b/src/odata/entity/parser/count.js new file mode 100644 index 0000000..cdc2d52 --- /dev/null +++ b/src/odata/entity/parser/count.js @@ -0,0 +1,15 @@ +export default function(req, entity, metadata) { + switch (req.query.$count) { + case 'true': + return true; + + case 'false': + return false; + + case undefined: + return undefined; + + default: + throw new Error('Unknown $count option, only "true" and "false" are supported.'); + } +} \ No newline at end of file diff --git a/src/odata/entity/parser/filter.js b/src/odata/entity/parser/filter.js new file mode 100644 index 0000000..4123595 --- /dev/null +++ b/src/odata/entity/parser/filter.js @@ -0,0 +1,193 @@ +import parseValue from '../../parser/value'; +import parseProperty from './property'; +import validateProperty from '../validators/property'; + +export default function (req, entity, metadata, mapping) { + const funcRegex = /(contains|indexof|year)\s*\(\s*([^,]+)\s*[,]?\s*([^)]*)\)\s*(eq|ne|gt|ge|lt|le)?\s*([0-9]*)/i; + + const replaceString = (filter, dictionary) => { + const replacer = (match, p1) => { + const result = `$${dictionary.length}`; + + dictionary[result] = p1; + return result; + }; + + if (filter.search(/'[^']*'/) === -1) { + return visitor('splitOr', filter, dictionary); + + } + + const replacedFilter = filter.replace(/'([^']*)'/g, replacer); + + return visitor('splitOr', replacedFilter, dictionary); + + }; + + const splitOr = (filter, dictionary) => { + const result = { + $or: [] + }; + + if (filter.search(/\s+or\s+/i) === -1) { + return visitor('splitAnd', filter, dictionary); + } + + const subConditions = filter.split(/\s+or\s+/i); + + subConditions.forEach(item => { + result.$or.push(visitor('splitAnd', item, dictionary)); + }); + + return result; + }; + + const splitAnd = (filter, dictionary) => { + const result = []; + + if (filter.search(/\s+and\s+/i) === -1) { + return visitor('splitCondition', filter, dictionary); + } + + const subConditions = filter.split(/\s+and\s+/i); + + subConditions.forEach(item => { + const newCondition = visitor('splitCondition', item, dictionary); + const properties = Object.keys(newCondition); + const oldCondition = result.find(item => + properties.find(name => item[name])); + const sameProperty = properties.find(name => oldCondition && oldCondition[name]); + + if (oldCondition) { + oldCondition[sameProperty] = { + ...oldCondition[sameProperty], + ...newCondition[sameProperty] + }; + } else { + result.push(newCondition); + } + }); + + return result.length > 1 ? { $and: result } : result[0]; + }; + + const splitCondition = (filter, dictionary) => { + const operatorIndex = filter.search(/\s+(eq|ne|gt|ge|lt|le)\s+/i); + + if (filter.match(funcRegex)) { + return visitor('parseFunction', filter, dictionary); + } + + const operands = filter.split(/\s+(eq|ne|gt|ge|lt|le)\s+/i); + + if (operands?.length != 3) { + const err = new Error(`Two operands and one operator was expected in '${filter}'`); + + err.status = 400; + throw err; + } + let operator; + const operatorPrettified = operands[1].trim().toLowerCase(); + + switch (operatorPrettified) { + case 'eq': + case 'ne': + case 'gt': + case 'lt': + operator = `$${operatorPrettified}`; + break; + + case 'ge': + operator = '$gte'; + break; + + case 'le': + operator = '$lte'; + break; + + default: + throw new Error(`Unexpected operator '${operatorPrettified}' in '${$filter}'`); + } + + const property = parseProperty(operands[0], mapping); + const value = operands[2].trim(); + + return { + [property]: { + [operator]: parseValue(dictionary[value] || value, validateProperty(operands[0].trim(), req, entity, metadata)) + } + }; + }; + + const parseFunction = (filter, dictionary) => { + // contains(CompanyName,'freds') + // indexof(CompanyName,'lfreds') eq 1 + // year(BirthDate) eq 0 + const match = filter.match(funcRegex); + + if (!match) { + const err = new Error(`Text '${filter}' can not be interpreted`); + + err.status = 400; + throw err; + } + + const func = match[1].toLowerCase(); + const property = parseProperty(match[2], mapping); + const parameter = match[3] && dictionary[match[3]] ? dictionary[match[3]] : match[3]; + + // 0 indexof(CompanyName,$0) eq 10 + // 1 indexof + // 2 CompanyName + // 3 $0 + // 4 eq + // 5 10 + + // 0 year(BirthDate) eq 0 + // 1 year + // 2 BirthDate + // 3 + // 4 eq + // 5 0 + + return { + [property]: { + $function: { + $name: func, + $parameter: parameter, + $operator: match[4], + $value: match[5] || undefined + } + } + }; + }; + + const visitor = (step, filter, dictionary) => { + if (!filter || !filter.trim()) { + return undefined; + } + + switch (step) { + case 'parseFunction': + return parseFunction(filter, dictionary); + + case 'replaceStrings': + return replaceString(filter, []); + + case 'splitAnd': + return splitAnd(filter, dictionary); + + case 'splitCondition': + return splitCondition(filter, dictionary); + + case 'splitOr': + return splitOr(filter, dictionary); + + default: + throw new Error(`Step '${step}' not implemented`); + } + }; + + return visitor('replaceStrings', req.query.$filter); + +} \ No newline at end of file diff --git a/src/odata/entity/parser/keys.js b/src/odata/entity/parser/keys.js new file mode 100644 index 0000000..fdff432 --- /dev/null +++ b/src/odata/entity/parser/keys.js @@ -0,0 +1,23 @@ +import parseValue from '../../parser/value'; +import parseProperty from './property'; +import validateProperty from '../validators/property'; + +export default function(req, entity, metadata, mapping) { + const result = {}; + + if (req.params) { + const params = Object.keys(req.params) + .filter(param => metadata.$Key.indexOf(param) >= 0); + + if (params) { + params.forEach(param => { + const property = parseProperty(param, mapping); + const propertyMetadata = validateProperty(param, req, entity, metadata); + + result[property] = parseValue(req.params[param], propertyMetadata); + }); + } + } + + return result; +} \ No newline at end of file diff --git a/src/odata/entity/parser/orderby.js b/src/odata/entity/parser/orderby.js new file mode 100644 index 0000000..45bfaec --- /dev/null +++ b/src/odata/entity/parser/orderby.js @@ -0,0 +1,23 @@ +import parseProperty from "./property"; +import validateProperty from "../validators/property"; + +export default function parseOrderBy(req, entity, metadata, mapping, options) { + const orderby = options || req.query.$orderby; + + if (orderby) { + const found = orderby.match(/([^ ,]+)\s*(asc|desc)?/gi); + + if (!found) { + throw new Error(`Orderby value '${orderby}' can not be parsed`); + } + + return [...found.map(singleOrder => { + const operands = singleOrder.match(/([^ ,]+)\s*(asc|desc)?/i); + const property = parseProperty(operands[1], req, entity, metadata, mapping); + + validateProperty(operands[1], req, entity, metadata); + + return [property, operands[2]?.trim().toLowerCase() || 'asc'] + })]; + } +} \ No newline at end of file diff --git a/src/odata/entity/parser/property.js b/src/odata/entity/parser/property.js new file mode 100644 index 0000000..2348c1e --- /dev/null +++ b/src/odata/entity/parser/property.js @@ -0,0 +1,10 @@ +export default function parseProperty(filter, mapping) { + let property = filter?.trim(); + + if (mapping[property]) { + property = mapping[property].intern; + + } + + return property; +} \ No newline at end of file diff --git a/src/odata/entity/parser/select.js b/src/odata/entity/parser/select.js new file mode 100644 index 0000000..6019179 --- /dev/null +++ b/src/odata/entity/parser/select.js @@ -0,0 +1,13 @@ +import parseProperty from "./property"; +import validateProperty from "../validators/property"; + +export default function(req, entity, metadata, mapping) { + return req.query.$select?.split(',').map((item) => { + const name = item.trim().replace('/', '.'); + const property = parseProperty(name, mapping); + + validateProperty(name, req, entity, metadata); + + return property; + }); +} \ No newline at end of file diff --git a/src/odata/entity/parser/skiptop.js b/src/odata/entity/parser/skiptop.js new file mode 100644 index 0000000..1f75602 --- /dev/null +++ b/src/odata/entity/parser/skiptop.js @@ -0,0 +1,34 @@ +import { min } from '../../../utils'; + +function parse(value, options) { + const input = value; + + if (!input) { + return; + } + + const result = +input; + if (Number.isNaN(result)) { + const err = new Error(`Value '${input}' should be a number`); + + err.status = 400; + throw err; + } + + if (result < 0) { + const err = new Error(`Value '${result}' should be a positive number`); + + err.status = 400; + throw err; + } + + return min([result, options]); +} + +export function parseSkip(req, options) { + return parse(req.query.$skip, options); +} + +export function parseTop(req, options) { + return parse(req.query.$top, options); +} \ No newline at end of file diff --git a/src/odata/entity/validators/property.js b/src/odata/entity/validators/property.js new file mode 100644 index 0000000..6910de9 --- /dev/null +++ b/src/odata/entity/validators/property.js @@ -0,0 +1,21 @@ +export default function validateProperty(name, req, entity, currentMetadata) { + const property = name.toString(); + + if (currentMetadata[property]) { + return currentMetadata[property]; + } + + const indexDot = property.indexOf('.'); + if ( indexDot > 0) { + const nextProperty = property.substr(indexDot + 1); + const complexType = property.substr(0, indexDot); + + return validateProperty(nextProperty, req, entity, req.$odata.$metadata.complexType(currentMetadata[complexType].$Type)); + } + + const err = new Error(`Entity '${entity}' has no property named '${property}'`); + + err.status = 400; + err.target = property; + throw err; +} \ No newline at end of file diff --git a/src/odata/parser/value.js b/src/odata/parser/value.js new file mode 100644 index 0000000..f1ad9cb --- /dev/null +++ b/src/odata/parser/value.js @@ -0,0 +1,72 @@ +function parseBoolean(value, metadata) { + if (value === 'true') { + return true; + } + + if (value === 'false') { + return false; + } + + const err = new Error(`Text '${value}' is not valid boolean representation`); + + err.status = 400; + throw err; +} + +function parseNumber(value, metadata) { + const result = +value; + + if (Number.isNaN(value)) { + const err = new Error(`Text '${value}' is not valid represenation of a number`); + + err.status = 400; + throw err; + } + + return result; +} + +function parseDate(value, metadata) { + const result = new Date(value); + + if (Number.isNaN(result.valueOf())) { + const err = new Error(`Text '${value}' is not valid represenation of a date`); + + err.status = 400; + throw err; + } +} + +export default function (value, metadata) { + const trimmed = value.trim(); + + if (metadata.$Nullable && trimmed === 'null') { + return null; + } + + switch (metadata.$Type) { + case 'Edm.Boolean': + return parseBoolean(trimmed, metadata); + + case 'Edm.Byte': + case 'Edm.Decimal': + case 'Edm.Double': + case 'Edm.Duration': + case 'Edm.Int16': + case 'Edm.Int32': + case 'Edm.Int64': + case 'Edm.SByte': + case 'Edm.Single': + return parseNumber(trimmed, metadata); + + case 'Edm.Date': + case 'Edm.DateTimeOffset': + case 'Edm.Duration': + case 'Edm.TimeOfDay': + return parseDate(trimmed, metadata); + + default: + return trimmed; + } + +} \ No newline at end of file diff --git a/src/odata/validator.js b/src/odata/validator.js new file mode 100644 index 0000000..eb12746 --- /dev/null +++ b/src/odata/validator.js @@ -0,0 +1,188 @@ + +export const validateIdentifier = (identifier) => { + if (!identifier || !identifier.match(/^^[_a-zA-Z0-9][_a-zA-Z0-9.-]*$/)) { + throw new Error(`Invalid simple identifier '${identifier}'`); + } +} + + +function shouldContains(property, member, list) { + if (property[member] && list.indexOf(property[member]) === -1 + && (!property[member].match(/node\.odata/) || member != '$Type')) {// custom type + throw new Error(`${member} '${property[member]}' is invalid`); + } +} + +function validateType(property, member) { + const types = ['Edm.Binary', 'Edm.Boolean', 'Edm.Byte', 'Edm.Date', + 'Edm.DateTimeOffset', 'Edm.Decimal', 'Edm.Double', 'Edm.Duration', 'Edm.Guid', + 'Edm.Int16', 'Edm.Int32', 'Edm.Int64', 'Edm.SByte', 'Edm.Single', + 'Edm.Stream', 'Edm.String', 'Edm.TimeOfDay', 'Edm.Geography', 'Edm.GeographyPoint', + 'Edm.GeographyLineString', 'Edm.GeographyPolygon', 'Edm.GeographyMultiPoint', 'Edm.GeographyMultiLineString', + 'Edm.GeographyMultiPolygon', 'Edm.GeographyCollection', 'Edm.Geometry', 'Edm.GeometryPoint', 'Edm.GeometryLineString', + 'Edm.GeometryPolygon', 'Edm.GeometryMultiPoint', 'Edm.GeometryMultiLineString', 'Edm.GeometryMultiPolygon', + 'Edm.GeometryCollection']; + + shouldContains(property, member.trim(), types); + +} + +function validateSRID(name, property) { + if (!property[name]) { + throw new Error(`If SRID is given, then the value had to be supplied`); + } + if (property[name] !== 'variable') { + const srid = +(property[name]); + + if (Number.isNaN(srid)) { + throw new Error(`'${srid}' is invalid value for SRID of ${name} property`); + } + if (srid < 0) { + throw new Error(`SRID has to be a non negative value. Current '${srid}'`); + } + } +} + +function shouldBePositive(name, property, member) { + const value = property[member]; + + if (!value) { + throw new Error(`If '${member}' is given, than the value had to be supplied`); + } + + if (Number.isNaN(+value)) { + throw new Error(`Value '${value}' is invalid for '${member}'`); + } + + if (+value < 1) { + throw new Error(`If '${member}' is given, than the value had to be supplied`) + } + +} + +export const validateProperty = (name, property) => { + validateIdentifier(name); + + const members = Object.keys(property); + const allowedMembers = ['$Type', '$Collection', '$Nullable', '$MaxLength', + '$Unicode', '$Precision', '$Scale', '$SRID', '$DefaultValue']; + const boolean = [true, false]; + + members.forEach(member => { + switch (member.trim()) { + case '$Type': + validateType(property, member); + break; + + case '$Collection': + case '$Nullable': + case '$Unicode': + shouldContains(property, member.trim(), boolean); + break; + + case '$SRID': + validateSRID(name, property); + break; + + case '$MaxLength': + case '$Precision': + case '$Scale': + shouldBePositive(name, property, member); + break; + + case '$DefaultValue': + break; + + default: + const trimmedMember = member.trim(); + + if (!trimmedMember.match(/^(@\w+(\.\w+)?(#\w+)?)+$/)) { // annotations should be ignored + throw new Error(`'${trimmedMember}' ist not allowed as member of property '${name}'`); + } + } + }); +} + +const validateParameter = parameter => { + if (!parameter) { + throw new Error('Parameter should not be undefined'); + } + + if (!parameter.$Name) { + throw new Error('$Name of Parameter should be given'); + } + + const clone = JSON.parse(JSON.stringify(parameter)); + + delete clone.$Name; + + validateProperty(parameter.$Name, clone); +} + +export const validateParameters = parameter => { + if (!parameter) { + throw new Error('Parameter should not be undefined or null'); + } + + if (!Array.isArray(parameter)) { + throw new Error('Parameter should be an array of parameters'); + } + + parameter.forEach(item => validateParameter(item)); +} + +function validateComplexType(node) { + const properties = Object.keys(node); + + properties.filter(name => name !== '$Kind') + .forEach(name => validateProperty(name, node[name])); + + if (!properties.length) { + throw new Error('ComplexType without properties is not allowed') + } +} + +function validateEntityType(node) { + const attributes = Object.keys(node); + + if (!node.$Key || !node.$Key.length) { + throw new Error('EntityType without key is not allowed') + } + + if (!Array.isArray(node.$Key)) { + throw new Error('$Key of Entitytype has to be an array of property names'); + } + + const properties = attributes.filter(name => name !== '$Kind' && name !== '$Key' && name[0] != '@'); + + properties.forEach(name => validateProperty(name, node[name])); + + if (!properties.length) { + throw new Error('ComplexType without properties is not allowed') + } + + node.$Key.forEach(key => { + if (properties.indexOf(key) === -1) { + throw new Error(`EntityType has not a property for $Key with name "${key}"`) + } + }); +} + +export const validate = node => { + if (!node) { + throw new Error('For validation an object should not be undefined'); + } + + switch (node.$Kind) { + case 'ComplexType': + validateComplexType(node); + break; + + case 'EntityType': + validateEntityType(node); + break; + + default: + throw new Error('For validation an object need a property $Kind'); + } +} \ No newline at end of file diff --git a/src/parser/countParser.js b/src/parser/countParser.js deleted file mode 100644 index 8f2b275..0000000 --- a/src/parser/countParser.js +++ /dev/null @@ -1,28 +0,0 @@ -import filterParser from './filterParser'; - -// ?$count=10 -// -> -// query.count(10) -export default (mongooseModel, $count, $filter) => new Promise((resolve, reject) => { - if ($count === undefined) { - resolve(); - return; - } - - switch ($count) { - case 'true': { - const query = mongooseModel.find(); - filterParser(query, $filter); - query.count((err, count) => { - resolve(count); - }); - break; - } - case 'false': - resolve(); - break; - default: - reject(new Error('Unknown $count option, only "true" and "false" are supported.')); - break; - } -}); diff --git a/src/parser/filterParser.js b/src/parser/filterParser.js deleted file mode 100644 index 84ceb9c..0000000 --- a/src/parser/filterParser.js +++ /dev/null @@ -1,140 +0,0 @@ -// Operator Description Example -// Comparison Operators -// eq Equal Address/City eq 'Redmond' -// ne Not equal Address/City ne 'London' -// gt Greater than Price gt 20 -// ge Greater than or equal Price ge 10 -// lt Less than Price lt 20 -// le Less than or equal Price le 100 -// has Has flags Style has Sales.Color'Yellow' #todo -// Logical Operators -// and Logical and Price le 200 and Price gt 3.5 -// or Logical or Price le 3.5 or Price gt 200 #todo -// not Logical negation not endswith(Description,'milk') #todo - -// eg. -// http://host/service/Products?$filter=Price lt 10.00 -// http://host/service/Categories?$filter=Products/$count lt 10 - -import functions from './functionsParser'; -import { split } from '../utils'; - -const OPERATORS_KEYS = ['eq', 'ne', 'gt', 'ge', 'lt', 'le', 'has']; - -const stringHelper = { - has: (str, key) => str.indexOf(key) >= 0, - - isBeginWith: (str, key) => str.indexOf(key) === 0, - - isEndWith: (str, key) => str.lastIndexOf(key) === (str.length - key.length), - - removeEndOf: (str, key) => { - if (stringHelper.isEndWith(str, key)) { - return str.substr(0, str.length - key.length); - } - return str; - }, -}; - -const validator = { - formatValue: (value) => { - let val; - if (value === 'true') { - val = true; - } else if (value === 'false') { - val = false; - } else if (!Number.isNaN(+value)) { - val = +value; - } else if (stringHelper.isBeginWith(value, "'") && stringHelper.isEndWith(value, "'")) { - val = value.slice(1, -1); - } else if (value === 'null') { - val = value; - } else { - return ({ err: new Error(`Syntax error at '${value}'.`) }); - } - return ({ val }); - }, -}; - -export default (query, $filter) => new Promise((resolve, reject) => { - if (!$filter) { - resolve(); - return; - } - - const condition = split($filter, ['and', 'or']) - .filter((item) => (item !== 'and' && item !== 'or')); - - condition.forEach((item) => { - // parse "indexof(title,'X1ML') gt 0" - const conditionArr = split(item, OPERATORS_KEYS); - if (conditionArr.length === 0) { - // parse "contains(title,'X1ML')" - conditionArr.push(item); - } - if (conditionArr.length !== 3 && conditionArr.length !== 1) { - return reject(new Error(`Syntax error at '${item}'.`)); - } - - let key = conditionArr[0]; - const [, odataOperator, value] = conditionArr; - - if (key === 'id') key = '_id'; - - let val; - if (value !== undefined) { - const result = validator.formatValue(value); - if (result.err) { - return reject(result.err); - } - val = result.val; - } - - // function query - const functionKey = key.substring(0, key.indexOf('(')); - if (['indexof', 'year', 'contains'].indexOf(functionKey) > -1) { - functions[functionKey](query, key, odataOperator, val); - } else { - if (conditionArr.length === 1) { - return reject(new Error(`Syntax error at '${item}'.`)); - } - if (value === 'null') { - switch (odataOperator) { - case 'eq': - query.exists(key, false); - return resolve(); - case 'ne': - query.exists(key, true); - return resolve(); - default: - break; - } - } - // operator query - switch (odataOperator) { - case 'eq': - query.where(key).equals(val); - break; - case 'ne': - query.where(key).ne(val); - break; - case 'gt': - query.where(key).gt(val); - break; - case 'ge': - query.where(key).gte(val); - break; - case 'lt': - query.where(key).lt(val); - break; - case 'le': - query.where(key).lte(val); - break; - default: - return reject(new Error("Incorrect operator at '#{item}'.")); - } - } - return query; - }); - resolve(); -}); diff --git a/src/parser/functionsParser.js b/src/parser/functionsParser.js deleted file mode 100644 index e1382fc..0000000 --- a/src/parser/functionsParser.js +++ /dev/null @@ -1,78 +0,0 @@ -const convertToOperator = (odataOperator) => { - let operator; - switch (odataOperator) { - case 'eq': - operator = '=='; - break; - case 'ne': - operator = '!='; - break; - case 'gt': - operator = '>'; - break; - case 'ge': - operator = '>='; - break; - case 'lt': - operator = '<'; - break; - case 'le': - operator = '<='; - break; - default: - throw new Error('Invalid operator code, expected one of ["==", "!=", ">", ">=", "<", "<="].'); - } - return operator; -}; - -// contains(CompanyName,'icrosoft') -const contains = (query, fnKey) => { - let [key, target] = fnKey.substring(fnKey.indexOf('(') + 1, fnKey.indexOf(')')).split(','); - [key, target] = [key.trim(), target.trim()]; - query.$where(`this.${key}.indexOf(${target}) != -1`); -}; - -// indexof(CompanyName,'X') eq 1 -const indexof = (query, fnKey, odataOperator, value) => { - let [key, target] = fnKey.substring(fnKey.indexOf('(') + 1, fnKey.indexOf(')')).split(','); - [key, target] = [key.trim(), target.trim()]; - const operator = convertToOperator(odataOperator); - query.$where(`this.${key}.indexOf(${target}) ${operator} ${value}`); -}; - -// year(publish_date) eq 2000 -const year = (query, fnKey, odataOperator, value) => { - const key = fnKey.substring(fnKey.indexOf('(') + 1, fnKey.indexOf(')')); - - const start = new Date(+value, 0, 1); - const end = new Date(+value + 1, 0, 1); - - switch (odataOperator) { - case 'eq': - query.where(key).gte(start).lt(end); - break; - case 'ne': { - const condition = [{}, {}]; - condition[0][key] = { $lt: start }; - condition[1][key] = { $gte: end }; - query.or(condition); - break; - } - case 'gt': - query.where(key).gte(end); - break; - case 'ge': - query.where(key).gte(start); - break; - case 'lt': - query.where(key).lt(start); - break; - case 'le': - query.where(key).lt(end); - break; - default: - throw new Error('Invalid operator code, expected one of ["==", "!=", ">", ">=", "<", "<="].'); - } -}; - -export default { indexof, year, contains }; diff --git a/src/parser/mimetypeParser.js b/src/parser/mimetypeParser.js new file mode 100644 index 0000000..86f0fab --- /dev/null +++ b/src/parser/mimetypeParser.js @@ -0,0 +1,54 @@ +export default class MimetypeParser { + constructor() { + this._regexes = { + 'application/xml': /((application|\*)\/(xml|\*)|^xml$)/, + 'application/json': /((application|\*)\/(json|\*)|^json$)/, + 'multipart/mixed': /multipart\/mixed/ + }; + } + + getmMediaType(format, accept, supportedFormats, requrestContentType) { + if (format) { + // get requested media type from $format query + return this._getMediaType(format, supportedFormats); + } else if (accept) { + // get requested media type from accept header + return this._getMediaType(accept, supportedFormats); + } else if (requrestContentType) { + return requrestContentType; + } + + return supportedFormats[0]; + } + + _getMediaType(header, supportedTypes) { + // reduce multi mimetypes to most weigth mimetype + // e.g. Accept: text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8 + const mimeStructs = header.split(/[ ,]+/g); + const mostWeightMimetype = mimeStructs.reduce((previous, current) => { + const [mimetype, qualityParam] = current.split(/[ ;]+/); + const [, qualityValue] = qualityParam ? qualityParam.split(/=/) : ['q', 1]; + const result = { + ...previous, + }; + + const supported = supportedTypes.find(item => mimetype.match(this._regexes[item])); + + if (supported + && (!previous.mimetype || previous.qualityValue < qualityValue)) { + result.mimetype = supported; + result.qualityValue = qualityValue; + } + return result; + }, {}); + + if (mostWeightMimetype.mimetype) { + return mostWeightMimetype.mimetype; + } + + const error406 = new Error('Not acceptable'); + + error406.status = 406; + throw error406; + } +} \ No newline at end of file diff --git a/src/parser/multipartMixed.js b/src/parser/multipartMixed.js new file mode 100644 index 0000000..cea8dfd --- /dev/null +++ b/src/parser/multipartMixed.js @@ -0,0 +1,54 @@ +const bodyParser = require('body-parser'); + +function multipart(req, res, next) { + const header = req.headers['content-type']; + + if (!header || header.indexOf('multipart/mixed') === -1) { + next(); + return; + } + + const matchesBoundary = header.match(/boundary\s*=\s*([^;]*)/); + + req.body = { + requests: req.body.split(new RegExp(`\s*--${matchesBoundary[1]}[-]{0,2}\s*`)) + .filter(item => item.trim()) + .map(singleRequestText => { + const result = {}; + + if (singleRequestText.indexOf("Group ID: ") >= 0) { + return; //sap extension, not documentet in odata + } + const matchMethodUrl = singleRequestText.match(/^(GET|POST|PUT|PATCH|DELETE)\s+([\w\/\.,$?=\-()']+)\s*/m); + + if (!matchMethodUrl) { + throw new Error(`Method in ${singleRequestText} not supported`); + } + + result.method = matchMethodUrl[1].toLowerCase(); + result.url = matchMethodUrl[2]; + + const headerText = singleRequestText.split(matchMethodUrl[1])[1]; + const matchHeaders = headerText.match(/^^([\w-]+)\s*:\s*([\w\s;=.\/-]+)\s*$/gmi); + + result.headers = { + }; + matchHeaders.forEach((value) => { + const parts = value.split(':'); + + result.headers[parts[0].trim()] = parts[1].trim(); + }); + + const blocks = singleRequestText.split('\r\n\r\n'); + if (blocks.length > 2 && blocks[2].trim()) { + result.body = JSON.parse(blocks[2]); + } + + return result; + }).filter(item => item) + }; + + next(); +} + +export default [bodyParser.text({type: 'multipart/mixed'}), multipart]; \ No newline at end of file diff --git a/src/parser/selectParser.js b/src/parser/selectParser.js deleted file mode 100644 index 122a226..0000000 --- a/src/parser/selectParser.js +++ /dev/null @@ -1,32 +0,0 @@ -// ?$select=Rating,ReleaseDate -// -> -// query.select('Rating ReleaseDate') -export default (query, $select) => new Promise((resolve) => { - if (!$select) { - resolve(); - return; - } - - const list = $select.split(',').map((item) => item.trim()); - - const selectFields = { _id: 0 }; - const { tree } = query.model.schema; - Object.keys(tree).map((item) => { - if (list.indexOf(item) >= 0) { - if (item === 'id') { - selectFields._id = 1; - } else if (typeof tree[item] === 'function' || tree[item].select !== false) { - selectFields[item] = 1; - } - } - return undefined; - }); - - if (Object.keys(selectFields).length === 1 && selectFields._id === 0) { - resolve(); - return; - } - - query.select(selectFields); - resolve(); -}); diff --git a/src/parser/skipParser.js b/src/parser/skipParser.js deleted file mode 100644 index 5fdda1e..0000000 --- a/src/parser/skipParser.js +++ /dev/null @@ -1,16 +0,0 @@ -import { min } from '../utils'; - -// ?$skip=10 -// -> -// query.skip(10) -export default (query, skip, maxSkip) => new Promise((resolve) => { - if (Number.isNaN(+skip)) { - resolve(); - return; - } - const _skip = min([maxSkip, skip]); - if (_skip > 0) { - query.skip(_skip); - } - resolve(); -}); diff --git a/src/parser/topParser.js b/src/parser/topParser.js deleted file mode 100644 index 59aa866..0000000 --- a/src/parser/topParser.js +++ /dev/null @@ -1,16 +0,0 @@ -import { min } from '../utils'; - -// ?$top=10 -// -> -// query.top(10) -export default (query, top, maxTop) => new Promise((resolve) => { - if (Number.isNaN(+top)) { - resolve(); - return; - } - const _top = min([maxTop, top]); - if (_top > 0) { - query.limit(_top); - } - resolve(); -}); diff --git a/src/pipes.js b/src/pipes.js deleted file mode 100644 index dbbf1dd..0000000 --- a/src/pipes.js +++ /dev/null @@ -1,126 +0,0 @@ -import http from 'http'; -import XmlWriter from './metadata/xmlWriter'; - -const xmlWriter = new XmlWriter(); - -function writeJson(res, data, status, resolve) { - res.type('application/json'); - res.status(status).jsonp(data); - resolve(data); -} - -function getMediaType(accept) { - if (accept.match(/(application\/)?json/)) { - return 'application/json'; - } if (accept.match(/(application\/)?xml/)) { - return 'application/xml'; - } - - const error406 = new Error('Not acceptable'); - - error406.status = 406; - throw error406; -} - -function getWriter(req, result) { - let mediaType; - - if (req.query.$format) { - // get requested media type from $format query - mediaType = getMediaType(req.query.$format); - } else if (req.headers.accept) { - // get requested media type from accept header - mediaType = getMediaType(req.headers.accept); - } - - // xml representation of metadata - switch (mediaType) { - case 'application/json': - return writeJson; - - case 'application/xml': - if (result.entity) { - // xml wirter for entities and actions is not implemented - const error406 = new Error('Not acceptable'); - - error406.status = 406; - throw error406; - } - return xmlWriter.writeXml.bind(xmlWriter); - - default: - // no media type requested set defaults depend of context - if (result.entity) { - return writeJson; // default for entities and actions - } - - return xmlWriter.writeXml.bind(xmlWriter); // default for metadata - } -} - -const authorizePipe = (req, res, auth) => new Promise((resolve, reject) => { - if (auth !== undefined) { - if (!auth(req, res)) { - const result = new Error(); - - result.status = 401; - reject(result); - return; - } - } - resolve(); -}); - -const beforePipe = (req, res, before) => new Promise((resolve) => { - if (before) { - before(req.body, req, res); - } - resolve(); -}); - -const respondPipe = (req, res, result) => new Promise((resolve, reject) => { - try { - if (result.status === 204) { // no content - res.status(204).end(); - resolve(); - return; - } - - const status = result.status || 200; - const writer = getWriter(req, result); - let data; - - if (result.entity) { - // json Representation of data - data = result.entity; - } else { - // xml representation of metadata - data = result.metadata; - } - - writer(res, data, status, resolve); - } catch (error) { - reject(error); - } -}); - -const afterPipe = (req, res, after, data) => new Promise((resolve) => { - if (after) { - after(data, req.body, req, res); - } - resolve(); -}); - -const errorPipe = (req, res, err) => new Promise(() => { - const status = err.status || 500; - const text = err.text || err.message || http.STATUS_CODES[status]; - res.status(status).send(text); -}); - -export default { - afterPipe, - authorizePipe, - beforePipe, - errorPipe, - respondPipe, -}; diff --git a/src/rest/delete.js b/src/rest/delete.js deleted file mode 100644 index 794c2d4..0000000 --- a/src/rest/delete.js +++ /dev/null @@ -1,16 +0,0 @@ -export default (req, MongooseModel) => new Promise((resolve, reject) => { - MongooseModel.remove({ _id: req.params.id }, (err, result) => { - if (err) { - return reject(err); - } - - if (JSON.parse(result).n === 0) { - const error = new Error('Not Found'); - - error.status = 404; - return reject(error); - } - - return resolve({ status: 204 }); - }); -}); diff --git a/src/rest/get.js b/src/rest/get.js deleted file mode 100644 index b442b83..0000000 --- a/src/rest/get.js +++ /dev/null @@ -1,16 +0,0 @@ -export default (req, MongooseModel) => new Promise((resolve, reject) => { - MongooseModel.findById(req.params.id, (err, entity) => { - if (err) { - return reject(err); - } - - if (!entity) { - const result = new Error('Not Found'); - - result.status = 404; - return reject(result); - } - - return resolve({ entity }); - }); -}); diff --git a/src/rest/index.js b/src/rest/index.js deleted file mode 100644 index bcd264a..0000000 --- a/src/rest/index.js +++ /dev/null @@ -1,90 +0,0 @@ -import { Router } from 'express'; -import list from './list'; -import post from './post'; -import put from './put'; -import del from './delete'; -import patch from './patch'; -import get from './get'; -import pipes from '../pipes'; - -function addRestRoutes(router, routes, mongooseModel, options) { - return routes.map((route) => { - const { - method, url, ctrl, hook, - } = route; - return router[method](url, (req, res) => { - pipes.authorizePipe(req, res, hook.auth) - .then(() => pipes.beforePipe(req, res, hook.before)) - .then(() => ctrl(req, mongooseModel, options)) - .then((result) => pipes.respondPipe(req, res, result || {})) - .then((data) => pipes.afterPipe(req, res, hook.after, data)) - .catch((err) => pipes.errorPipe(req, res, err)); - }); - }); -} - -const getRouter = (mongooseModel, { url, hooks, options }) => { - const resourceListURL = `/${url}`; - const resourceURL = `${resourceListURL}\\(:id\\)`; - - const routes = [ - { - method: 'post', - url: resourceListURL, - ctrl: post, - hook: hooks.post, - }, - { - method: 'put', - url: resourceURL, - ctrl: put, - hook: hooks.put, - }, - { - method: 'patch', - url: resourceURL, - controller: patch, - config: hooks.patch, - }, - { - method: 'delete', - url: resourceURL, - ctrl: del, - hook: hooks.delete, - }, - { - method: 'get', - url: resourceURL, - ctrl: get, - hook: hooks.get, - }, - { - method: 'get', - url: resourceListURL, - ctrl: list, - hook: hooks.list, - }, - ]; - - /*eslint-disable */ - const router = Router(); - /* eslint-enable */ - addRestRoutes(router, routes, mongooseModel, options); - return router; -}; - -const getOperationRouter = (resourceUrl, actionUrl, fn, auth) => { - /*eslint-disable */ - const router = Router(); - /* eslint-enable */ - - router.post(`${resourceUrl}${actionUrl}`, (req, res, next) => { - pipes.authorizePipe(req, res, auth) - .then(() => fn(req, res, next)) - .catch((result) => pipes.errorPipe(req, res, result)); - }); - - return router; -}; - -export default { getRouter, getOperationRouter }; diff --git a/src/rest/list.js b/src/rest/list.js deleted file mode 100644 index 9258e92..0000000 --- a/src/rest/list.js +++ /dev/null @@ -1,62 +0,0 @@ -import countParser from '../parser/countParser'; -import filterParser from '../parser/filterParser'; -import orderbyParser from '../parser/orderbyParser'; -import skipParser from '../parser/skipParser'; -import topParser from '../parser/topParser'; -import selectParser from '../parser/selectParser'; - -function _countQuery(model, { count, filter }) { - return new Promise((resolve, reject) => { - countParser(model, count, filter).then((dataCount) => (dataCount !== undefined - ? resolve({ '@odata.count': dataCount }) - : resolve({}) - )).catch(reject); - }); -} - -function _dataQuery(model, { - filter, orderby, skip, top, select, -}, options) { - return new Promise((resolve, reject) => { - const query = model.find(); - filterParser(query, filter) - .then(() => orderbyParser(query, orderby || options.orderby)) - .then(() => skipParser(query, skip, options.maxSkip)) - .then(() => topParser(query, top, options.maxTop)) - .then(() => selectParser(query, select)) - .then(() => query.exec((err, data) => { - if (err) { - return reject(err); - } - return resolve({ value: data }); - })) - .catch(reject); - }); -} - -export default (req, MongooseModel, options) => new Promise((resolve, reject) => { - const params = { - count: req.query.$count, - filter: req.query.$filter, - orderby: req.query.$orderby, - skip: req.query.$skip, - top: req.query.$top, - select: req.query.$select, - // TODO expand: req.query.$expand, - // TODO search: req.query.$search, - }; - - Promise.all([ - _countQuery(MongooseModel, params), - _dataQuery(MongooseModel, params, options), - ]).then((results) => { - const entity = results.reduce((current, next) => ({ ...current, ...next })); - resolve({ entity }); - }).catch((err) => { - const result = new Error(err.message); - - result.previous = err; - result.status = 500; - reject(result); - }); -}); diff --git a/src/rest/patch.js b/src/rest/patch.js deleted file mode 100644 index 2663b61..0000000 --- a/src/rest/patch.js +++ /dev/null @@ -1,15 +0,0 @@ -export default (req, MongooseModel) => new Promise((resolve, reject) => { - MongooseModel.findOne({ id: req.params.id }, (err, entity) => { - if (err) { - reject(err); - } else { - MongooseModel.update({ id: req.params.id }, { ...entity, ...req.body }, (err1) => { - if (err1) { - reject(err1); - } else { - resolve({ entity: req.body, originEntity: entity }); - } - }); - } - }); -}); diff --git a/src/rest/post.js b/src/rest/post.js deleted file mode 100644 index ad63d59..0000000 --- a/src/rest/post.js +++ /dev/null @@ -1,18 +0,0 @@ -export default (req, MongooseModel) => new Promise((resolve, reject) => { - if (!Object.keys(req.body).length) { - const error = new Error(); - - error.status = 422; - reject(error); - } else { - const entity = MongooseModel.create(req.body); - - entity.save((err) => { - if (err) { - reject(err); - } else { - resolve({ status: 201, entity }); - } - }); - } -}); diff --git a/src/rest/put.js b/src/rest/put.js deleted file mode 100644 index 77a5970..0000000 --- a/src/rest/put.js +++ /dev/null @@ -1,36 +0,0 @@ -function _updateEntity(resolve, reject, MongooseModel, req, entity) { - MongooseModel.findByIdAndUpdate(entity.id, req.body, (err) => { - if (err) { - return reject(err); - } - const newEntity = req.body; - newEntity.id = entity.id; - return resolve({ entity: newEntity, originEntity: entity }); - }); -} - -function _createEntity(resolve, reject, MongooseModel, req, entity) { - const uuidReg = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; - if (!uuidReg.test(req.params.id)) { - return reject({ status: 400 }, { text: 'Id is invalid.' }); - } - const newEntity = MongooseModel.create(req.body); - newEntity._id = req.params.id; - return newEntity.save((err) => { - if (err) { - return reject(err); - } - return resolve({ status: 201, entity: newEntity, originEntity: entity }); - }); -} - -export default (req, MongooseModel) => new Promise((resolve, reject) => { - MongooseModel.findOne({ _id: req.params.id }, (err, entity) => { - if (err) { - return reject(err); - } - return entity - ? _updateEntity(resolve, reject, MongooseModel, req, entity) - : _createEntity(resolve, reject, MongooseModel, req, entity); - }); -}); diff --git a/src/server.js b/src/server.js index 2f499e6..3194092 100644 --- a/src/server.js +++ b/src/server.js @@ -1,29 +1,79 @@ import createExpress from './express'; -import Resource from './ODataResource'; +import bodyParser from 'body-parser'; +import MongoEntity from './mongo/Entity'; +import MongoSingleton from './mongo/Singleton'; +import Entity from './odata/entity/Entity'; import Func from './ODataFunction'; -import Metadata from './metadata/ODataMetadata'; -import Db from './db/db'; +import Metadata from './odata/Metadata'; +import ServiceDocument from './odata/ServiceDocument'; +import Batch from './odata/Batch'; +import Action from './odata/Action'; +import error from './middlewares/error'; +import writer from './middlewares/writer'; +import Hooks from './odata/Hooks'; +import multipartMixed from './parser/multipartMixed'; +import Singleton from './odata/entity/Singleton'; +import Vocabulary from './odata/Vocabulary'; function checkAuth(auth, req) { return !auth || auth(req); } class Server { - constructor(db, prefix, options) { + constructor(prefix, options) { + const opts = (options && options.expressRequestLimit) + ? { limit: options.expressRequestLimit } : {}; + this._app = createExpress(options); this._settings = { maxTop: 10000, maxSkip: 10000, orderby: undefined, }; - this.defaultConfiguration(db, prefix); + this.defaultConfiguration(prefix); + + this.hooks = new Hooks(); // TODO: Infact, resources is a mongooseModel instance, origin name is repositories. // Should mix _resources object and resources object: _resources + resource = resources. // Encapsulation to a object, separate mognoose, try to use *repository pattern*. // 这里也许应该让 resources 支持 odata 查询的, 以方便直接在代码中使用 OData 查询方式来进行数据筛选, 达到隔离 mongo 的效果. - this.resources = {}; - this._metadata = new Metadata(this); + this.resources = { + $metadata: new Metadata(this), + $batch: new Batch(this), + }; + //unbound actions + this.actions = {}; + + this.hooks.addBefore(multipartMixed); + this.hooks.addBefore(bodyParser.json(opts)); + this.hooks.addBefore(async (req, res) => { + req.$odata = { + $metadata: this.resources.$metadata + }; + res.$odata = { + status: 404, + supportedMimetypes: ['application/json'], + messages: [] + } + }, 'service-initialization'); + this.hooks.addAfter(writer, 'writer', true); + + this._serviceDocument = new ServiceDocument(this); + this.annotations = new Vocabulary(); + this.error = error; + } + + vocabulary() { + return this.annotations; + } + + addBefore(fn, name) { + this.hooks.addBefore(fn, name); + } + + addAfter(fn, name) { + this.hooks.addAfter(fn, name); } function(url, middleware, params) { @@ -32,144 +82,175 @@ class Server { this.resources[func.getName()] = func; } - resource(name, model) { - if (model === undefined) { + entity(name, handler, metadata, settings) { + if (this.resources[name]) { + throw new Error(`Entity with name "${name}" already defined`); + } + + this.resources[name] = new Entity(name, handler, metadata, { + maxSkip: this._settings.maxSkip, //TODO: Validation of possible Mappings + maxTop: this._settings.maxTop, + orderby: this._settings.orderby, + ...settings + }, this.annotations); + + return this.resources[name]; + } + + mongoEntity(name, model, handler, metadata, settings, registerComplexTypes = true) { + if (name && !model) { + if (!this.resources[name]) { + throw new Error(`Entity '${name}' is not defined`); + } return this.resources[name]; } - const db = this.get('db'); - this.resources[name] = new Resource(this, name, model); + const mongoEntity = new MongoEntity(name, model, this.annotations); - this.resources[name].setModel(db.register(name, model)); + if (registerComplexTypes) { + const complexTypes = mongoEntity.getComplexTypes(); - return this.resources[name]; + if (complexTypes) { + Object.keys(complexTypes) + .forEach(typeName => { + const type = complexTypes[typeName]; + + this.complexType(typeName, type); + }); + } + } + + const entity = this.entity(name, { + ...mongoEntity.getHandler(), + ...handler + }, { + ...mongoEntity.getMetadata(), + ...metadata + }, settings); + + entity.mapping = mongoEntity.mapping; + + return entity; } - defaultConfiguration(db, prefix = '') { - this.set('app', this._app); - this.set('db', db); - this.set('prefix', prefix); + singleton(name, handler, metadata) { + if (this.resources[name]) { + throw new Error(`Entity with name "${name}" already defined`); + } + + this.resources[name] = new Singleton(name, handler, metadata, this.annotations); + + return this.resources[name]; } - post(url, callback, auth) { - const app = this.get('app'); - const prefix = this.get('prefix'); - app.post(`${prefix}${url}`, (req, res, next) => { - if (checkAuth(auth, req)) { - callback(req, res, next); - } else { - res.status(401).end(); - } - }); + singletonFrom(name, handler, entity) { + if (this.resources[name]) { + throw new Error(`Entity with name "${name}" already defined`); + } + + this.resources[name] = new Singleton(name, handler, entity, this.annotations); + + return this.resources[name]; } - put(url, callback, auth) { - const app = this.get('app'); - const prefix = this.get('prefix'); - app.put(`${prefix}${url}`, (req, res, next) => { - if (checkAuth(auth, req)) { - callback(req, res, next); - } else { - res.status(401).end(); + mongoSingleton(name, model, handler, metadata) { + if (name && !model) { + if (!this.resources[name]) { + throw new Error(`Entity '${name}' is not defined`); } + return this.resources[name]; + } + + const entity = new MongoSingleton(name, model, this.annotations); + + const complexTypes = entity.entity.getComplexTypes(); + + if (complexTypes) { + Object.keys(complexTypes) + .forEach(typeName => { + const type = complexTypes[typeName]; + + this.complexType(typeName, type); + }); + } + + const singletonEntity = this.singleton(name, { + ...entity.getHandler(), + ...handler + }, { + ...entity.entity.getMetadata(), + ...metadata }); + + singletonEntity.mapping = { + ...singletonEntity.mapping, + ...entity.mapping + } + return singletonEntity; } - delete(url, callback, auth) { - const app = this.get('app'); - const prefix = this.get('prefix'); - app.delete(`${prefix}${url}`, (req, res, next) => { - if (checkAuth(auth, req)) { - callback(req, res, next); - } else { - res.status(401).end(); - } - }); + defaultConfiguration(prefix = '') { + this.set('app', this._app); + this.set('prefix', prefix); } - patch(url, callback, auth) { - const app = this.get('app'); - const prefix = this.get('prefix'); - app.patch(`${prefix}${url}`, (req, res, next) => { - if (checkAuth(auth, req)) { - callback(req, res, next); - } else { - res.status(401).end(); - } - }); + action(name, fn, options) { + this.actions[name] = new Action(name, fn, this.annotations, options); + + return this.actions[name]; } - listen(...args) { - const router = this._metadata._router(); + getRouter() { + const result = []; - this._app.use(this.get('prefix'), router); + result.push(this._serviceDocument._router()); Object.keys(this.resources).forEach((resourceKey) => { const resource = this.resources[resourceKey]; - const resourceRouter = resource._router(this.getSettings()); - this.use(this.get('prefix'), resourceRouter); + result.push(resource._router ? resource._router() : resource.getRouter()); if (resource.actions) { Object.keys(resource.actions).forEach((actionKey) => { const action = resource.actions[actionKey]; - this.use(action.router); + result.push(action.getRouter()); }); } }); - return this._app.listen(...args); - } + Object.keys(this.actions).forEach(actionKey => { + const action = this.actions[actionKey]; - getSettings() { - return this._settings; + result.push(action.getRouter()); + }); + + return [...this.hooks.before, ...result, ...this.hooks.after, this.error]; } - use(...args) { - if (args[0] instanceof Resource) { - const [resource] = args; - this.resources[resource.getName()] = resource; - return; + complexType(name, properties) { + if (!properties) { + throw new Error('Metadata for complex type should be given'); } - this._app.use(...args); + return this.resources.$metadata.complexType(name, properties); } - get(key, callback, auth) { - if (callback === undefined) { - return this._settings[key]; - } - // TODO: Need to refactor, same as L70-L80 - const app = this.get('app'); - const prefix = this.get('prefix'); - return app.get(`${prefix}${key}`, (req, res, next) => { - if (checkAuth(auth, req)) { - callback(req, res, next); - } else { - res.status(401).end(); - } + listen(...args) { + const router = this.getRouter(); + + router.forEach((item) => { + this._app.use(this.get('prefix'), item); }); + + return this._app.listen(...args); + } + + get(key) { + return this._settings[key]; } set(key, val) { switch (key) { - case 'db': { - let db = val; - - if (typeof val === 'string') { - db = new Db(); - db.createConnection(val, null, (err) => { - if (err) { - console.error(err.message); - console.error('Failed to connect to database on startup.'); - process.exit(); - } - }); - } - - this._settings[key] = db; - break; - } case 'prefix': { let prefix = val; if (prefix === '/') { @@ -183,21 +264,20 @@ class Server { } default: { this._settings[key] = val; + if (this.resources) { + Object.keys(this.resources) + .forEach(name => { + if (this.resources[name].set) { + this.resources[name].set(key, val); + } + }); + } break; } } return this; } - // provide a event listener to handle not able to connect DB. - on(name, event) { - if (['connected', 'disconnected'].indexOf(name) > -1) { - const db = this.get('db'); - - db.on(name, event); - } - } - engine(...args) { this._app.engine(...args); } diff --git a/src/writer/Console.js b/src/writer/Console.js new file mode 100644 index 0000000..157b066 --- /dev/null +++ b/src/writer/Console.js @@ -0,0 +1,48 @@ +export default class Console { + constructor(settings) { + const logLevel = settings && settings.logLevel || process.env.LOG_LEVEL || 'error'; + + switch (logLevel) { + case 'debug': + this.logLevel = 40; + break; + + case 'info': + this.logLevel = 30; + break; + + case 'warning': + this.logLevel = 20; + break; + + case 'error': + this.logLevel = 10; + break; + + default: + if (logLevel) { + console.error(`Unsupported log level ${logLevel}`); + } + this.logLevel = 10; + break; + } + + this.namespace = settings && settings.namespace || 'node.odata'; + } + + debug(msg) { + if (this.logLevel < 40) { + return; + } + + console.debug(`[${new Date().toUTCString()}] ${this.namespace ? this.namespace : ''}: ${msg}`); + } + + log(obj) { + if (this.logLevel < 40) { + return; + } + + console.log(obj); + } +} \ No newline at end of file diff --git a/src/writer/jsonWriter.js b/src/writer/jsonWriter.js new file mode 100644 index 0000000..a7b0a3b --- /dev/null +++ b/src/writer/jsonWriter.js @@ -0,0 +1,13 @@ +export default class { + writeJson(res, data, status) { + let normalizedData = data; + + if (data.toObject) { + normalizedData = data.toObject(); + } + + res.type('application/json'); + res.status(status).jsonp(normalizedData); + } + +} diff --git a/src/writer/multipartWriter.js b/src/writer/multipartWriter.js new file mode 100644 index 0000000..0066db8 --- /dev/null +++ b/src/writer/multipartWriter.js @@ -0,0 +1,40 @@ +export default class MultipartWriter { + write(res, result, status, httpVersion) { + const boundary = 'batch_1'; + let body = ''; + + result.responses.forEach(response => { + body += `--${boundary}\r\nContent-Type: application/http\r\n\r\nHTTP/${httpVersion} ${response.status} ${response.statusText}\r\n`; + if (response.headers) { + const headers = Object.keys(response.headers); + + headers.forEach(header => { + body += `${header}: ${response.headers[header]}\r\n` + }); + } + body += '\r\n'; + + let textBody; + switch (typeof response.body) { + case 'string': + textBody = response.body; + break; + + case 'undefined': // http status 204 + textBody = '{}'; + break; + + default: + textBody = JSON.stringify(response.body); + break; + } + + body += `${textBody}\r\n`; + }); + + body += `--${boundary}--`; + + res.setHeader('content-type', `multipart/mixed;boundary=${boundary}`); + res.send(Buffer.from(body)).status(status); + } +} \ No newline at end of file diff --git a/src/writer/xmlWriter.js b/src/writer/xmlWriter.js new file mode 100644 index 0000000..7083b09 --- /dev/null +++ b/src/writer/xmlWriter.js @@ -0,0 +1,280 @@ +export default class XmlWriter { + visitor(type, node, name) { + switch (type) { + case 'document': + return this.visitDocument(node); + + case 'EntityType': + return this.visitEntityType(node, name); + + case 'Property': + return this.visitProperty(node, name); + + case 'EntityContainer': + return this.visitEntityContainter(node); + + case 'EntitySet': + return this.visitEntitySet(node, name); + + case 'Singleton': + return this.visitSingleton(node, name); + + case 'TypeDefinition': + return this.visitTypeDefinition(node, name); + + case 'ComplexType': + return this.visitComplexType(node, name); + + case 'Action': + return this.visitAction(node, name); + + case 'ActionImport': + return this.visitActionImport(node, name); + + case 'Function': + return this.visitFunction(node, name); + + case 'FunctionImport': + return this.visitFunctionImport(node, name); + + case 'Term': + return this.visitTerm(node, name); + + default: + throw new Error(`Type ${type} is not supported`); + } + } + + visitTerm(node, name) { + const appliesTo = node.$AppliesTo.reduce((previos, current) => { + return previos ? `${previos} ${current}` : current; + }, ""); + let type = node.$Collection ? `Collection(${node.$Type || 'Edm.String'})` : node.$Type; + + type = type ? `Type="${type}" ` : ''; + + return ` + + `; + } + + visitDocument(node) { + let body = ''; + + this.document = node; + + Object.keys(node).forEach((subnode) => { + if (node[subnode].$Kind) { + body += this.visitor(node[subnode].$Kind, node[subnode], subnode); + } + }); + + return ( + ` + + + ${body} + + + `); + } + + visitEntitySet(node, name) { + return ``; + } + + visitSingleton(node, name) { + return ``; + } + + visitEntityContainter(node) { + let entitySets = ''; + let singletons = ''; + let functions = ''; + let actions = '' + + Object.keys(node) + .filter((item) => item !== '$Kind') + .forEach((item) => { + if (node[item].$Collection === true) { + entitySets += this.visitor('EntitySet', node[item], item); + } else if (node[item].$Type) { + singletons += this.visitor('Singleton', node[item], item); + } else if (node[item].$Action) { + actions += this.visitor('ActionImport', node[item], item); + } else { + functions += this.visitor('FunctionImport', node[item], item); + } + }); + return ( + ` + ${entitySets}${singletons}${functions}${actions} + `); + } + + visitProperty(node, name) { + const type = node.$Collection ? `Collection(${node.$Type})` : node.$Type; + const annotations = Object.keys(node) + .filter(attribute => attribute[0] === '@') + .reduce((previous, current) => `${previous}${this.visitAnnotation(node[current], current)}`, ""); + let attributes = ''; + + if (node.$Nullable) { + attributes += ' Nullable="true"'; + } + if (node.$MaxLength) { + attributes += ` MaxLength="${node.$MaxLength}"`; + } + if (node.$DefaultValue) { + attributes += ` DefaultValue="${node.$DefaultValue}"`; + } + + if (!annotations) { + return ``; + } + return ` + ${annotations} + `; + + } + + visitAnnotation(node, name) { + const termName = name.substr(1); + const term = this.document[termName]; + + if (!term) { + throw new Error(`Term '${termName}' is not defined in scope`); + } + + const type = term.$Type ? term.$Type.split('.')[1] : 'String'; + let values; + + if (term.$Collection) { + values = node.reduce((previous, current) => `${previous}<${type}>${current}`, ""); + values = `${values}`; + } else { + values = `<${type}>${node}`; + } + + return ` + + ${values} + `; + } + + visitEntityType(node, name) { + let properties = ''; + let annotations = ''; + + Object.keys(node) + .filter((item) => item !== '$Kind' && item !== '$Key' && item[0] != '@') + .forEach((item) => { + properties += this.visitor('Property', node[item], item); + }); + + Object.keys(node) + .filter((item) => item[0] === '@') + .forEach((item) => { + annotations += this.visitAnnotation(node[item], item); + }); + + return ( + ` + + + + ${properties} + ${annotations} + `); + } + + visitTypeDefinition(node, name) { + let attributes = ''; + + if (node.$MaxLength) { + attributes += ` MaxLength="${node.$MaxLength}"`; + } + + return ( + ` + `); + } + + visitComplexType(node, name) { + let properties = ''; + + Object.keys(node) + .filter((item) => item !== '$Kind') + .forEach((item) => { + properties += this.visitor('Property', node[item], item); + }); + + return (` + + ${properties} + `); + } + + visitAction(node, name) { + const isBound = node.$IsBound ? ' IsBound="true"' : ''; + const annotations = Object.keys(node) + .filter(attribute => attribute[0] === '@') + .reduce((previous, current) => `${previous}${this.visitAnnotation(node[current], current)}`, ""); + const parameter = node.$Parameter && node.$Parameter + .map((item) => { + const parameterAnnotations = Object.keys(item) + .filter(attribute => attribute[0] === '@') + .reduce((previous, current) => `${previous}${this.visitAnnotation(item[current], current)}`, ""); + let type = ''; + + if (item.$Collection) { + type = ` Type="Collection(${item.$Type})"`; + } else if (item.$Type) { + type = ` Type="${item.$Type}"`; + } + if (!parameterAnnotations) { + return ``; + } + return ` + ${parameterAnnotations} + `; + }) + .reduce((previos, current) => `${previos}${current}`, ''); + + return (` + + ${annotations} + ${parameter || ''} + + `); + } + + visitActionImport(node, name) { + return (` + + `); + } + + visitFunction(node, name) { + const type = node.$ReturnType.$Collection ? `Collection(${node.$ReturnType.$Type})` : node.$ReturnType.$Type; + + return (` + + + + `); + } + + visitFunctionImport(node, name) { + return (` + + `); + } + + writeXml(res, data, status) { + const xml = this.visitor('document', data, '', '').replace(/\s*\s*/g, '>'); + + res.type('application/xml'); + res.status(status).send(xml); + } +} diff --git a/test/api.Function.js b/test/api.Function.js index 376bf37..7c031bf 100644 --- a/test/api.Function.js +++ b/test/api.Function.js @@ -1,14 +1,12 @@ import 'should'; import request from 'supertest'; import { odata, host, port } from './support/setup'; -import FakeDb from './support/fake-db'; describe('odata.api.Function', () => { let httpServer; before(() => { - const db = new FakeDb(); - const server = odata(db); + const server = odata(); server.function('/test', (req, res, next) => res.jsonp({ test: 'ok' })); httpServer = server.listen(port); }); diff --git a/test/api.Resource.js b/test/api.Resource.js deleted file mode 100644 index 4c583c3..0000000 --- a/test/api.Resource.js +++ /dev/null @@ -1,24 +0,0 @@ -import 'should'; -import request from 'supertest'; -import { odata, host, port, bookSchema } from './support/setup'; -import FakeDb from './support/fake-db'; - -describe('odata.api.Resouce', () => { - let httpServer; - - before(() => { - const db = new FakeDb(); - const server = odata(db); - server.resource('book', bookSchema); - httpServer = server.listen(port); - }); - - after(() => { - httpServer.close(); - }); - - it('should work', async function() { - const res = await request(host).get('/book'); - res.body.should.be.have.property('value'); - }); -}); diff --git a/test/hook.action.js b/test/hook.action.js new file mode 100644 index 0000000..6f78dd0 --- /dev/null +++ b/test/hook.action.js @@ -0,0 +1,118 @@ +import 'should'; +import 'should-sinon'; +import request from 'supertest'; +import { odata, host, port } from './support/setup'; +import sinon from 'sinon'; + +function requestToHalfPrice(id) { + return request(host).post(`/book(${id})/50off`); +} + +function halfPrice(price) { + return +(price / 2).toFixed(2); +} + +describe('hook.action', () => { + let httpServer, server; + + beforeEach(async function () { + server = odata(); + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + }); + + it('should call fn and before hook', async function () { + const callbackFn = sinon.spy(); + const action = server.action('salam-aleikum', async (req, res) => { + callbackFn(); + res.$odata.result = { result: req.hook }; + }); + + const callbackHook = sinon.spy(); + action.addBefore(async (req, res) => { + req.hook = 'data drives'; + callbackHook(); + }, 'sample-before'); + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.salam-aleikum`); + + res.body.should.deepEqual({result: 'data drives'}); + + callbackFn.should.be.callCount(1); + callbackHook.should.be.callCount(1); + }); + + it('should return error from before hook and not execute fn', async function () { + const callback = sinon.spy(); + const action = server.action('salam-aleikum', async (req, res) => { + callback(); + res.$odata.result = {result: 'authority check don`t works'}; + }); + + action.addBefore(async (req, res) => { + const error = new Error(); + + error.status = 401; + + throw error; + }, 'sample-bug-hook'); + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.salam-aleikum`); + + res.res.statusMessage.should.be.equal('Unauthorized'); + callback.should.be.callCount(0); + }); + + it('should call fn and after hook', async function () { + const callbackFn = sinon.spy(); + const action = server.action('salam-aleikum', async (req, res) => { + callbackFn(); + res.$odata.result = {result: 'data drives'}; + }); + + const callbackHook = sinon.spy(); + action.addAfter(async (req, res) => { + callbackHook(); + }, 'sample-after-hook'); + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.salam-aleikum`); + + res.body.should.deepEqual({result: 'data drives'}); + + callbackFn.should.be.callCount(1); + callbackHook.should.be.callCount(1); + }); + + it('should call next callback by using async func', async function () { + const action = server.action('salam-aleikum', async (req, res) => { + res.$odata.status = 204; + }); + + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.salam-aleikum`); + + res.res.statusMessage.should.be.equal('No Content'); + }); + + it('should works with next callback', async function () { + const action = server.action('salam-aleikum', async (req, res, next) => { + res.$odata.status = 204; + next(); + }); + + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.salam-aleikum`); + + res.res.statusMessage.should.be.equal('No Content'); + }); + +}); diff --git a/test/hook.all.after.js b/test/hook.all.after.js deleted file mode 100644 index f16e5f0..0000000 --- a/test/hook.all.after.js +++ /dev/null @@ -1,44 +0,0 @@ -import 'should'; -import 'should-sinon'; -import request from 'supertest'; -import sinon from 'sinon'; -import { odata, host, port, bookSchema, assertSuccess } from './support/setup'; -import FakeDb from './support/fake-db'; -import books from './support/books.json'; - -describe('hook.all.after', function() { - let data, httpServer, server, db; - - beforeEach(async function() { - db = new FakeDb(); - server = odata(db); - server.resource('book', bookSchema); - data = db.addData('book', books); - }); - - afterEach(() => { - httpServer.close(); - }); - - it('should work', async function() { - const callback = sinon.spy(); - server.resources.book.all().after((entity) => { - entity.should.be.have.property('title'); - callback(); - }); - httpServer = server.listen(port); - const res = await request(host).get(`/book(${data[0].id})`); - assertSuccess(res); - callback.should.be.called(); - }); - - it('should work with multiple hooks', async function() { - const callback = sinon.spy(); - server.resources.book.all().after(callback).after(callback); - httpServer = server.listen(port); - const res = await request(host).get(`/book(${data[0].id})`); - assertSuccess(res); - callback.should.be.calledTwice(); - }); -}); - diff --git a/test/hook.all.before.js b/test/hook.all.before.js deleted file mode 100644 index 6d68fce..0000000 --- a/test/hook.all.before.js +++ /dev/null @@ -1,43 +0,0 @@ -import 'should'; -import 'should-sinon'; -import request from 'supertest'; -import sinon from 'sinon'; -import { odata, host, port, bookSchema } from './support/setup'; -import FakeDb from './support/fake-db'; -import books from './support/books.json'; - -describe('hook.all.before', function() { - let data, httpServer, server, db; - - beforeEach(async function() { - db = new FakeDb(); - server = odata(db); - server.resource('book', bookSchema); - - data = db.addData('book', books); - }); - - afterEach(() => { - httpServer.close(); - }); - - it('should work', async function() { - const callback = sinon.spy(); - server.resources.book.all().before((entity, req) => { - req.params.should.be.have.property('id'); - req.params.id.should.be.equal(data[0].id); - callback(); - }); - httpServer = server.listen(port); - await request(host).get(`/book(${data[0].id})`); - callback.should.be.called(); - }); - it('should work with multiple hooks', async function() { - const callback = sinon.spy(); - server.resources.book.all().before(callback).before(callback); - httpServer = server.listen(port); - await request(host).get(`/book(${data[0].id})`); - callback.should.be.calledTwice(); - }); -}); - diff --git a/test/hook.delete.after.js b/test/hook.delete.after.js deleted file mode 100755 index e3dc0ae..0000000 --- a/test/hook.delete.after.js +++ /dev/null @@ -1,42 +0,0 @@ -import 'should'; -import 'should-sinon'; -import request from 'supertest'; -import sinon from 'sinon'; -import { odata, host, port, bookSchema, assertSuccess } from './support/setup'; -import FakeDb from './support/fake-db'; -import books from './support/books.json'; - -describe('hook.delete.after', function() { - let data, httpServer, server, db; - - beforeEach(async function() { - db = new FakeDb(); - server = odata(db); - server.resource('book', bookSchema); - - data = db.addData('book', books); - }); - - afterEach(() => { - httpServer.close(); - }); - - it('should work', async function() { - const callback = sinon.spy(); - server.resources.book.delete().after((entity) => { - callback(); - }); - httpServer = server.listen(port); - const res = await request(host).delete(`/book(${data[0].id})`); - assertSuccess(res); - callback.should.be.called(); - }); - it('should work with multiple hooks', async function() { - const callback = sinon.spy(); - server.resources.book.delete().after(callback).after(callback); - httpServer = server.listen(port); - const res = await request(host).delete(`/book(${data[0].id})`); - assertSuccess(res); - callback.should.be.calledTwice(); - }); -}); diff --git a/test/hook.delete.before.js b/test/hook.delete.before.js deleted file mode 100644 index 398ca41..0000000 --- a/test/hook.delete.before.js +++ /dev/null @@ -1,42 +0,0 @@ -import 'should'; -import 'should-sinon'; -import request from 'supertest'; -import sinon from 'sinon'; -import { odata, host, port, bookSchema } from './support/setup'; -import FakeDb from './support/fake-db'; -import books from './support/books.json'; - -describe('hook.delete.before', function() { - let data, httpServer, server, db; - - beforeEach(async function() { - db = new FakeDb(); - server = odata(db); - server.resource('book', bookSchema); - - data = db.addData('book', books); - }); - - afterEach(() => { - httpServer.close(); - }); - - it('should work', async function() { - const callback = sinon.spy(); - server.resources.book.delete().before((entity, req) => { - req.params.should.be.have.property('id'); - req.params.id.should.be.equal(data[0].id); - callback(); - }); - httpServer = server.listen(port); - await request(host).delete(`/book(${data[0].id})`); - callback.should.be.called(); - }); - it('should work with multiple hooks', async function() { - const callback = sinon.spy(); - server.resources.book.delete().before(callback).before(callback); - httpServer = server.listen(port); - await request(host).delete(`/book(${data[0].id})`); - callback.should.be.calledTwice(); - }); -}); diff --git a/test/hook.entity.after.js b/test/hook.entity.after.js new file mode 100644 index 0000000..2b7a472 --- /dev/null +++ b/test/hook.entity.after.js @@ -0,0 +1,58 @@ +import 'should'; +import 'should-sinon'; +import request from 'supertest'; +import sinon from 'sinon'; +import { odata, host, port, assertSuccess } from './support/setup'; +import { BookMetadata } from './support/books.model'; +import mongoose from 'mongoose'; + +describe('hook.entity.after', function() { + let data, httpServer, server, db; + + beforeEach(async function() { + server = odata(); + server.entity('book', { + get: (req, res, next) => { + res.$odata.result = { + title: "Test hook" + }; + next(); + } + }, BookMetadata); + }); + + afterEach(() => { + httpServer.close(); + mongoose.default.connection.close(); + }); + + it('should work', async function() { + const callback = sinon.spy(); + server.resources.book.addAfter((req, res, next) => { + res.$odata.result.should.be.have.property('title'); + res.$odata.result.title.should.be.equal("Test hook"); + callback(); + next(); + }); + httpServer = server.listen(port); + const res = await request(host).get(`/book('AFFE')`); + assertSuccess(res); + callback.should.be.called(); + }); + + it('should work with multiple hooks', async function() { + const callback = sinon.spy(); + const hook = (req, res, next) => { + callback(); + next(); + }; + + server.resources.book.addAfter(hook); + server.resources.book.addAfter(hook); + httpServer = server.listen(port); + const res = await request(host).get(`/book('AFFE')`); + assertSuccess(res); + callback.should.be.calledTwice(); + }); +}); + diff --git a/test/hook.entity.before.js b/test/hook.entity.before.js new file mode 100644 index 0000000..0dcda80 --- /dev/null +++ b/test/hook.entity.before.js @@ -0,0 +1,56 @@ +import 'should'; +import 'should-sinon'; +import request from 'supertest'; +import sinon from 'sinon'; +import { odata, host, port, assertSuccess } from './support/setup'; +import { BookMetadata } from './support/books.model'; +import mongoose from 'mongoose'; + +describe('hook.entity.before', function() { + let httpServer, server; + + beforeEach(async function() { + server = odata(); + server.entity('book', { + get: (req, res, next) => { + res.$odata.result = { + title: "Test hook" + }; + res.$odata.status = 200; + next(); + } + }, BookMetadata); + }); + + afterEach(() => { + httpServer.close(); + mongoose.default.connection.close(); + }); + + it('should work', async function() { + const callback = sinon.spy(); + server.resources.book.addBefore((req, res, next) => { + callback(); + req.$odata.$Key.should.be.have.property('id'); + req.$odata.$Key.id.should.be.equal('AFFE'); + next(); + }); + httpServer = server.listen(port); + const res = await request(host).get(`/book('AFFE')`); + assertSuccess(res); + callback.should.be.called(); + }); + it('should work with multiple hooks', async function() { + const callback = sinon.spy(); + const hook = (req, res, next) => { + callback(); + next(); + }; + server.resources.book.addBefore(hook); + server.resources.book.addBefore(hook); + httpServer = server.listen(port); + await request(host).get(`/book('AFFE')`); + callback.should.be.calledTwice(); + }); +}); + diff --git a/test/hook.get.after.js b/test/hook.get.after.js deleted file mode 100755 index 44729ab..0000000 --- a/test/hook.get.after.js +++ /dev/null @@ -1,42 +0,0 @@ -import 'should'; -import 'should-sinon'; -import request from 'supertest'; -import sinon from 'sinon'; -import { host, port, bookSchema, odata } from './support/setup'; -import FakeDb from './support/fake-db'; -import books from './support/books.json'; - -describe('hook.get.after', function() { - let data, httpServer, server, db; - - beforeEach(async function() { - db = new FakeDb(); - server = odata(db); - server.resource('book', bookSchema); - - data = db.addData('book', books); - }); - - afterEach(() => { - httpServer.close(); - }); - - it('should work', async function() { - const callback = sinon.spy(); - - server.resources.book.get().after((entity) => { - entity.should.be.have.property('title'); - callback(); - }); - httpServer = server.listen(port); - await request(host).get(`/book(${data[0].id})`); - callback.should.be.called(); - }); - it('should work with multiple hooks', async function() { - const callback = sinon.spy(); - server.resources.book.get().after(callback).after(callback); - httpServer = server.listen(port); - await request(host).get(`/book(${data[0].id})`); - callback.should.be.calledTwice(); - }); -}); diff --git a/test/hook.get.before.js b/test/hook.get.before.js deleted file mode 100644 index da74993..0000000 --- a/test/hook.get.before.js +++ /dev/null @@ -1,44 +0,0 @@ -import 'should'; -import 'should-sinon'; -import request from 'supertest'; -import sinon from 'sinon'; -import { host, port, bookSchema, odata } from './support/setup'; -import FakeDb from './support/fake-db'; -import books from './support/books.json'; - -describe('hook.get.before', function() { - let data, httpServer, server, db; - - beforeEach(async function() { - db = new FakeDb(); - server = odata(db); - server.resource('book', bookSchema); - - data = db.addData('book', books); - }); - - afterEach(() => { - httpServer.close(); - }); - - it('should work', async function() { - const callback = sinon.spy(); - - server.resources.book.get().before((entity, req) => { - req.params.should.be.have.property('id'); - req.params.id.should.be.equal(data[0].id); - callback(); - }); - httpServer = server.listen(port); - await request(host).get(`/book(${data[0].id})`); - callback.should.be.called(); - }); - it('should work with multiple hooks', async function() { - const callback = sinon.spy(); - - server.resources.book.get().before(callback).before(callback); - httpServer = server.listen(port); - await request(host).get(`/book(${data[0].id})`); - callback.should.be.calledTwice(); - }); -}); diff --git a/test/hook.list.after.js b/test/hook.list.after.js deleted file mode 100644 index c8fa335..0000000 --- a/test/hook.list.after.js +++ /dev/null @@ -1,44 +0,0 @@ -import 'should'; -import 'should-sinon'; -import request from 'supertest'; -import sinon from 'sinon'; -import { host, port, bookSchema, odata } from './support/setup'; -import FakeDb from './support/fake-db'; -import books from './support/books.json'; - -describe('hook.list.after', function() { - let data, httpServer, server, db; - - beforeEach(async function() { - db = new FakeDb(); - server = odata(db); - server.resource('book', bookSchema); - - data = db.addData('book', books); - }); - - afterEach(() => { - httpServer.close(); - }); - - it('should work', async function() { - const callback = sinon.spy(); - - server.resources.book.list().after((result) => { - result.should.be.have.property('value'); - callback(); - }); - httpServer = server.listen(port); - await request(host).get(`/book`); - callback.should.be.called(); - }); - it('should work with multiple hooks', async function() { - const callback = sinon.spy(); - - server.resources.book.list().after(callback).after(callback); - httpServer = server.listen(port); - await request(host).get(`/book`); - callback.should.be.calledTwice(); - }); -}); - diff --git a/test/hook.list.before.js b/test/hook.list.before.js deleted file mode 100644 index 3b03423..0000000 --- a/test/hook.list.before.js +++ /dev/null @@ -1,43 +0,0 @@ -import 'should'; -import 'should-sinon'; -import request from 'supertest'; -import sinon from 'sinon'; -import { host, port, bookSchema, odata } from './support/setup'; -import FakeDb from './support/fake-db'; -import books from './support/books.json'; - -describe('hook.list.before', function() { - let data, httpServer, server, db; - - beforeEach(async function() { - db = new FakeDb(); - server = odata(db); - server.resource('book', bookSchema); - - data = db.addData('book', books); - }); - - afterEach(() => { - httpServer.close(); - }); - - it('should work', async function() { - const callback = sinon.spy(); - - server.resources.book.list().before((entity, req) => { - callback(); - }); - httpServer = server.listen(port); - await request(host).get(`/book`); - callback.should.be.called(); - }); - it('should work with multiple hooks', async function() { - const callback = sinon.spy(); - - server.resources.book.list().before(callback).before(callback); - httpServer = server.listen(port); - await request(host).get(`/book`); - callback.should.be.calledTwice(); - }); -}); - diff --git a/test/hook.post.after.js b/test/hook.post.after.js deleted file mode 100755 index 5cfce20..0000000 --- a/test/hook.post.after.js +++ /dev/null @@ -1,48 +0,0 @@ -import 'should'; -import 'should-sinon'; -import request from 'supertest'; -import sinon from 'sinon'; -import { odata, host, port, bookSchema } from './support/setup'; -import FakeDb from './support/fake-db'; -import books from './support/books.json'; - -describe('hook.post.after', function() { - let data, httpServer, server, db; - - beforeEach(async function() { - db = new FakeDb(); - server = odata(db); - server.resource('book', bookSchema); - - data = db.addData('book', books); - }); - - afterEach(() => { - httpServer.close(); - }); - - it('should work', async function() { - const callback = sinon.spy(); - const TITLE = 'HOOK_POST_AFTER'; - - server.resources.book.post().after((entity) => { - entity.should.be.have.property('title'); - entity.title.should.be.equal(TITLE); - callback(); - }); - httpServer = server.listen(port); - await request(host).post(`/book`).send({ title: TITLE }); - callback.should.be.called(); - }); - it('should work with multiple hooks', async function() { - const callback = sinon.spy(); - const TITLE = 'HOOK_POST_AFTER'; - - server.resources.book.post().after(callback).after(callback); - httpServer = server.listen(port); - await request(host).post(`/book`).send({ title: TITLE }); - callback.should.be.calledTwice(); - }); -}); - - diff --git a/test/hook.post.before.js b/test/hook.post.before.js deleted file mode 100644 index 4b66594..0000000 --- a/test/hook.post.before.js +++ /dev/null @@ -1,48 +0,0 @@ -import 'should'; -import 'should-sinon'; -import request from 'supertest'; -import sinon from 'sinon'; -import { host, port, bookSchema, odata } from './support/setup'; -import FakeDb from './support/fake-db'; -import books from './support/books.json'; - -describe('hook.post.before', function() { - let data, httpServer, server, db; - - beforeEach(async function() { - db = new FakeDb(); - server = odata(db); - server.resource('book', bookSchema); - - data = db.addData('book', books); - }); - - afterEach(() => { - httpServer.close(); - }); - - it('should work', async function() { - const callback = sinon.spy(); - const TITLE = 'HOOK_POST_BEFORE'; - - server.resources.book.post().before((entity, req) => { - req.body.should.be.have.property('title'); - req.body.title.should.be.equal(TITLE); - callback(); - }); - httpServer = server.listen(port); - await request(host).post(`/book`).send({ title: TITLE }); - callback.should.be.called(); - }); - it('should work with multiple hooks', async function() { - const callback = sinon.spy(); - const TITLE = 'HOOK_POST_BEFORE'; - - server.resources.book.post().before(callback).before(callback); - httpServer = server.listen(port); - await request(host).post(`/book`).send({ title: TITLE }); - callback.should.be.calledTwice(); - }); -}); - - diff --git a/test/hook.put.after.js b/test/hook.put.after.js deleted file mode 100755 index 617bfdf..0000000 --- a/test/hook.put.after.js +++ /dev/null @@ -1,43 +0,0 @@ -import 'should'; -import 'should-sinon'; -import request from 'supertest'; -import sinon from 'sinon'; -import { host, port, bookSchema, odata } from './support/setup'; -import FakeDb from './support/fake-db'; -import books from './support/books.json'; - -describe('hook.put.after', function() { - let data, httpServer, server, db; - - beforeEach(async function() { - db = new FakeDb(); - server = odata(db); - server.resource('book', bookSchema); - - data = db.addData('book', books); - }); - - afterEach(() => { - httpServer.close(); - }); - - it('should work', async function() { - const callback = sinon.spy(); - - server.resources.book.put().after((entity) => { - entity.should.be.have.property('title'); - callback(); - }); - httpServer = server.listen(port); - await request(host).put(`/book(${data[0].id})`).send(data[0]); - callback.should.be.called(); - }); - it('should work with multiple hooks', async function() { - const callback = sinon.spy(); - - server.resources.book.put().after(callback).after(callback); - httpServer = server.listen(port); - await request(host).put(`/book(${data[0].id})`).send(data[0]); - callback.should.be.calledTwice(); - }); -}); diff --git a/test/hook.put.before.js b/test/hook.put.before.js deleted file mode 100644 index 5936888..0000000 --- a/test/hook.put.before.js +++ /dev/null @@ -1,44 +0,0 @@ -import 'should'; -import 'should-sinon'; -import request from 'supertest'; -import sinon from 'sinon'; -import { host, port, bookSchema, odata } from './support/setup'; -import FakeDb from './support/fake-db'; -import books from './support/books.json'; - -describe('hook.put.before', function() { - let data, httpServer, server, db; - - beforeEach(async function() { - db = new FakeDb(); - server = odata(db); - server.resource('book', bookSchema); - - data = db.addData('book', books); - }); - - afterEach(() => { - httpServer.close(); - }); - - it('should work', async function() { - const callback = sinon.spy(); - - server.resources.book.put().before((entity, req) => { - req.params.should.be.have.property('id'); - req.params.id.should.be.equal(data[0].id); - callback(); - }); - httpServer = server.listen(port); - await request(host).put(`/book(${data[0].id})`).send(data[0]); - callback.should.be.called(); - }); - it('should work with multiple hooks', async function() { - const callback = sinon.spy(); - - server.resources.book.put().before(callback).before(callback); - httpServer = server.listen(port); - await request(host).put(`/book(${data[0].id})`).send(data[0]); - callback.should.be.calledTwice(); - }); -}); diff --git a/test/metadata.resource.complex.js b/test/metadata.resource.complex.js deleted file mode 100644 index ecdf50b..0000000 --- a/test/metadata.resource.complex.js +++ /dev/null @@ -1,237 +0,0 @@ -// For issue: https://github.com/TossShinHwa/node-odata/issues/96 -// For issue: https://github.com/TossShinHwa/node-odata/issues/25 - -import 'should'; -import request from 'supertest'; -import { host, conn, port, odata, assertSuccess } from './support/setup'; -import FakeDb from './support/fake-db'; - -describe('metadata.resource.complex', () => { - let httpServer, server, db; - - beforeEach(async function() { - db = new FakeDb(); - server = odata(db); - }); - - afterEach(() => { - httpServer.close(); - }); - - it('should return json metadata for nested document array', async function() { - const jsonDocument = { - $Version: '4.0', - ObjectId: { - $Kind: "TypeDefinition", - $UnderlyingType: "Edm.String", - $MaxLength: 24 - }, - p1Child1: { - $Kind: 'ComplexType', - p2: { - $Type: 'Edm.String' - } - }, - 'complex-model': { - $Kind: "EntityType", - $Key: ["id"], - id: { - $Type: "self.ObjectId", - $Nullable: false, - }, - p1: { - $Type: 'self.p1Child1', - $Collection: true - } - }, - $EntityContainer: 'org.example.DemoService', - ['org.example.DemoService']: { - $Kind: 'EntityContainer', - 'complex-model': { - $Collection: true, - $Type: `self.complex-model`, - } - }, - }; - server.resource('complex-model', { - p1: [{ // array of objects - p2: String - }] - }); - httpServer = server.listen(port); - const res = await request(host).get('/$metadata?$format=json'); - assertSuccess(res); - res.body.should.deepEqual(jsonDocument); - }); - - it('should return xml metadata for nested document array', async function() { - const xmlDocument = - ` - - - - - - - - - - - - - - - - - - - - `.replace(/\s*\s*/g, '>'); - server.resource('complex-model', { - p1: [{ // array of objects - p2: String - }] - }); - httpServer = server.listen(port); - const res = await request(host).get('/$metadata').set('accept', 'application/xml'); - assertSuccess(res); - res.text.should.equal(xmlDocument); - }); - - it('should return json metadata for nested array', async function() { - const jsonDocument = { - $Version: '4.0', - ObjectId: { - $Kind: "TypeDefinition", - $UnderlyingType: "Edm.String", - $MaxLength: 24 - }, - 'complex-model': { - $Kind: "EntityType", - $Key: ["id"], - id: { - $Type: "self.ObjectId", - $Nullable: false, - }, - p3: { - $Type: 'Edm.String', - $Collection: true - } - }, - $EntityContainer: 'org.example.DemoService', - ['org.example.DemoService']: { - $Kind: 'EntityContainer', - 'complex-model': { - $Collection: true, - $Type: `self.complex-model`, - } - }, - }; - server.resource('complex-model', { - p3: [String], // array of primitive type - }); - httpServer = server.listen(port); - const res = await request(host).get('/$metadata?$format=json').set('accept', 'application/json'); - res.statusCode.should.equal(200); - res.body.should.deepEqual(jsonDocument); - }); - - it('should return xml metadata for nested array', async function() { - const xmlDocument = - ` - - - - - - - - - - - - - - - - - `.replace(/\s*\s*/g, '>'); - server.resource('complex-model', { - p3: [String] - }); - httpServer = server.listen(port); - const res = await request(host).get('/$metadata').set('accept', 'application/xml'); - assertSuccess(res); - res.text.should.equal(xmlDocument); - }); - - it('should return json metadata for nested document', async function() { - const jsonDocument = { - $Version: '4.0', - ObjectId: { - $Kind: "TypeDefinition", - $UnderlyingType: "Edm.String", - $MaxLength: 24 - }, - 'complex-model': { - $Kind: "EntityType", - $Key: ["id"], - id: { - $Type: "self.ObjectId", - $Nullable: false, - }, - 'p4.p5': { - $Type: 'Edm.String' - } - }, - $EntityContainer: 'org.example.DemoService', - ['org.example.DemoService']: { - $Kind: 'EntityContainer', - 'complex-model': { - $Collection: true, - $Type: `self.complex-model`, - } - }, - }; - server.resource('complex-model', { - p4: { - p5: String - } - }); - httpServer = server.listen(port); - const res = await request(host).get('/$metadata?$format=json'); - res.statusCode.should.equal(200); - res.body.should.deepEqual(jsonDocument); - }); - - it('should return xml metadata for nested document', async function() { - const xmlDocument = - ` - - - - - - - - - - - - - - - - - `.replace(/\s*\s*/g, '>'); - server.resource('complex-model', { - p4: { - p5: String - } - }); - httpServer = server.listen(port); - const res = await request(host).get('/$metadata'); - assertSuccess(res); - res.text.should.equal(xmlDocument); - }); -}); diff --git a/test/metadata.action..js b/test/metadata/action.js similarity index 51% rename from test/metadata.action..js rename to test/metadata/action.js index ba1e38d..d675045 100644 --- a/test/metadata.action..js +++ b/test/metadata/action.js @@ -3,15 +3,13 @@ import 'should'; import request from 'supertest'; -import { host, conn, port, odata, assertSuccess } from './support/setup'; -import FakeDb from './support/fake-db'; +import { host, port, odata, assertSuccess } from '../support/setup'; describe('metadata.action', () => { - let httpServer, server, db; + let httpServer, server; beforeEach(async function() { - db = new FakeDb(); - server = odata(db); + server = odata(); }); @@ -22,41 +20,43 @@ describe('metadata.action', () => { it('should return json metadata for action that bound to instance', async function() { const jsonDocument = { $Version: '4.0', - ObjectId: { - $Kind: "TypeDefinition", - $UnderlyingType: "Edm.String", - $MaxLength: 24 - }, 'bound-action': { $Kind: 'Action', $IsBound: true, $Parameter: [{ $Name: 'book', - $Type: 'self.book' + $Type: 'node.odata.book' }] }, - 'book': { + book: { $Kind: "EntityType", $Key: ["id"], id: { - $Type: "self.ObjectId", - $Nullable: false, + $Type: 'Edm.String', + $MaxLength: 24 }, author: { $Type: 'Edm.String' } }, - $EntityContainer: 'org.example.DemoService', - ['org.example.DemoService']: { + $EntityContainer: 'node.odata', + ['node.odata']: { $Kind: 'EntityContainer', - 'book': { + book: { $Collection: true, - $Type: `self.book`, + $Type: `node.odata.book`, } }, }; - server.resource('book', { - author: String + server.entity('book', null, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + author: { + $Type: 'Edm.String' + } }).action('bound-action', (req, res, next) => {}, { binding: 'entity' }); @@ -70,27 +70,32 @@ describe('metadata.action', () => { const xmlDocument = ` - - - + - + - + - + `.replace(/\s*\s*/g, '>'); - server.resource('book', { - author: String + server.entity('book', null, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + author: { + $Type: 'Edm.String' + } }).action('bound-action', (req, res, next) => {}, { binding: 'entity' }); @@ -103,42 +108,44 @@ describe('metadata.action', () => { it('should return json metadata for action that bound to collection', async function() { const jsonDocument = { $Version: '4.0', - ObjectId: { - $Kind: "TypeDefinition", - $UnderlyingType: "Edm.String", - $MaxLength: 24 - }, 'bound-action': { $Kind: 'Action', $IsBound: true, $Parameter: [{ $Name: 'book', - $Type: 'self.book', + $Type: 'node.odata.book', $Collection: true }] }, - 'book': { + book: { $Kind: "EntityType", $Key: ["id"], id: { - $Type: "self.ObjectId", - $Nullable: false, + $Type: 'Edm.String', + $MaxLength: 24 }, author: { $Type: 'Edm.String' } }, - $EntityContainer: 'org.example.DemoService', - ['org.example.DemoService']: { + $EntityContainer: 'node.odata', + ['node.odata']: { $Kind: 'EntityContainer', - 'book': { + book: { $Collection: true, - $Type: `self.book`, + $Type: `node.odata.book`, } }, }; - server.resource('book', { - author: String + server.entity('book', null, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + author: { + $Type: 'Edm.String' + } }).action('bound-action', (req, res, next) => {}, { binding: 'collection' }); @@ -152,27 +159,32 @@ describe('metadata.action', () => { const xmlDocument = ` - - - + - + - + - + `.replace(/\s*\s*/g, '>'); - server.resource('book', { - author: String + server.entity('book', null, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + author: { + $Type: 'Edm.String' + } }).action('bound-action', (req, res, next) => {}, { binding: 'collection' }); @@ -181,4 +193,69 @@ describe('metadata.action', () => { assertSuccess(res); res.text.should.equal(xmlDocument); }); + + it('should not accept action names with special characters', function() { + try { + const action = server.action('/login', (req, res, next) => {}); + + action.getRouter(); + + throw new Error('Invalid name should not accepted'); + + } catch(error) { + error.message.should.equal(`Invalid simple identifier '/login'`); + } + }); + + it('should return json metadata for unbound action', async function() { + const jsonDocument = { + $Version: '4.0', + 'unbound-action': { + $Kind: 'Action', + $Parameter: [{ + $Name: 'book', + $Type: 'node.odata.book' + }] + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + 'unbound-action-import': { + $Action: 'node.odata.unbound-action' + } + } + }; + server.action('unbound-action', + (req, res, next) => {}, { + $Parameter: [{ + $Name: 'book', + $Type: 'node.odata.book' + }] + }); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + assertSuccess(res); + res.body.should.deepEqual(jsonDocument); + }); + + it('should return xml metadata for action without parameter', async function() { + const xmlDocument = + ` + + + + + + + + + + `.replace(/\s*\s*/g, '>'); + server.action('unbound-action', + (req, res, next) => {}); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata').set('accept', 'application/xml'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); }); diff --git a/test/metadata/annotation.js b/test/metadata/annotation.js new file mode 100644 index 0000000..2865981 --- /dev/null +++ b/test/metadata/annotation.js @@ -0,0 +1,488 @@ +import 'should'; +import request from 'supertest'; +import { host, port, odata, assertSuccess } from '../support/setup'; +import should from 'should'; + +describe('metadata.annotations', () => { + let httpServer, server; + + beforeEach(async function () { + server = odata(); + + }); + + afterEach(() => { + httpServer.close(); + }); + + it('should return json metadata with property annotation', async function () { + const jsonDocument = { + $Version: '4.0', + readonly: { + $Kind: "Term", + $Type: "Edm.Boolean", + $AppliesTo: [ + "Property" + ], + }, + book: { + $Kind: "EntityType", + $Key: ["id"], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + author: { + $Type: 'Edm.String', + '@readonly': true + } + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + book: { + $Collection: true, + $Type: `node.odata.book`, + } + } + }; + const vocabulary = server.vocabulary(); + + vocabulary.define('readonly', 'boolean', ['Property']); + + server.entity('book', null, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + author: { + $Type: 'Edm.String', + ...vocabulary.annotate('readonly', 'Property', true) + } + }); + + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + assertSuccess(res); + res.body.should.deepEqual(jsonDocument); + }); + + it('should return xml metadata with property annotation', async function () { + const xmlDocument = + ` + + + + + + + + + + + true + + + + + + + + + `.replace(/\s*\s*/g, '>'); + const vocabulary = server.vocabulary(); + + vocabulary.define('readonly', 'boolean', ['Property']); + server.entity('book', null, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + author: { + $Type: 'Edm.String', + ...vocabulary.annotate('readonly', 'Property', true) + } + }); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata').set('accept', 'application/xml'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); + + it('should fail for not defined property annotation', async function () { + try { + const vocabulary = server.vocabulary(); + vocabulary.annotate('unknown', 'Property', true); + should.fail(false, true, 'No exception thrown'); + + } catch (err) { + err.message.should.equal(`Annotation with name 'unknown' is not defined`); + } + }); + + it('should works with later annotations', async function () { + const jsonDocument = { + $Version: '4.0', + readonly: { + $Kind: "Term", + $Type: "Edm.Boolean", + $AppliesTo: [ + "Property" + ], + }, + book: { + $Kind: "EntityType", + $Key: ["id"], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + author: { + $Type: 'Edm.String', + '@readonly': true + } + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + book: { + $Collection: true, + $Type: `node.odata.book`, + } + }, + }; + const vocabulary = server.vocabulary(); + + vocabulary.define('readonly', 'boolean', ['Property']); + + const book = server.entity('book', null, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + author: { + $Type: 'Edm.String' + } + }); + + book.annotateProperty('author', 'readonly', true); + + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + assertSuccess(res); + res.body.should.deepEqual(jsonDocument); + }); + + it('should works with action parameter annotations', async function () { + const jsonDocument = { + $Version: '4.0', + readonly: { + $Kind: "Term", + $Type: "Edm.Boolean", + $AppliesTo: [ + "Parameter" + ], + }, + 'changePassword': { + $Kind: 'Action', + $Parameter: [{ + $Type: 'Edm.String', + $Name: 'newPassword', + '@readonly': true + }, { + $Type: 'Edm.String', + $Name: 'repeat' + }] + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + 'changePassword-import': { + $Action: 'node.odata.changePassword' + } + }, + }; + const vocabulary = server.vocabulary(); + + vocabulary.define('readonly', 'boolean', ['Parameter']); + + const action = server.action('changePassword', + (req, res, next) => { }, { + $Parameter: [{ + $Type: 'Edm.String', + $Name: 'newPassword' + }, { + $Type: 'Edm.String', + $Name: 'repeat' + }] + }); + + action.annotateParameter('newPassword', 'readonly', true); + + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + assertSuccess(res); + res.body.should.deepEqual(jsonDocument); + }); + + it('should works with action parameter annotations in xml format', async function () { + const xmlDocument = + ` + + + + + + + true + + + + + + + + + + `.replace(/\s*\s*/g, '>'); + const vocabulary = server.vocabulary(); + + vocabulary.define('readonly', 'boolean', ['Parameter']); + + const action = server.action('changePassword', + (req, res, next) => { }, { + $Parameter: [{ + $Type: 'Edm.String', + $Name: 'newPassword' + }, { + $Type: 'Edm.String', + $Name: 'repeat' + }] + }); + + action.annotateParameter('newPassword', 'readonly', true); + + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=xml'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); + + + it('should works collection annotations', async function () { + const jsonDocument = { + $Version: '4.0', + fields: { + $Kind: "Term", + $AppliesTo: [ + "Action" + ], + $Collection: true + }, + 'changePassword': { + $Kind: 'Action', + $Parameter: [{ + $Type: 'Edm.String', + $Name: 'newPassword' + }, { + $Type: 'Edm.String', + $Name: 'repeat' + }], + '@fields': ['newPassword', 'repeat'] + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + 'changePassword-import': { + $Action: 'node.odata.changePassword' + } + }, + }; + const vocabulary = server.vocabulary(); + + vocabulary.define('fields', { + item: 'parameter', + type: 'string' + }, ['Action']); + + const action = server.action('changePassword', + (req, res, next) => { }, { + $Parameter: [{ + $Type: 'Edm.String', + $Name: 'newPassword' + }, { + $Type: 'Edm.String', + $Name: 'repeat' + }] + }); + + action.annotate('fields', ['newPassword', 'repeat']); + + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + assertSuccess(res); + res.body.should.deepEqual(jsonDocument); + }); + + it('should works collection annotations in xml', async function () { + const xmlDocument = + ` + + + + + + + newPassword + repeat + + + + + + + + + + + `.replace(/\s*\s*/g, '>'); + + const vocabulary = server.vocabulary(); + + vocabulary.define('fields', { + item: 'parameter', + type: 'string' + }, ['Action']); + + const action = server.action('changePassword', + (req, res, next) => { }, { + $Parameter: [{ + $Type: 'Edm.String', + $Name: 'newPassword' + }, { + $Type: 'Edm.String', + $Name: 'repeat' + }] + }); + + action.annotate('fields', ['newPassword', 'repeat']); + + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=xml'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); + + + it('should works with collection annotations on entities', async function () { + const jsonDocument = { + $Version: '4.0', + fields: { + $Kind: "Term", + $AppliesTo: [ + "Entity Type" + ], + $Collection: true + }, + book: { + $Kind: "EntityType", + $Key: ["id"], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + author: { + $Type: 'Edm.String' + }, + '@fields': ['id', 'author'] + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + book: { + $Collection: true, + $Type: `node.odata.book`, + } + } + }; + const vocabulary = server.vocabulary(); + + vocabulary.define('fields', { + item: ['property'], + type: 'string' + }, ['Entity Type']); + + const entity = server.entity('book', null, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + author: { + $Type: 'Edm.String' + } + }); + + entity.annotate('fields', ['id', 'author']); + + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + assertSuccess(res); + res.body.should.deepEqual(jsonDocument); + }); + + it('should works with collection annotations on entities in xml', async function () { + const xmlDocument = + ` + + + + + + + + + + + + id + author + + + + + + + + + `.replace(/\s*\s*/g, '>'); + + const vocabulary = server.vocabulary(); + + vocabulary.define('fields', { + item: ['property'], + type: 'string' + }, ['Entity Type']); + + const entity = server.entity('book', null, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + author: { + $Type: 'Edm.String' + } + }); + + entity.annotate('fields', ['id', 'author']); + + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=xml'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); +}); diff --git a/test/metadata/complex.type.js b/test/metadata/complex.type.js new file mode 100644 index 0000000..48e3a44 --- /dev/null +++ b/test/metadata/complex.type.js @@ -0,0 +1,77 @@ +import 'should'; +import request from 'supertest'; +import { host, port, odata, assertSuccess } from '../support/setup'; + +describe('metadata.complex.type', () => { + let httpServer, server, db; + + beforeEach(async function() { + server = odata(); + + }); + + afterEach(() => { + httpServer.close(); + }); + + it('should return explizit defined custom type in json format', async function() { + const jsonDocument = { + $Version: '4.0', + fullName: { + $Kind: "ComplexType", + first: { + $Type: "Edm.String" + }, + last: { + $Type: 'Edm.String' + } + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer' + }, + }; + server.complexType('fullName', { + first: { + $Type: 'Edm.String' + }, + last: { + $Type: 'Edm.String' + } + }); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + assertSuccess(res); + res.body.should.deepEqual(jsonDocument); + }); + + it('should return explizit defined custom type in xml format', async function() { + const xmlDocument = + ` + + + + + + + + + + + `.replace(/\s*\s*/g, '>'); + server.complexType('fullName', { + first: { + $Type: 'Edm.String' + }, + last: { + $Type: 'Edm.String' + } + }); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); + + +}); diff --git a/test/metadata/custom.resource.js b/test/metadata/custom.resource.js new file mode 100644 index 0000000..0d112bc --- /dev/null +++ b/test/metadata/custom.resource.js @@ -0,0 +1,60 @@ +// For issue: https://github.com/TossShinHwa/node-odata/issues/96 +// For issue: https://github.com/TossShinHwa/node-odata/issues/25 + +import 'should'; +import request from 'supertest'; +import { host, port, odata, assertSuccess } from '../support/setup'; + +describe('metadata.custom.resource', () => { + let httpServer, server; + + beforeEach(async function() { + server = odata(); + + }); + + afterEach(() => { + httpServer.close(); + }); + + + it('should return json metadata for custom resource', async function() { + const jsonDocument = { + $Version: '4.0', + book: { + $Kind: "EntityType", + $Key: ["id"], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + salted: { + $Type: 'Edm.Boolean' + } + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + book: { + $Collection: true, + $Type: `node.odata.book`, + } + }, + }; + server.entity('book', {}, { + $Key: ["id"], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + salted: { + $Type: 'Edm.Boolean' + } + }); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + assertSuccess(res); + res.body.should.deepEqual(jsonDocument); + }); + +}); diff --git a/test/metadata.format.js b/test/metadata/format.js similarity index 54% rename from test/metadata.format.js rename to test/metadata/format.js index f6010e8..8b89372 100644 --- a/test/metadata.format.js +++ b/test/metadata/format.js @@ -1,67 +1,59 @@ -// For issue: https://github.com/TossShinHwa/node-odata/issues/96 -// For issue: https://github.com/TossShinHwa/node-odata/issues/25 - import 'should'; import request from 'supertest'; -import { host, conn, port, bookSchema, odata, assertSuccess } from './support/setup'; -import FakeDb from './support/fake-db'; +import { host, port, odata, assertSuccess } from '../support/setup'; describe('metadata.format', () => { - let httpServer, server, db; + let httpServer, server; - const jsonDocument = { - $Version: '4.0', - ObjectId: { - $Kind: "TypeDefinition", - $UnderlyingType: "Edm.String", + const metadata = { + $Key: ["id"], + id: { + $Type: 'Edm.String', $MaxLength: 24 }, + author: { + $Type: 'Edm.String' + }, + description: { + $Type: 'Edm.String' + }, + genre: { + $Type: 'Edm.String' + }, + price: { + $Type: 'Edm.Double' + }, + publish_date: { + $Type: 'Edm.DateTimeOffset' + }, + title: { + $Type: 'Edm.String' + } + }; + const jsonDocument = { + $Version: '4.0', book: { $Kind: "EntityType", - $Key: ["id"], - id: { - $Type: "self.ObjectId", - $Nullable: false, - }, - author: { - $Type: 'Edm.String' - }, - description: { - $Type: 'Edm.String' - }, - genre: { - $Type: 'Edm.String' - }, - price: { - $Type: 'Edm.Double' - }, - publish_date: { - $Type: 'Edm.DateTimeOffset' - }, - title: { - $Type: 'Edm.String' - } + ...metadata }, - $EntityContainer: 'org.example.DemoService', - ['org.example.DemoService']: { + $EntityContainer: 'node.odata', + ['node.odata']: { $Kind: 'EntityContainer', book: { $Collection: true, - $Type: `self.book`, + $Type: `node.odata.book`, } }, }; - const xmlDocument = - ` + const xmlDocument = + ` - - - + - + @@ -70,16 +62,15 @@ describe('metadata.format', () => { - + `.replace(/\s*\s*/g, '>'); - beforeEach(async function() { - db = new FakeDb(); - server = odata(db); - server.resource('book', bookSchema); + beforeEach(async function () { + server = odata(); + server.entity('book', null, metadata); }); @@ -87,15 +78,7 @@ describe('metadata.format', () => { httpServer.close(); }); - it('should return xml if no format given', async function() { - httpServer = server.listen(port); - const res = await request(host).get('/$metadata'); - assertSuccess(res); - checkContentType(res, 'application/xml'); - res.text.should.equal(xmlDocument); - }); - - it('should return json according accept header', async function() { + it('should return json according accept header', async function () { httpServer = server.listen(port); const res = await request(host).get('/$metadata').set('accept', 'application/json'); assertSuccess(res); @@ -103,13 +86,29 @@ describe('metadata.format', () => { res.body.should.deepEqual(jsonDocument); }); - it('should return xml if $format overrides accept header', async function() { + it('should return json if $format overrides accept header', async function () { httpServer = server.listen(port); const res = await request(host).get('/$metadata?$format=json').set('accept', 'application/xml'); res.statusCode.should.equal(200); checkContentType(res, 'application/json'); res.body.should.deepEqual(jsonDocument); }); + + it('should return xml if xml has highest quality value', async function () { + httpServer = server.listen(port); + const res = await request(host).get('/$metadata').set('accept', 'application/json;q=0.9, application/xml'); + res.statusCode.should.equal(200); + checkContentType(res, 'application/xml'); + res.text.should.equal(xmlDocument); + }); + + it('should return xml if xml and json matched with asterix', async function () { + httpServer = server.listen(port); + const res = await request(host).get('/$metadata').set('accept', '*/*'); + res.statusCode.should.equal(200); + checkContentType(res, 'application/xml'); + res.text.should.equal(xmlDocument); + }); }); diff --git a/test/metadata.function.js b/test/metadata/function.js similarity index 67% rename from test/metadata.function.js rename to test/metadata/function.js index 5a81520..061c7c2 100644 --- a/test/metadata.function.js +++ b/test/metadata/function.js @@ -1,17 +1,12 @@ -// For issue: https://github.com/TossShinHwa/node-odata/issues/96 -// For issue: https://github.com/TossShinHwa/node-odata/issues/25 - import 'should'; import request from 'supertest'; -import { host, conn, port, odata, assertSuccess } from './support/setup'; -import FakeDb from './support/fake-db'; +import { host, port, odata, assertSuccess } from '../support/setup'; describe('metadata.function', () => { - let httpServer, server, db; + let httpServer, server; beforeEach(async function() { - db = new FakeDb(); - server = odata(db); + server = odata(); }); @@ -22,22 +17,17 @@ describe('metadata.function', () => { it('should return json metadata for function', async function() { const jsonDocument = { $Version: '4.0', - ObjectId: { - $Kind: "TypeDefinition", - $UnderlyingType: "Edm.String", - $MaxLength: 24 - }, 'odata-function': { $Kind: 'Function', $ReturnType: { $Type: 'Edm.String' } }, - $EntityContainer: 'org.example.DemoService', - ['org.example.DemoService']: { + $EntityContainer: 'node.odata', + ['node.odata']: { $Kind: 'EntityContainer', 'odata-function': { - $Function: 'self.odata-function' + $Function: 'node.odata.odata-function' } }, }; @@ -57,14 +47,12 @@ describe('metadata.function', () => { const xmlDocument = ` - - - + - + diff --git a/test/metadata/singleton.js b/test/metadata/singleton.js new file mode 100644 index 0000000..c5e6dc5 --- /dev/null +++ b/test/metadata/singleton.js @@ -0,0 +1,102 @@ +import 'should'; +import request from 'supertest'; +import { host, port, odata, assertSuccess } from '../support/setup'; +import { BookMetadata } from '../support/books.model'; + +describe('metadata.singleton', () => { + let httpServer, server; + + beforeEach(async function() { + server = odata(); + + }); + + afterEach(() => { + httpServer.close(); + }); + + it('[json] should render entity type if only singleton defined', async function() { + const jsonDocument = { + $Version: '4.0', + book: { + $Kind: "EntityType", + ...BookMetadata + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + book: { + $Type: `node.odata.book` + } + }, + }; + server.singleton('book', {}, BookMetadata); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + assertSuccess(res); + res.body.should.deepEqual(jsonDocument); + }); + + it('[xml] should render entity type if only singleton defined', async function() { + const xmlDocument = + ` + + + + + + + + + + + + + + + + + + + + + `.replace(/\s*\s*/g, '>'); + + server.singleton('book', {}, BookMetadata); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); + + + + it('[json] should render entity type once', async function() { + const jsonDocument = { + $Version: '4.0', + book: { + $Kind: "EntityType", + ...BookMetadata + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + book: { + $Collection: true, + $Type: `node.odata.book` + }, + "current-book": { + $Type: `node.odata.book` + } + }, + }; + const bookEntity = server.entity('book', null, BookMetadata); + server.singletonFrom('current-book', null, bookEntity); + httpServer = server.listen(port); + + const res = await request(host).get('/$metadata?$format=json'); + + assertSuccess(res); + res.body.should.deepEqual(jsonDocument); + }); +}); diff --git a/test/mimetype.defaults.js b/test/mimetype.defaults.js new file mode 100644 index 0000000..bee9ced --- /dev/null +++ b/test/mimetype.defaults.js @@ -0,0 +1,45 @@ +import 'should'; +import request from 'supertest'; +import { host, port, odata, assertSuccess } from './support/setup'; +import { BookMetadata } from './support/books.model'; + +describe('mimetype.defaults', () => { + let httpServer, server; + + beforeEach(async function() { + server = odata(); + server.entity('book', { + list: (req, res, next) => { + res.$odata.result = { + value: [] + }; + next(); + } + }, BookMetadata); + + }); + + afterEach(() => { + httpServer.close(); + }); + + it('should return xml if no format given for metadata request', async function() { + httpServer = server.listen(port); + const res = await request(host).get('/$metadata'); + assertSuccess(res); + checkContentType(res, 'application/xml'); + }); + + it('should return json if no format given for data request', async function() { + httpServer = server.listen(port); + const res = await request(host).get('/book'); + assertSuccess(res); + checkContentType(res, 'application/json'); + }); +}); + + +function checkContentType(res, value) { + res.header.should.have.property('content-type'); + res.header['content-type'].should.containEql(value); +} \ No newline at end of file diff --git a/test/model.complex.action.js b/test/model.complex.action.js deleted file mode 100644 index c691519..0000000 --- a/test/model.complex.action.js +++ /dev/null @@ -1,52 +0,0 @@ -// For issue: https://github.com/TossShinHwa/node-odata/issues/69 - -import 'should'; -import request from 'supertest'; -import { odata, host, port, assertSuccess } from './support/setup'; -import FakeDb from './support/fake-db'; - -describe('model.complex.action', () => { - let httpServer; - - before(() => { - const db = new FakeDb(); - const server = odata(db); - const resource = server.resource('order', { product: [{ price: Number }] }); - - resource.action('/all-item-greater', (req, res, next) => { - const { price } = req.query; - const $elemMatch = { price: { $gt: price } }; - server.resources.order.model.exec((err, data) => res.jsonp(data.slice(1))); - }, { binding : 'collection' }); - httpServer = server.listen(port); - }); - - after(() => { - httpServer.close(); - }); - - it('should work when PUT a complex entity', async function () { - const entities = [{ - product: [ - { price: 1 }, - { price: 2 }, - { price: 4 }, - ], - }, { - product: [ - { price: 32 }, - { price: 64 }, - { price: 99 }, - ], - }]; - entities.forEach(async entity => await request(host).post('/order').send(entity)); - - const res = await request(host).post(`/order/all-item-greater`); - assertSuccess(res); - res.body.should.matchEach((item) => { - return item.product[0].price > 30 - && item.product[1].price > 30 - && item.product[2].price > 30; - }); - }); -}); diff --git a/test/model.complex.filter.js b/test/model.complex.filter.js deleted file mode 100644 index 325038a..0000000 --- a/test/model.complex.filter.js +++ /dev/null @@ -1,34 +0,0 @@ -// For issue: https://github.com/TossShinHwa/node-odata/issues/69 - -import 'should'; -import 'should-sinon'; -import request from 'supertest'; -import { odata, assertSuccess, host, port } from './support/setup'; -import Db from './support/fake-db'; -import sinon from 'sinon'; - -describe('model.complex.filter', () => { - let httpServer, db, mock; - - before(() => { - db = new Db(); - const server = odata(db); - const resource = server.resource('complex-model-filter', { product: [{ price: Number }] }); - - mock = sinon.mock(resource.model); - mock.expects('where').once().withArgs('product.price').returns(resource.model); - mock.expects('gt').once().withArgs(30).returns(resource.model); - httpServer = server.listen(port); - }); - - after(() => { - httpServer.close(); - }); - - it('should work when PUT a complex entity', async function() { - const res = await request(host).get(`/complex-model-filter?$filter=product.price gt 30`); - - assertSuccess(res); - mock.verify(); - }); -}); diff --git a/test/model.complex.js b/test/model.complex.js deleted file mode 100644 index 4c315c8..0000000 --- a/test/model.complex.js +++ /dev/null @@ -1,45 +0,0 @@ -// For issue: https://github.com/TossShinHwa/node-odata/issues/55 - -import 'should'; -import request from 'supertest'; -import { odata, host, port } from './support/setup'; -import FakeDb from './support/fake-db'; - -function addResource() { - return request(host) - .post('/complex-model') - .send({ p1: [{ p2: 'origin' }] }); -} - -function updateResouce(id) { - return request(host) - .put(`/complex-model(${id})`) - .send({ p1: [{ p2: 'new' }] }); -} - -function queryResource(id) { - return request(host) - .get(`/complex-model(${id})`); -} - -describe('model.complex', () => { - let httpServer; - - before(() => { - const db = new FakeDb(); - const server = odata(db); - server.resource('complex-model', { p1: [{ p2: String }] }); - httpServer = server.listen(port); - }); - - after(() => { - httpServer.close(); - }); - - it('should work when PUT a complex entity', async function() { - const entity = await addResource(); - await updateResouce(entity.body.id); - const res = await queryResource(entity.body.id); - res.body.p1[0].p2.should.be.equal('new'); - }); -}); diff --git a/test/model.custom.id.js b/test/model.custom.id.js deleted file mode 100644 index f5702b8..0000000 --- a/test/model.custom.id.js +++ /dev/null @@ -1,30 +0,0 @@ -import 'should'; -import request from 'supertest'; -import fakeDb from './support/fake-db'; -import { odata, host, port } from './support/setup'; - -describe('model.custom.id', () => { - let httpServer; - - before(async function() { - const db = new fakeDb(); - const server = odata(db); - server.resource('custom-id', { id: Number }); - httpServer = server.listen(port); - await request(host).post('/custom-id').send({ id: 100 }); - }); - - after(() => { - httpServer.close(); - }); - - it('should work when use a custom id to query specific entity', async function() { - const res = await request(host).get('/custom-id(100)'); - res.body.id.should.be.equal(100); - }); - - it('should work when use a custom id to query a list', async function() { - const res = await request(host).get('/custom-id?$filter=id eq \'100\''); - res.body.value.length.should.be.greaterThan(0); - }); -}); diff --git a/test/model.hidden.field.js b/test/model.hidden.field.js deleted file mode 100644 index eee41cc..0000000 --- a/test/model.hidden.field.js +++ /dev/null @@ -1,52 +0,0 @@ -import 'should'; -import sinon from 'sinon'; -import request from 'supertest'; -import FakeDb from './support/fake-db'; -import { odata, host, port } from './support/setup'; - -describe('model.hidden.field', function () { - let httpServer, id, resource, mock; - - before(async function () { - const db = new FakeDb(); - const server = odata(db); - resource = server.resource('hidden-field', { - name: String, - password: { - type: String, - select: false - } - }); - httpServer = server.listen(port); - const data = db.addData('hidden-field', [{ - name: 'zack', - password: '123' - }]); - id = data[0].id; - }); - - after(() => { - httpServer.close(); - }); - - afterEach(() => { - mock.restore(); - }); - - it('should work when get entities list even it is selected', async function () { - mock = sinon.mock(resource.model); - mock.expects('select').once().withArgs({ - _id: 0, - name: 1 - }).returns(resource.model); - await request(host).get('/hidden-field?$select=name, password'); - mock.verify(); - }); - - it('should work when get entities list even only it is selected', async function () { - mock = sinon.mock(resource.model); - mock.expects('select').never().returns(resource.model); - await request(host).get('/hidden-field?$select=password'); - mock.verify(); - }); -}); diff --git a/test/model.special.name.js b/test/model.special.name.js deleted file mode 100644 index 9f31649..0000000 --- a/test/model.special.name.js +++ /dev/null @@ -1,26 +0,0 @@ -import 'should'; -import request from 'supertest'; -import { odata, host, port } from './support/setup'; -import FakeDb from './support/fake-db'; - -describe('model.special.name', () => { - let httpServer; - - before(() => { - const db = new FakeDb(); - const server = odata(db); - server.resource('funcion-keyword', { year: Number }); - httpServer = server.listen(port); - }); - - after(() => { - httpServer.close(); - }); - - it('should work when use odata function keyword', async function() { - const res = await request(host) - .post('/funcion-keyword') - .send({ year: 2015 }); - res.status.should.be.equal(201); - }); -}); diff --git a/test/mongo/connected/error.js b/test/mongo/connected/error.js new file mode 100644 index 0000000..52349fd --- /dev/null +++ b/test/mongo/connected/error.js @@ -0,0 +1,57 @@ +import 'should'; +import request from 'supertest'; +import { host, port, odata } from '../../support/setup'; +import mongoose from 'mongoose'; +import { connect } from '../../support/db'; + +const Schema = mongoose.Schema; + +describe('mongo.error', () => { + let httpServer, server; + + before(() => { + mongoose.set('overwriteModels', true); + }) + + beforeEach(async function() { + server = odata(); + + }); + + afterEach(() => { + httpServer.close(); + mongoose.default.connection.close(); + }); + + it('should return 400 for mongo validation errors', async function() { + const result = { + error: { + code: "400", + message: "Path `password` (`ggm`) is shorter than the minimum allowed length (8).", + target: "password" + } + }; + const UserSchema = new Schema({ + email: { + type: String + }, + password: { + type: String, + minLength: 8 + }, + }); + + const UserModel = mongoose.model('User', UserSchema); + + server.mongoEntity('User', UserModel); + await connect(server); + httpServer = server.listen(port); + + const res = await request(host) + .post(`/User`) + .send({ password: 'ggm' }); + + res.body.should.deepEqual(result); + }); + +}); diff --git a/test/mongo/connected/model.complex.js b/test/mongo/connected/model.complex.js new file mode 100644 index 0000000..b74d50a --- /dev/null +++ b/test/mongo/connected/model.complex.js @@ -0,0 +1,54 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from '../../support/setup'; +import mongoose from 'mongoose'; +import { connect } from '../../support/db'; + +const Schema = mongoose.Schema; + +function addResource() { + return request(host) + .post('/complex-model') + .send({ p1: [{ p2: 'origin' }] }); +} + +function updateResouce(id) { + return request(host) + .put(`/complex-model('${id}')`) + .send({ p1: [{ p2: 'new' }] }); +} + +function queryResource(id) { + return request(host) + .get(`/complex-model('${id}')`); +} + +describe('mongo.connected.model.complex', () => { + let httpServer; + + before(() => { + const server = odata(); + const ComplexModelSchema = new Schema({ p1: [{ p2: String }] }); + + const ComplexModel = mongoose.model('p1', ComplexModelSchema); + server.mongoEntity('complex-model', ComplexModel); + connect(server); + httpServer = server.listen(port); + }); + + after(() => { + httpServer.close(); + mongoose.default.connection.close(); + }); + + it('should work when PUT a complex entity', async function() { + const entity = await addResource(); + entity.body.should.have.property('id'); + assertSuccess(entity) + let res = await updateResouce(entity.body.id); + assertSuccess(res); + res = await queryResource(entity.body.id); + assertSuccess(res); + res.body.p1[0].p2.should.be.equal('new'); + }); +}); diff --git a/test/mongo/connected/model.hidden.field.js b/test/mongo/connected/model.hidden.field.js new file mode 100644 index 0000000..aa4179c --- /dev/null +++ b/test/mongo/connected/model.hidden.field.js @@ -0,0 +1,46 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port } from '../../support/setup'; +import mongoose from 'mongoose'; +import { init } from '../../support/db'; + +const Schema = mongoose.Schema; + +describe('mongo.connected.model.hidden.field', function () { + let httpServer, Model; + + before(async function () { + const server = odata(); + + const ModelSchema = new Schema({ + name: String, + password: { + type: String, + select: false + } + }); + + Model = mongoose.model('hidden-field', ModelSchema); + + server.mongoEntity('hidden-field', Model); + init(server); + + httpServer = server.listen(port); + + }); + + after(() => { + httpServer.close(); + }); + + it('should fail because a property is requested that is not visible', async function () { + const res = await request(host).get('/hidden-field?$select=name, password'); + + res.should.have.property('error'); + res.error.should.not.be.equal(false); + res.body.error.code.should.be.equal('400'); + res.body.error.message.should.be.equal(`Entity 'hidden-field' has no property named 'password'`); + + }); + +}); diff --git a/test/mongo/connected/model.special.name.js b/test/mongo/connected/model.special.name.js new file mode 100644 index 0000000..b895903 --- /dev/null +++ b/test/mongo/connected/model.special.name.js @@ -0,0 +1,34 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from '../../support/setup'; +import mongoose from 'mongoose'; +import { connect } from '../../support/db'; + +const Schema = mongoose.Schema; + +describe('model.special.name', () => { + let httpServer; + + before(() => { + const server = odata(); + const ModelSchema = new Schema({ year: Number }); + + const Model = mongoose.model('function-keyword', ModelSchema); + server.mongoEntity('function-keyword', Model); + connect(server); + httpServer = server.listen(port); + }); + + after(() => { + httpServer.close(); + mongoose.default.connection.close(); + }); + + it('should work when use odata function keyword', async function() { + const res = await request(host) + .post('/function-keyword') + .send({ year: 2015 }); + assertSuccess(res); + res.status.should.be.equal(201); + }); +}); diff --git a/test/mongo/connected/rest.list.js b/test/mongo/connected/rest.list.js new file mode 100644 index 0000000..52dfb3f --- /dev/null +++ b/test/mongo/connected/rest.list.js @@ -0,0 +1,29 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port } from '../../support/setup'; +import mongoose from 'mongoose'; +import { connect } from '../../support/db'; +import { BookModel } from '../../support/books.model'; + +describe('mongo.connected.rest.list', () => { + let httpServer + + before(() => { + const server = odata(); + + server.mongoEntity('book', BookModel); + connect(server); + + httpServer = server.listen(port); + }); + + after(() => { + httpServer.close(); + mongoose.default.connection.close(); + }); + + it('should work', async function () { + const res = await request(host).get('/book'); + res.body.should.be.have.property('value'); + }); +}); diff --git a/test/rest.post.js b/test/mongo/connected/rest.post.js similarity index 53% rename from test/rest.post.js rename to test/mongo/connected/rest.post.js index 6a4b6c1..af03e03 100644 --- a/test/rest.post.js +++ b/test/mongo/connected/rest.post.js @@ -1,26 +1,32 @@ import 'should'; import request from 'supertest'; -import { odata, host, port, bookSchema } from './support/setup'; -import FakeDb from './support/fake-db'; +import { odata, host, port } from '../../support/setup'; +import { connect } from '../../support/db'; +import mongoose from 'mongoose'; +import { BookModel } from '../../support/books.model'; describe('rest.post', () => { - let httpServer; + let httpServer, server; - before(async function() { - const db = new FakeDb(); - const server = odata(db); - server.resource('book', bookSchema) + before(function() { + server = odata(); + server.mongoEntity('book', BookModel); + connect(server); httpServer = server.listen(port); }); after(() => { httpServer.close(); + mongoose.default.connection.close(); }); it('should create new resource', async function() { const res = await request(host) .post(`/book`) - .send({ title: Math.random() }); + .send({ title: 'rest.post.js' }); + if (!res.ok) { + res.text.should.equal(''); + } res.body.should.be.have.property('id'); res.body.should.be.have.property('title'); }); diff --git a/test/mongo/metadata.js b/test/mongo/metadata.js new file mode 100644 index 0000000..7a67949 --- /dev/null +++ b/test/mongo/metadata.js @@ -0,0 +1,386 @@ +import 'should'; +import request from 'supertest'; +import { host, port, odata, assertSuccess } from '../support/setup'; +import mongoose from 'mongoose'; +import { BookModel } from '../support/books.model'; + +const Schema = mongoose.Schema; + +describe('mongo.metadata', () => { + let httpServer, server; + + before(() => { + mongoose.set('overwriteModels', true); + }) + + beforeEach(async function() { + server = odata(); + + }); + + afterEach(() => { + httpServer.close(); + }); + + it('should return json metadata and ignore unknown attributes', async function() { + const jsonDocument = { + $Version: '4.0', + book: { + $Kind: "EntityType", + $Key: ["id"], + id: { + $Type: 'Edm.String', + $MaxLength: 24, + $Nullable: true + }, + price: { + $Type: 'Edm.Double', + $Nullable: true + }, + author: { + $Type: 'Edm.String' + } + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + book: { + $Collection: true, + $Type: `node.odata.book`, + } + }, + }; + const BookSchema = new Schema({ + price: { + type: Number, + min: 1, + max: 300 + }, + author: { + type: String, + required: true, + trim:true, + unique: true, + minLength: 2, + match: [/[a-z]+/, 'It must containatleast one lowercase letter'], + validate: [{ + validator: (value) => value.match(/[A-Z]+/), + msg: 'It must contain at least one capital letter' + }] + } + }); + + const CustomBookModel = mongoose.model('book', BookSchema); + + server.mongoEntity('book', CustomBookModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + assertSuccess(res); + res.body.should.deepEqual(jsonDocument); + }); + + it('should return xml metadata and ignore unknown attributes', async function() { + const xmlDocument = + ` + + + + + + + + + + + + + + + + `.replace(/\s*\s*/g, '>'); + const BookSchema = new Schema({ + price: { + type: Number, + min: 1, + max: 300 + }, + author: { + type: String, + required: true, + minLength: 2, + match: [/[a-z]+/, 'It must containatleast one lowercase letter'], + validate: [{ + validator: (value) => value.match(/[A-Z]+/), + msg: 'It must contain at least one capital letter' + }] + } + }); + + const CustomBookModel = mongoose.model('book', BookSchema); + + server.mongoEntity('book', CustomBookModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); + + it('should return json metadata with maxLength attribute', async function() { + const jsonDocument = { + $Version: '4.0', + book: { + $Kind: "EntityType", + $Key: ["id"], + id: { + $Type: 'Edm.String', + $MaxLength: 24, + $Nullable: true + }, + author: { + $Type: 'Edm.String', + $MaxLength: 25, + $Nullable: true + } + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + book: { + $Collection: true, + $Type: `node.odata.book`, + } + }, + }; + const BookSchema = new Schema({ + author: { + type: String, + maxLength: 25 + } + }); + + const CustomBookModel = mongoose.model('book', BookSchema); + + server.mongoEntity('book', CustomBookModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + assertSuccess(res); + res.body.should.deepEqual(jsonDocument); + }); + + it('should return xml metadata with maxLength attribute', async function() { + const xmlDocument = + ` + + + + + + + + + + + + + + + `.replace(/\s*\s*/g, '>'); + const BookSchema = new Schema({ + author: { + type: String, + maxLength: 25 + } + }); + + const CustomBookModel = mongoose.model('book', BookSchema); + + server.mongoEntity('book', CustomBookModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); + + it('should return json metadata with default value attribute', async function() { + const jsonDocument = { + $Version: '4.0', + book: { + $Kind: "EntityType", + $Key: ["id"], + id: { + $Type: 'Edm.String', + $MaxLength: 24, + $Nullable: true + }, + author: { + $Type: 'Edm.String', + $DefaultValue: "William Shakespeare", + $Nullable: true + } + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + book: { + $Collection: true, + $Type: `node.odata.book`, + } + }, + }; + const BookSchema = new Schema({ + author: { + type: String, + default: 'William Shakespeare' + } + }); + + const CustomBookModel = mongoose.model('book', BookSchema); + + server.mongoEntity('book', CustomBookModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + assertSuccess(res); + res.body.should.deepEqual(jsonDocument); + }); + + it('should return xml metadata with default value attribute', async function() { + const xmlDocument = + ` + + + + + + + + + + + + + + + `.replace(/\s*\s*/g, '>'); + const BookSchema = new Schema({ + author: { + type: String, + default: 'William Shakespeare' + } + }); + + const CustomBookModel = mongoose.model('book', BookSchema); + + server.mongoEntity('book', CustomBookModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); + + it('should return json metadata with boolean property', async function() { + const jsonDocument = { + $Version: '4.0', + book: { + $Kind: "EntityType", + $Key: ["id"], + id: { + $Type: 'Edm.String', + $MaxLength: 24, + $Nullable: true + }, + salted: { + $Type: 'Edm.Boolean', + $Nullable: true + } + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + book: { + $Collection: true, + $Type: `node.odata.book`, + } + }, + }; + const BookSchema = new Schema({ + salted: { + type: Boolean + } + }); + + const CustomBookModel = mongoose.model('book', BookSchema); + + server.mongoEntity('book', CustomBookModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + assertSuccess(res); + res.body.should.deepEqual(jsonDocument); + }); + + it('should return xml metadata with boolean property', async function() { + const xmlDocument = + ` + + + + + + + + + + + + + + + `.replace(/\s*\s*/g, '>'); + const BookSchema = new Schema({ + salted: { + type: Boolean + } + }); + + const CustomBookModel = mongoose.model('book', BookSchema); + + server.mongoEntity('book', CustomBookModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); + + + it('should render timestamps as nullable for singleton', async function() { + const xmlDocument = + ` + + + + + + + + + + + + + + + + + + + + + + `.replace(/\s*\s*/g, '>'); + + server.mongoSingleton('book', BookModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); +}); diff --git a/test/mongo/metadata.resource.complex.js b/test/mongo/metadata.resource.complex.js new file mode 100644 index 0000000..d73ce8c --- /dev/null +++ b/test/mongo/metadata.resource.complex.js @@ -0,0 +1,473 @@ +import 'should'; +import request from 'supertest'; +import { host, port, odata, assertSuccess } from '../support/setup'; +import mongoose from 'mongoose'; + +const Schema = mongoose.Schema; + +describe('mongo.metadata.resource.complex', () => { + let httpServer, server; + + before(() => { + mongoose.set('overwriteModels', true); + }) + + beforeEach(async function () { + server = odata(); + }); + + afterEach(() => { + httpServer.close(); + }); + + it('should return json metadata for nested document array', async function () { + const jsonDocument = { + $Version: '4.0', + "complex-modelp1Child1": { + $Kind: 'ComplexType', + id: { + $Type: 'Edm.String', + $MaxLength: 24, + $Nullable: true + }, + p2: { + $Type: 'Edm.String', + $Nullable: true + } + }, + 'complex-model': { + $Kind: "EntityType", + $Key: ["id"], + id: { + $Type: 'Edm.String', + $MaxLength: 24, + $Nullable: true + }, + p1: { + $Type: 'node.odata.complex-modelp1Child1', + $Collection: true, + $Nullable: true + } + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + 'complex-model': { + $Collection: true, + $Type: `node.odata.complex-model`, + } + }, + }; + const ComplexModelSchema = new Schema({ + p1: [{ // array of objects + p2: String + }] + }); + + const ComplexModel = mongoose.model('complex-model', ComplexModelSchema); + server.mongoEntity('complex-model', ComplexModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + assertSuccess(res); + res.body.should.deepEqual(jsonDocument); + }); + + it('should return xml metadata for nested document array', async function () { + const xmlDocument = + ` + + + + + + + + + + + + + + + + + + + `.replace(/\s*\s*/g, '>'); + const ComplexModelSchema = new Schema({ + p1: [{ // array of objects + p2: String + }] + }); + + const ComplexModel = mongoose.model('complex-model', ComplexModelSchema); + server.mongoEntity('complex-model', ComplexModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata').set('accept', 'application/xml'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); + + it('should return json metadata for nested array', async function () { + const jsonDocument = { + $Version: '4.0', + 'complex-model': { + $Kind: "EntityType", + $Key: ["id"], + id: { + $Type: 'Edm.String', + $MaxLength: 24, + $Nullable: true + }, + p3: { + $Type: 'Edm.String', + $Collection: true, + $Nullable: true + } + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + 'complex-model': { + $Collection: true, + $Type: `node.odata.complex-model`, + } + }, + }; + const ComplexModelSchema = new Schema({ + p3: [String] // array of primitive type + }); + + const ComplexModel = mongoose.model('complex-model', ComplexModelSchema); + server.mongoEntity('complex-model', ComplexModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json').set('accept', 'application/json'); + res.statusCode.should.equal(200); + res.body.should.deepEqual(jsonDocument); + }); + + it('should return xml metadata for nested array', async function () { + const xmlDocument = + ` + + + + + + + + + + + + + + + `.replace(/\s*\s*/g, '>'); + const ComplexModelSchema = new Schema({ + p3: [String] // array of primitive type + }); + + const ComplexModel = mongoose.model('complex-model', ComplexModelSchema); + server.mongoEntity('complex-model', ComplexModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata').set('accept', 'application/xml'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); + + + it('should return xml metadata for nested enum array', async function () { + const xmlDocument = + ` + + + + + + + + + + + + + + + `.replace(/\s*\s*/g, '>'); + const ComplexModelSchema = new Schema({ + p3: [{ + type: String, + enum: ['P4'] + }] + }); + + const ComplexModel = mongoose.model('complex-model', ComplexModelSchema); + server.mongoEntity('complex-model', ComplexModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata').set('accept', 'application/xml'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); + + + it('should return json metadata for nested document in document', async function () { + const jsonDocument = { + $Version: '4.0', + "complex-modelp4Child1": { + $Kind: 'ComplexType', + p5: { + $Type: 'Edm.String', + $Nullable: true + } + }, + 'complex-model': { + $Kind: "EntityType", + $Key: ["id"], + id: { + $Type: 'Edm.String', + $MaxLength: 24, + $Nullable: true + }, + p4: { + $Type: 'node.odata.complex-modelp4Child1' + } + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + 'complex-model': { + $Collection: true, + $Type: `node.odata.complex-model`, + } + }, + }; + const ComplexModelSchema = new Schema({ + p4: { + p5: String + } + }); + + const ComplexModel = mongoose.model('complex-model', ComplexModelSchema); + server.mongoEntity('complex-model', ComplexModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + res.statusCode.should.equal(200); + res.body.should.deepEqual(jsonDocument); + }); + + it('should return xml metadata for nested document in document', async function () { + const xmlDocument = + ` + + + + + + + + + + + + + + + + + + `.replace(/\s*\s*/g, '>'); + const ComplexModelSchema = new Schema({ + p4: { + p5: String + } + }); + + const ComplexModel = mongoose.model('complex-model', ComplexModelSchema); + server.mongoEntity('complex-model', ComplexModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); + + it('should return json metadata for nested document in array', async function () { + const jsonDocument = { + $Version: '4.0', + p1p2Child1: { + $Kind: "ComplexType", + p3: { + $Type: 'Edm.String', + $Nullable: true + }, + p4: { + $Type: "node.odata.p1p4Child2" + }, + id: { + $Type: 'Edm.String', + $MaxLength: 24, + $Nullable: true + } + }, + p1p4Child2: { + $Kind: "ComplexType", + p5: { + $Type: 'Edm.String', + $Nullable: true + } + }, + p1: { + $Kind: "EntityType", + $Key: ["id"], + id: { + $Type: 'Edm.String', + $MaxLength: 24, + $Nullable: true + }, + p2: { + $Type: 'node.odata.p1p2Child1', + $Collection: true, + $Nullable: true + } + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + p1: { + $Collection: true, + $Type: `node.odata.p1`, + } + }, + }; + const ComplexModelSchema = new Schema({ + p2: [{ + p3: String, + p4: { + p5: String + } + }] + }); + + const ComplexModel = mongoose.model('p1', ComplexModelSchema); + server.mongoEntity('p1', ComplexModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata?$format=json'); + res.statusCode.should.equal(200); + res.body.should.deepEqual(jsonDocument); + }); + + it('should return xml metadata for nested document in document', async function () { + const xmlDocument = + ` + + + + + + + + + + + + + + + + + + + + + + + `.replace(/\s*\s*/g, '>'); + const ComplexModelSchema = new Schema({ + p2: [{ + p3: String, + p4: { + p5: String + } + }] + }); + + const ComplexModel = mongoose.model('p1', ComplexModelSchema); + server.mongoEntity('p1', ComplexModel); + httpServer = server.listen(port); + const res = await request(host).get('/$metadata'); + assertSuccess(res); + res.text.should.equal(xmlDocument); + }); + + it('should use mapping if given', async function () { + const jsonDocument = { + $Version: '4.0', + myComlexType: { + $Kind: "ComplexType", + id: { + $Type: 'Edm.String', + $MaxLength: 24, + $Nullable: true + }, + p3: { + $Type: 'Edm.String' + } + }, + p1: { + $Kind: "EntityType", + $Key: ["id"], + id: { + $Type: 'Edm.String', + $MaxLength: 24, + $Nullable: true + }, + p2: { + $Type: 'node.odata.myComlexType' + } + }, + $EntityContainer: 'node.odata', + ['node.odata']: { + $Kind: 'EntityContainer', + p1: { + $Collection: true, + $Type: `node.odata.p1`, + } + }, + }; + const ComplexModelSchema = new Schema({ + p2: { + p3: String + } + }); + + const ComplexModel = mongoose.model('p1', ComplexModelSchema); + server.complexType('myComlexType', { + id: { + $Type: 'Edm.String', + $MaxLength: 24, + $Nullable: true + }, + p3: { + $Type: 'Edm.String' + } + }); + const entity = server.mongoEntity('p1', ComplexModel, undefined, undefined, undefined, false); + + entity.mapping = { + ...entity.mapping, + p2: { + intern: 'p2', + attributes: { + $Type: 'node.odata.myComlexType' + } + } + }; + entity.update + httpServer = server.listen(port); + + const res = await request(host).get('/$metadata?$format=json'); + + res.statusCode.should.equal(200); + res.body.should.deepEqual(jsonDocument); + }); +}); diff --git a/test/mongo/mocked/client/base.js b/test/mongo/mocked/client/base.js new file mode 100644 index 0000000..834face --- /dev/null +++ b/test/mongo/mocked/client/base.js @@ -0,0 +1,70 @@ +import 'should'; +import request from 'supertest'; +import sinon from 'sinon'; +import { odata, host, port, assertSuccess } from '../../../support/setup'; +import mongoose from 'mongoose'; +import { init } from '../../../support/db'; + +describe('mongo.mocked.client.base', () => { + let httpServer, server, modelMock, instanceMock, queryMock, query, Model; + + before(() => { + const Schema = mongoose.Schema; + const ModelSchema = new Schema({ + client: Number + }); + + mongoose.set('overwriteModels', true); + + + Model = mongoose.model('client', ModelSchema); + + query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + gte: () => { }, + lt: () => { }, + exec: () => { }, + count: () => new Promise((resolve) => resolve(1)), + model: Model + }; + }); + + beforeEach(async function () { + server = odata(); + init(server); + + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + modelMock?.restore(); + instanceMock?.restore(); + queryMock?.restore(); + }); + + it('should fail for client collection without client', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findById').never(); + httpServer = server.listen(port); + + const res = await request(host).get(`/client('1')`); + + modelMock.verify(); + res.body.should.deepEqual({ + error: { + code: '400', + message: `For entity 'client' you must send a client value` + } + }); + + }); + +}); diff --git a/test/mongo/mocked/client/count.js b/test/mongo/mocked/client/count.js new file mode 100644 index 0000000..5b4e27c --- /dev/null +++ b/test/mongo/mocked/client/count.js @@ -0,0 +1,68 @@ +import 'should'; +import request from 'supertest'; +import sinon from 'sinon'; +import { odata, host, port, assertSuccess } from '../../../support/setup'; +import mongoose from 'mongoose'; +import { init } from '../../../support/db'; + +describe('mongo.mocked.client.count', () => { + let httpServer, server, modelMock, instanceMock, queryMock, query, Model; + + before(() => { + const Schema = mongoose.Schema; + const ModelSchema = new Schema({ + client: Number + }); + + mongoose.set('overwriteModels', true); + + + Model = mongoose.model('client', ModelSchema); + + query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + gte: () => { }, + lt: () => { }, + exec: () => { }, + count: () => new Promise((resolve) => resolve(1)), + model: Model + }; + }); + + beforeEach(async function () { + server = odata(); + init(server); + + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + modelMock?.restore(); + instanceMock?.restore(); + queryMock?.restore(); + }); + + it('should apply client to the count', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('find').once() + .withArgs({ + client: 99 + }).returns(query); + httpServer = server.listen(port); + + const res = await request(host).get(`/client/$count?sap-client=099`); + + modelMock.verify(); + assertSuccess(res); + + }); + +}); diff --git a/test/mongo/mocked/client/delete.js b/test/mongo/mocked/client/delete.js new file mode 100644 index 0000000..f1bd689 --- /dev/null +++ b/test/mongo/mocked/client/delete.js @@ -0,0 +1,98 @@ +import 'should'; +import request from 'supertest'; +import sinon from 'sinon'; +import { odata, host, port, assertSuccess } from '../../../support/setup'; +import mongoose from 'mongoose'; +import { init } from '../../../support/db'; + +describe('mongo.mocked.client.delete', () => { + let httpServer, server, modelMock, instanceMock, queryMock, query, Model; + + before(() => { + const Schema = mongoose.Schema; + const ModelSchema = new Schema({ + client: Number + }); + + mongoose.set('overwriteModels', true); + + + Model = mongoose.model('client', ModelSchema); + + query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + gte: () => { }, + lt: () => { }, + exec: () => { }, + count: () => new Promise((resolve) => resolve(1)), + model: Model + }; + }); + + beforeEach(async function () { + server = odata(); + init(server); + + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + modelMock?.restore(); + instanceMock?.restore(); + queryMock?.restore(); + }); + + it('should fail on delete with wrong client', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findById').once() + .withArgs('1') + .returns(new Promise(resolve => resolve({ + toObject: () => ({ + _id: 1, + client: 98 + }) + }))); + httpServer = server.listen(port); + + const res = await request(host).delete(`/client('1')?sap-client=099`); + + modelMock.verify(); + res.status.should.be.equal(404); + + }); + + it('should work on delete with client', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + const instance = { + client: 99, + deleteOne: async () => {} + }; + modelMock = sinon.mock(Model); + modelMock.expects('findById').once() + .withArgs('1') + .returns(new Promise(resolve => resolve(instance))); + + instanceMock = sinon.mock(instance); + instanceMock.expects('deleteOne').once(); + httpServer = server.listen(port); + + const res = await request(host).delete(`/client('1')?sap-client=099`); + + modelMock.verify(); + instanceMock.verify(); + res.status.should.be.equal(204); + + }); + +}); diff --git a/test/mongo/mocked/client/get.js b/test/mongo/mocked/client/get.js new file mode 100644 index 0000000..1825c3d --- /dev/null +++ b/test/mongo/mocked/client/get.js @@ -0,0 +1,96 @@ +import 'should'; +import request from 'supertest'; +import sinon from 'sinon'; +import { odata, host, port, assertSuccess } from '../../../support/setup'; +import mongoose from 'mongoose'; +import { init } from '../../../support/db'; + +describe('mongo.mocked.client.get', () => { + let httpServer, server, modelMock, instanceMock, queryMock, query, Model; + + before(() => { + const Schema = mongoose.Schema; + const ModelSchema = new Schema({ + client: Number + }); + + mongoose.set('overwriteModels', true); + + + Model = mongoose.model('client', ModelSchema); + + query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + gte: () => { }, + lt: () => { }, + exec: () => { }, + count: () => new Promise((resolve) => resolve(1)), + model: Model + }; + }); + + beforeEach(async function () { + server = odata(); + init(server); + + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + modelMock?.restore(); + instanceMock?.restore(); + queryMock?.restore(); + }); + + + it('should apply client to the key', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findById').once() + .withArgs('1') + .returns(new Promise(resolve => resolve({ + toObject: () => ({ + _id: 1, + client: 99 + }) + }))); + httpServer = server.listen(port); + + const res = await request(host).get(`/client('1')?sap-client=099`); + + modelMock.verify(); + assertSuccess(res); + + }); + + it('should fail with correct key and wrong client', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findById').once() + .withArgs('1') + .returns(new Promise(resolve => resolve({ + toObject: () => ({ + _id: 1, + client: 98 + }) + }))); + httpServer = server.listen(port); + + const res = await request(host).get(`/client('1')?sap-client=099`); + + modelMock.verify(); + res.status.should.be.equal(404); + + }); + +}); diff --git a/test/mongo/mocked/client/getSingleton.js b/test/mongo/mocked/client/getSingleton.js new file mode 100644 index 0000000..a5cb069 --- /dev/null +++ b/test/mongo/mocked/client/getSingleton.js @@ -0,0 +1,113 @@ +import 'should'; +import request from 'supertest'; +import sinon from 'sinon'; +import { odata, host, port, assertSuccess } from '../../../support/setup'; +import mongoose from 'mongoose'; +import { init } from '../../../support/db'; + + +describe('mongo.mocked.client.getSingleton', () => { + let httpServer, server, modelMock, instanceMock, queryMock, query, Model; + + before(() => { + const Schema = mongoose.Schema; + const ModelSchema = new Schema({ + client: Number + }); + + mongoose.set('overwriteModels', true); + + + Model = mongoose.model('client', ModelSchema); + + query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + gte: () => { }, + lt: () => { }, + exec: () => { }, + count: () => new Promise((resolve) => resolve(1)), + model: Model + }; + }); + + beforeEach(async function () { + server = odata(); + init(server); + + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + modelMock?.restore(); + instanceMock?.restore(); + queryMock?.restore(); + }); + + it('should returns a transient singleton with wrong client', async function () { + const entity = server.mongoSingleton('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findOne').once() + .withArgs({ + client: 99 + }) + .returns(query); + queryMock = sinon.mock(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve())); + instanceMock = sinon.mock(Model.prototype); + instanceMock.expects('toObject').once() + .returns({}); + httpServer = server.listen(port); + + const res = await request(host).get(`/client?sap-client=099`); + + modelMock.verify(); + queryMock.verify(); + instanceMock.verify(); + res.body.should.deepEqual({ + id: null, + client: 99 + }); + + }); + + it('should returns a singleton with client', async function () { + const entity = server.mongoSingleton('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findOne').once() + .withArgs({ + client: 99 + }) + .returns(query); + queryMock = sinon.mock(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve({ + toObject: () => ({ + id: '1', + client: 99 + }) + }))); + httpServer = server.listen(port); + + const res = await request(host).get(`/client?sap-client=099`); + + modelMock.verify(); + queryMock.verify(); + instanceMock.verify(); + res.body.should.deepEqual({ + id: '1', + client: 99 + }); + + }); +}); diff --git a/test/mongo/mocked/client/list.js b/test/mongo/mocked/client/list.js new file mode 100644 index 0000000..54ed018 --- /dev/null +++ b/test/mongo/mocked/client/list.js @@ -0,0 +1,105 @@ +import 'should'; +import request from 'supertest'; +import sinon from 'sinon'; +import { odata, host, port, assertSuccess } from '../../../support/setup'; +import mongoose from 'mongoose'; +import { init } from '../../../support/db'; + +describe('mongo.mocked.client.list', () => { + let httpServer, server, modelMock, instanceMock, queryMock, query, Model; + + before(() => { + const Schema = mongoose.Schema; + const ModelSchema = new Schema({ + client: Number + }); + + mongoose.set('overwriteModels', true); + + + Model = mongoose.model('client', ModelSchema); + + query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + gte: () => { }, + lt: () => { }, + exec: () => { }, + count: () => new Promise((resolve) => resolve(1)), + model: Model + }; + }); + + beforeEach(async function () { + server = odata(); + init(server); + + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + modelMock?.restore(); + instanceMock?.restore(); + queryMock?.restore(); + }); + + it('should extend filter with client', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('find').once() + .withArgs({ + $and: [{ + client: { + $eq: 99 + } + }, { + client: { + $eq: 88 + } + }] + }).returns(query); + queryMock = sinon.mock(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve([]))); + httpServer = server.listen(port); + + const res = await request(host).get(`/client?$filter=client eq 88&sap-client=099`); + + modelMock.verify(); + + assertSuccess(res); + + }); + + it('should creates filter with client', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('find').once() + .withArgs({ + client: { + $eq: 99 + } + }).returns(query); + queryMock = sinon.mock(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve([]))); + httpServer = server.listen(port); + + const res = await request(host).get(`/client?sap-client=099`); + + modelMock.verify(); + + assertSuccess(res); + + }); + +}); diff --git a/test/mongo/mocked/client/patch.js b/test/mongo/mocked/client/patch.js new file mode 100644 index 0000000..c28bff6 --- /dev/null +++ b/test/mongo/mocked/client/patch.js @@ -0,0 +1,195 @@ +import 'should'; +import request from 'supertest'; +import sinon from 'sinon'; +import { odata, host, port, assertSuccess } from '../../../support/setup'; +import mongoose from 'mongoose'; +import { init } from '../../../support/db'; + +describe('mongo.mocked.client.patch', () => { + let httpServer, server, modelMock, instanceMock, queryMock, query, Model; + + before(() => { + const Schema = mongoose.Schema; + const ModelSchema = new Schema({ + client: Number, + text: String + }); + + mongoose.set('overwriteModels', true); + + + Model = mongoose.model('client', ModelSchema); + + query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + gte: () => { }, + lt: () => { }, + exec: () => { }, + count: () => new Promise((resolve) => resolve(1)), + model: Model + }; + }); + + beforeEach(async function () { + server = odata(); + init(server); + + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + modelMock?.restore(); + instanceMock?.restore(); + queryMock?.restore(); + }); + + it('should work if client is in body too', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findById').once() + .withArgs('1') + .returns(new Promise(resolve => resolve({ + toObject: () => ({ + _id: '1', + client: 99, + text: 'original' + }) + }))); + modelMock.expects('updateOne').once() + .withArgs({ + _id: '1' + }, { + _id: '1', + client: 99, + text: 'patched' + }).returns(new Promise(resolve => resolve())); + httpServer = server.listen(port); + + const res = (await request(host).patch(`/client('1')?sap-client=099`) + .send({ + client: 99, + text: 'patched' + })); + + modelMock.verify(); + assertSuccess(res); + + res.body.should.deepEqual({ + id: '1', + client: 99, + text: 'patched' + }); + + }); + + it('should fail with wrong client in body', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findById').once() + .withArgs('1') + .returns(new Promise(resolve => resolve({ + toObject: () => ({ + _id: '1', + client: 99, + text: 'original' + }) + }))); + modelMock.expects('updateOne').never(); + httpServer = server.listen(port); + + const res = (await request(host).patch(`/client('1')?sap-client=099`) + .send({ + client: 98, + text: 'patched' + })); + + modelMock.verify(); + res.body.should.deepEqual({ + error: { + message: 'Client value in custom parameter differs from client value in body', + code: '400' + } + }); + + }); + + it('should fail with correct key and wrong client', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findById').once() + .withArgs('1') + .returns(new Promise(resolve => resolve({ + toObject: () => ({ + _id: '1', + client: 99, + text: 'original' + }) + }))); + modelMock.expects('updateOne').never(); + httpServer = server.listen(port); + + const res = (await request(host).patch(`/client('1')?sap-client=098`) + .send({ + text: 'patched' + })); + + modelMock.verify(); + res.status.should.be.equal(404); + + }); + + it('should apply client to the key', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findById').once() + .withArgs('1') + .returns(new Promise(resolve => resolve({ + toObject: () => ({ + _id: '1', + client: 99, + text: 'original' + }) + }))); + modelMock.expects('updateOne').once() + .withArgs({ + _id: '1' + }, { + _id: '1', + client: 99, + text: 'patched' + }).returns(new Promise(resolve => resolve())); + httpServer = server.listen(port); + + const res = (await request(host).patch(`/client('1')?sap-client=099`) + .send({ + text: 'patched' + })); + + modelMock.verify(); + assertSuccess(res); + + res.body.should.deepEqual({ + id: '1', + client: 99, + text: 'patched' + }); + + }); + +}); diff --git a/test/mongo/mocked/client/patchSingleton.js b/test/mongo/mocked/client/patchSingleton.js new file mode 100644 index 0000000..81bf879 --- /dev/null +++ b/test/mongo/mocked/client/patchSingleton.js @@ -0,0 +1,173 @@ +import 'should'; +import request from 'supertest'; +import sinon from 'sinon'; +import { odata, host, port, assertSuccess } from '../../../support/setup'; +import mongoose from 'mongoose'; +import { init } from '../../../support/db'; + +describe('mongo.mocked.client.patchSingleton', () => { + let httpServer, server, modelMock, instanceMock, queryMock, query, Model; + + before(() => { + const Schema = mongoose.Schema; + const ModelSchema = new Schema({ + client: Number, + text: String + }); + + mongoose.set('overwriteModels', true); + + + Model = mongoose.model('client', ModelSchema); + + query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + gte: () => { }, + lt: () => { }, + exec: () => { }, + count: () => new Promise((resolve) => resolve(1)), + model: Model + }; + }); + + beforeEach(async function () { + server = odata(); + init(server); + + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + modelMock?.restore(); + instanceMock?.restore(); + queryMock?.restore(); + }); + + it('should work for upsert', async function () { + const entity = server.mongoSingleton('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findOne').once() + .withArgs({ + client: 99 + }) + .returns(new Promise(resolve => resolve())); + instanceMock = sinon.mock(Model.prototype); + instanceMock.expects('save').once() + .withArgs({ + validateBeforeSave: true, + validateModifiedOnly: true + }).returns(new Promise(resolve => resolve())); + instanceMock.expects('toObject').once() + .returns({ + _id: '1', + client: 99, + text: 'patched' + }); + httpServer = server.listen(port); + + const res = (await request(host).patch(`/client?sap-client=099`) + .send({ + text: 'patched' + })); + + modelMock.verify(); + instanceMock.verify(); + assertSuccess(res); + + res.body.should.deepEqual({ + id: '1', + client: 99, + text: 'patched' + }); + + }); + + it('should fail with wrong client in body', async function () { + const entity = server.mongoSingleton('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findOne').once() + .withArgs({ + client: 99 + }) + .returns(new Promise(resolve => resolve({ + _id: '1', + toObject: () => ({ + _id: '1', + client: 99, + text: 'original' + }) + }))); + modelMock.expects('updateOne').never(); + httpServer = server.listen(port); + + const res = (await request(host).patch(`/client?sap-client=099`) + .send({ + client: 98, + text: 'patched' + })); + + modelMock.verify(); + res.body.should.deepEqual({ + error: { + message: 'Client value in custom parameter differs from client value in body', + code: '400' + } + }); + + }); + + it('should work if client is in body too', async function () { + const entity = server.mongoSingleton('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findOne').once() + .withArgs({ + client: 99 + }).returns(new Promise(resolve => resolve({ + _id: '1', + toObject: () => ({ + _id: '1', + client: 99, + text: 'original' + }) + }))); + modelMock.expects('updateOne').once() + .withArgs({ + _id: '1' + }, { + _id: '1', + client: 99, + text: 'patched' + }).returns(new Promise(resolve => resolve())); + httpServer = server.listen(port); + + const res = (await request(host).patch(`/client?sap-client=099`) + .send({ + client: 99, + text: 'patched' + })); + + modelMock.verify(); + assertSuccess(res); + + res.body.should.deepEqual({ + id: '1', + client: 99, + text: 'patched' + }); + + }); + +}); diff --git a/test/mongo/mocked/client/post.js b/test/mongo/mocked/client/post.js new file mode 100644 index 0000000..f371f08 --- /dev/null +++ b/test/mongo/mocked/client/post.js @@ -0,0 +1,111 @@ +import 'should'; +import request from 'supertest'; +import sinon from 'sinon'; +import { odata, host, port, assertSuccess } from '../../../support/setup'; +import mongoose from 'mongoose'; +import { init } from '../../../support/db'; + +describe('mongo.mocked.client.post', () => { + let httpServer, server, modelMock, instanceMock, queryMock, query, Model; + + before(() => { + const Schema = mongoose.Schema; + const ModelSchema = new Schema({ + client: Number, + text: String + }); + + mongoose.set('overwriteModels', true); + + + Model = mongoose.model('client', ModelSchema); + + query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + gte: () => { }, + lt: () => { }, + exec: () => { }, + count: () => new Promise((resolve) => resolve(1)), + model: Model + }; + }); + + beforeEach(async function () { + server = odata(); + init(server); + + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + modelMock?.restore(); + instanceMock?.restore(); + queryMock?.restore(); + }); + + it('should fail with wrong client in body', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + instanceMock = sinon.mock(Model.prototype); + instanceMock.expects('save').never(); + httpServer = server.listen(port); + + const res = (await request(host).post(`/client?sap-client=099`) + .send({ + client: 98, + text: 'patched' + })); + + instanceMock.verify(); + res.body.should.deepEqual({ + error: { + message: 'Client value in custom parameter differs from client value in body', + code: '400' + } + }); + + }); + + it('should work if client is in body too', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + instanceMock = sinon.mock(Model.prototype); + instanceMock.expects('save').once() + .withArgs({ + validateBeforeSave: true, + validateModifiedOnly: true + }); + instanceMock.expects('toObject').once() + .returns({ + _id: '1', + client: 99, + text: 'original' + }) + httpServer = server.listen(port); + + const res = (await request(host).post(`/client?sap-client=099`) + .send({ + client: 99, + text: 'original' + })); + + instanceMock.verify(); + assertSuccess(res); + + res.body.should.deepEqual({ + id: '1', + client: 99, + text: 'original' + }); + + }); + +}); diff --git a/test/mongo/mocked/client/put.js b/test/mongo/mocked/client/put.js new file mode 100644 index 0000000..da5b140 --- /dev/null +++ b/test/mongo/mocked/client/put.js @@ -0,0 +1,215 @@ +import 'should'; +import request from 'supertest'; +import sinon from 'sinon'; +import { odata, host, port, assertSuccess } from '../../../support/setup'; +import mongoose from 'mongoose'; +import { init } from '../../../support/db'; + +describe('mongo.mocked.client.put', () => { + let httpServer, server, modelMock, instanceMock, queryMock, query, Model; + + before(() => { + const Schema = mongoose.Schema; + const ModelSchema = new Schema({ + client: Number, + text: String + }); + + mongoose.set('overwriteModels', true); + + + Model = mongoose.model('client', ModelSchema); + + query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + gte: () => { }, + lt: () => { }, + exec: () => { }, + count: () => new Promise((resolve) => resolve(1)), + model: Model + }; + }); + + beforeEach(async function () { + server = odata(); + init(server); + + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + modelMock?.restore(); + instanceMock?.restore(); + queryMock?.restore(); + }); + + it('should work if client is in body too', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findOne').once() + .withArgs({ + _id: '1' + }) + .returns(new Promise(resolve => resolve({ + _id: '1', + client: 99, + toObject: () => ( + { + _id: '1', + client: 99, + text: 'original' + }) + }))); + modelMock.expects('findByIdAndUpdate').once() + .withArgs('1', { + _id: '1', + client: 99, + text: 'patched' + }).returns(new Promise(resolve => resolve())); + httpServer = server.listen(port); + + const res = (await request(host).put(`/client('1')?sap-client=099`) + .send({ + _id: '1', + client: 99, + text: 'patched' + })); + + modelMock.verify(); + assertSuccess(res); + + res.body.should.deepEqual({ + id: '1', + client: 99, + text: 'patched' + }); + + }); + + it('should fail with wrong client in body', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findOne').once() + .withArgs({ + _id: '1' + }) + .returns(new Promise(resolve => resolve({ + _id: '1', + client: 99, + toObject: () => ( + { + _id: '1', + client: 99, + text: 'original' + }) + }))); + modelMock.expects('findByIdAndUpdate').never(); + httpServer = server.listen(port); + + const res = (await request(host).put(`/client('1')?sap-client=099`) + .send({ + _id: '1', + client: 98, + text: 'patched' + })); + + modelMock.verify(); + res.body.should.deepEqual({ + error: { + message: 'Client value in custom parameter differs from client value in body', + code: '400' + } + }); + + }); + + it('should fail with correct key and wrong client', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findOne').once() + .withArgs({ + _id: '1' + }) + .returns(new Promise(resolve => resolve({ + _id: '1', + client: 99, + toObject: () => ( + { + _id: '1', + client: 99, + text: 'original' + }) + }))); + modelMock.expects('findByIdAndUpdate').never(); + httpServer = server.listen(port); + + const res = (await request(host).put(`/client('1')?sap-client=098`) + .send({ + _id: '1', + client: 98, + text: 'patched' + })); + + modelMock.verify(); + res.status.should.be.equal(404); + + }); + + it('should apply client to the key', async function () { + const entity = server.mongoEntity('client', Model); + + entity.clientField = 'client'; + + modelMock = sinon.mock(Model); + modelMock.expects('findOne').once() + .withArgs({ + _id: '1' + }) + .returns(new Promise(resolve => resolve({ + _id: '1', + client: 99, + toObject: () => ({ + _id: '1', + client: 99, + text: 'original' + }) + }))); + modelMock.expects('findByIdAndUpdate').once() + .withArgs('1', { + _id: '1', + client: 99, + text: 'patched' + }).returns(new Promise(resolve => resolve())); + httpServer = server.listen(port); + + const res = (await request(host).put(`/client('1')?sap-client=099`) + .send({ + _id: '1', + text: 'patched' + })); + + modelMock.verify(); + assertSuccess(res); + + res.body.should.deepEqual({ + id: '1', + client: 99, + text: 'patched' + }); + + }); + +}); diff --git a/test/mongo/mocked/model.complex.filter.js b/test/mongo/mocked/model.complex.filter.js new file mode 100644 index 0000000..9e9cc63 --- /dev/null +++ b/test/mongo/mocked/model.complex.filter.js @@ -0,0 +1,73 @@ +// For issue: https://github.com/TossShinHwa/node-odata/issues/69 + +import 'should'; +import 'should-sinon'; +import request from 'supertest'; +import { odata, assertSuccess, host, port } from '../../support/setup'; +import sinon from 'sinon'; +import mongoose from 'mongoose'; +import { init } from '../../support/db'; + +const Schema = mongoose.Schema; + +describe('mongo.mocked.model.complex.filter', () => { + let httpServer, modelMock, queryMock; + + before(() => { + const server = odata(); + const ComplexModelSchema = new Schema({ + product: { price: Number } + }); + + mongoose.set('overwriteModels', true); + const ComplexModel = mongoose.model('complex-model-filter', ComplexModelSchema); + + server.mongoEntity('complex-model-filter', ComplexModel); + init(server); + + const query = { + where: () => { }, + gt: () => { }, + select: () => { }, + exec: () => { }, + model: ComplexModel + }; + modelMock = sinon.mock(ComplexModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once().withArgs({"product.price": {$gt: 30}}).returns(query); + + queryMock.expects('select').once().withArgs({ _id: 0, product: 1}); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve([{ + toObject: () => ({ + product: { + price: 50 + } + }) + }]))); + httpServer = server.listen(port); + }); + + after(() => { + httpServer.close(); + }); + + afterEach(() => { + modelMock.restore(); + queryMock?.restore(); + }) + + it('should work when filter a complex entity', async function () { + let res = await request(host).get(`/complex-model-filter?$select=product&$filter=product.price gt 30`); + assertSuccess(res); + res.body.should.deepEqual({ + value: [{ + product: { + price: 50 + } + }] + }); + modelMock.verify(); + queryMock.verify(); + }); +}); diff --git a/test/mongo/mocked/model.custom.id.js b/test/mongo/mocked/model.custom.id.js new file mode 100644 index 0000000..797bf7e --- /dev/null +++ b/test/mongo/mocked/model.custom.id.js @@ -0,0 +1,94 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from '../../support/setup'; +import sinon from 'sinon'; +import mongoose from 'mongoose'; +import { init } from '../../support/db'; + +const Schema = mongoose.Schema; + +describe('mongo.mocked.model.custom.id', () => { + let httpServer, modelMock, queryMock, Model; + + before(async function () { + const server = odata(); + + const ModelSchema = new Schema({ + id: { + type: Number, + unique: true + } + }); + + Model = mongoose.model('custom-id', ModelSchema); + + const entity = server.mongoEntity('custom-id', Model, undefined, { + id: { + $Type: 'Edm.Int16' + } + }, undefined); + + entity.mapping = { + id: { + intern: 'id', + attributes: { + $Type: 'Edm.Int16' + } + } + }; + + init(server); + + httpServer = server.listen(port); + }); + + after(() => { + httpServer.close(); + }); + + afterEach(() => { + modelMock.restore(); + queryMock?.restore(); + }) + + it('should work when use a custom id to query specific entity', async function () { + modelMock = sinon.mock(Model); + modelMock.expects('findById').once() + .returns(new Promise(resolve => resolve({ + toObject: () => ({ + id: 100 + }) + }))); + + const res = await request(host).get('/custom-id(100)'); + + assertSuccess(res); + res.body.id.should.be.equal(100); + modelMock.verify(); + }); + + it('should work when use a custom id to query a list', async function () { + const query = { + where: () => { }, + equals: () => { }, + exec: () => { }, + model: Model + }; + modelMock = sinon.mock(Model); + queryMock = sinon.mock(query); + modelMock.expects('find').once().withArgs({ id: { $eq: 100 } }).returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve([{ + toObject: () => ({ + id: 100 + }) + }]))); + + const res = await request(host).get('/custom-id?$filter=id eq 100'); + + assertSuccess(res); + res.body.value.length.should.be.greaterThan(0); + queryMock.verify(); + modelMock.verify(); + }); +}); diff --git a/test/mongo/mocked/odata.count.js b/test/mongo/mocked/odata.count.js new file mode 100644 index 0000000..b2c1876 --- /dev/null +++ b/test/mongo/mocked/odata.count.js @@ -0,0 +1,48 @@ +import 'should'; +import sinon from 'sinon'; +import request from 'supertest'; +import { odata, host, port } from '../../support/setup'; +import { init } from '../../support/db'; +import { BookModel } from '../../support/books.model'; + +describe('mongo.mocked.odata.count', function() { + let httpServer, modelMock, queryMock; + + before(async function() { + const server = odata(); + server.mongoEntity('book', BookModel); + init(server); + + httpServer = server.listen(port); + }); + + after(() => { + httpServer.close(); + modelMock.restore(); + queryMock?.restore(); + }); + + it('should get count for entity set', async function() { + const query = { + count: () => { }, + model: BookModel + }; + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once().returns(query); + queryMock.expects('count').once() + .returns(new Promise(resolve => resolve(13))); + + const res = await request(host).get('/book/$count'); + + if (res.error) { + res.error.status.should.be.equal(200); + } + res.text.should.be.equal('13'); + res.header.should.have.property('content-type'); + res.header['content-type'].should.containEql('text/plain'); + + modelMock.verify(); + queryMock.verify(); + }); +}); diff --git a/test/mongo/mocked/odata.query.count.js b/test/mongo/mocked/odata.query.count.js new file mode 100644 index 0000000..6f93def --- /dev/null +++ b/test/mongo/mocked/odata.query.count.js @@ -0,0 +1,66 @@ +import 'should'; +import sinon from 'sinon'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from '../../support/setup'; +import books from '../../support/books.json'; +import { init } from '../../support/db'; +import { BookModel } from '../../support/books.model'; + +describe('mongo.mocked.odata.query.count', function () { + const query = { + count: () => { }, + exec: () => { }, + model: BookModel + }; + let httpServer, modelMock, queryMock; + + before(async function () { + const server = odata(); + server.mongoEntity('book', BookModel); + init(server); + httpServer = server.listen(port); + }); + + after(() => { + httpServer.close(); + }); + + afterEach(() => { + modelMock.restore(); + queryMock?.restore(); + }); + + it('should get count', async function () { + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').twice().returns(query); + queryMock.expects('count').once() + .returns(new Promise(resolve => resolve(13))); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get('/book?$count=true'); + assertSuccess(res); + res.body.should.be.have.property('@odata.count'); + res.body.should.be.have.property('value'); + res.body['@odata.count'].should.be.equal(res.body.value.length.toString()); + + modelMock.verify(); + queryMock.verify(); + }); + it('should not get count', async function () { + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').twice().returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get('/book?$count=false'); + res.body.should.be.not.have.property('@odata.count'); + }); + it('should 500 when $count isn\'t \'true\' or \'false\'', async function () { + const res = await request(host).get('/book?$count=1'); + res.error.status.should.be.equal(500); + }); + +}); diff --git a/test/mongo/mocked/odata.query.filter.functions.js b/test/mongo/mocked/odata.query.filter.functions.js new file mode 100644 index 0000000..2fb6515 --- /dev/null +++ b/test/mongo/mocked/odata.query.filter.functions.js @@ -0,0 +1,135 @@ +import 'should'; +import sinon from 'sinon'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from '../../support/setup'; +import data from '../../support/books.json'; +import { BookModel } from '../../support/books.model'; + +describe('mongo.mocked.odata.query.filter.functions', function () { + const query = { + $where: () => { }, + where: () => { }, + gte: () => { }, + lt: () => { }, + exec: () => { }, + model: BookModel + }; + let httpServer, modelMock, queryMock; + + before(async function () { + const server = odata(); + + server.mongoEntity('book', BookModel); + httpServer = server.listen(port); + }); + + after(() => { + httpServer.close(); + }); + + afterEach(() => { + modelMock?.restore(); + queryMock?.restore(); + }); + + describe('[contains]', () => { + it('should filter items', async function () { + const books = data.filter(item => item.title.indexOf('i') >= 0); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once().withArgs({title: {$where: `this.title.indexOf('i') != -1`}}).returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get(`/book?$filter=contains(title,'i')`); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + it('should filter items when it has extra spaces in query string', async function () { + const books = data.filter(item => item.title.indexOf('Visual Studio') >= 0); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once().withArgs({title: {$where: `this.title.indexOf('Visual Studio') != -1`}}).returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get(`/book?$filter=contains(title,'Visual Studio')`); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + }); + + describe('[indexof]', () => { + it('should filter items', async function () { + const books = data.filter(item => item.title.indexOf('i') >= 1); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once().withArgs({title: {$where: `this.title.indexOf('i') >= 1`}}).returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get(`/book?$filter=indexof(title,'i') ge 1`); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + it('should filter items when it has extra spaces in query string', async function () { + const books = data.filter(item => item.title.indexOf('Visual Studio') >= 0); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once().withArgs({title: {$where: `this.title.indexOf('Visual Studio') >= 0`}}).returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get(`/book?$filter=indexof(title,'Visual Studio') ge 0`); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + }); + + describe('[year]', () => { + it('should filter items', async function () { + const books = data.filter(item => item.publish_date >= new Date(2000, 0, 1) && item.publish_date < new Date(2001, 0, 1)); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once().withArgs({ + publish_date: {$gte: new Date(2000, 0, 1), $lt: new Date(2001, 0, 1)} + }).returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get(`/book?$filter=year(publish_date) eq 2000`); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + }); +}); diff --git a/test/mongo/mocked/odata.query.filter.js b/test/mongo/mocked/odata.query.filter.js new file mode 100644 index 0000000..ecb6c5e --- /dev/null +++ b/test/mongo/mocked/odata.query.filter.js @@ -0,0 +1,225 @@ +import 'should'; +import sinon from 'sinon'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from '../../support/setup'; +import data from '../../support/books.json'; +import { BookModel } from '../../support/books.model'; + +describe('mongo.mocked.odata.query.filter', function () { + const query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + gte: () => { }, + lt: () => { }, + exec: () => { }, + model: BookModel + }; + let httpServer, modelMock, queryMock; + + before(async function () { + const server = odata(); + + server.mongoEntity('book', BookModel); + httpServer = server.listen(port); + + }); + + after(() => { + httpServer.close(); + }); + + afterEach(() => { + modelMock?.restore(); + queryMock?.restore(); + }); + + describe('[Equal]', () => { + it('should filter items', async function () { + const books = data.filter(item => item.title === 'Midnight Rain'); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once().withArgs({title: {$eq: 'Midnight Rain'}}).returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get(`/book?$filter=title eq 'Midnight Rain'`); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + it('should filter items when field has keyword', async function () { + const books = data.filter(item => item.author === 'Ralls, Kim'); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once().withArgs({author: {$eq: 'Ralls, Kim'}}).returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get(`/book?$filter=author eq 'Ralls, Kim'`); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + it('should filter items when use id', async function () { + const books = data.filter(item => item.id === '2'); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once().withArgs({_id: {$eq: '2'}}).returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get(encodeURI(`/book?$filter=id eq '2'`)); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + }); + + describe("[Not equal]", () => { + it('should filter items', async function () { + const books = data.filter(item => item.author != 'Ralls, Kim'); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once().withArgs({author: {$ne: 'Ralls, Kim'}}).returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get(`/book?$filter=author ne 'Ralls, Kim'`); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + }); + + describe("[Greater than]", () => { + it('should filter items', async function () { + const books = data.filter(item => item.price > 36.95); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once().withArgs({price: {$gt: 36.95}}).returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get(`/book?$filter=price gt 36.95`); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + }); + + describe('[Greater than or equal]', () => { + it('should filter items', async function () { + const books = data.filter(item => item.price >= 36.95); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once().withArgs({price: {$gte: 36.95}}).returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get(`/book?$filter=price ge 36.95`); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + }); + + describe('[Less than]', () => { + it('should filter items', async function () { + const books = data.filter(item => item.price < 36.95); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once().withArgs({price: {$lt: 36.95}}).returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get(`/book?$filter=price lt 36.95`); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + }); + + describe('[Less than or equal]', () => { + it('should filter items', async function () { + const books = data.filter(item => item.price <= 36.95); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once().withArgs({price: {$lte: 36.95}}).returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get(`/book?$filter=price le 36.95`); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + }); + + describe('[Logical and]', () => { + it("should filter items", async function () { + const books = data.filter(item => item.title != 'Midnight Rain' && item.price >= 36.95); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').once() + .withArgs({ + $and: [{ + title: {$ne: 'Midnight Rain'} + }, { + price: {$gte: 36.95} + }]}).returns(query); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get(`/book?$filter=title ne 'Midnight Rain' and price ge 36.95`); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + }); +}); diff --git a/test/mongo/mocked/odata.query.orderby.js b/test/mongo/mocked/odata.query.orderby.js new file mode 100644 index 0000000..63e54bd --- /dev/null +++ b/test/mongo/mocked/odata.query.orderby.js @@ -0,0 +1,135 @@ +import 'should'; +import sinon from 'sinon'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from '../../support/setup'; +import data from '../../support/books.json'; +import { BookModel } from '../../support/books.model'; + +describe('mongo.mocked.odata.query.orderby', () => { + const query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + gte: () => { }, + sort: () => { }, + exec: () => { }, + model: BookModel + }; + let httpServer, modelMock, queryMock; + const dataIsolated = JSON.parse(JSON.stringify(data)); + + before(async function() { + const server = odata(); + + server.mongoEntity('book', BookModel); + httpServer = server.listen(port); + + }); + + after(() => { + httpServer.close(); + }); + + afterEach(() => { + modelMock?.restore(); + queryMock?.restore(); + }); + + it('should default let items order with asc', async function() { + const books = dataIsolated.sort((a, b) => a.price - b.price); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').returns(query); + queryMock.expects('sort').once().withArgs([['price', 'asc']]); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get('/book?$orderby=price'); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + + it('should let items order asc', async function() { + const books = dataIsolated.sort((a, b) => a.price - b.price); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').returns(query); + queryMock.expects('sort').once().withArgs([['price', 'asc']]); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get('/book?$orderby=price asc'); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + + it('should let items order desc', async function() { + const books = dataIsolated.sort((a, b) => b.price - a.price); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').returns(query); + queryMock.expects('sort').once().withArgs([['price', 'desc']]); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get('/book?$orderby=price desc'); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + + it('should let items order when use multiple fields', async function() { + const books = dataIsolated.sort((a, b) => { + const result = a.price - b.price; + + if (!result) { + return a.title - b.title; + } + + return result; + }); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').returns(query); + queryMock.expects('sort').once().withArgs([['price', 'asc'], ['title', 'asc']]); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get('/book?$orderby=price,title'); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + + it("should fail by not exist field", async function() { + modelMock = sinon.mock(BookModel); + modelMock.expects('find').never(); + + const res = await request(host).get('/book?$orderby=not-exist-field'); + + modelMock.verify(); + res.status.should.be.equal(400); + }); +}); diff --git a/test/mongo/mocked/odata.query.select.js b/test/mongo/mocked/odata.query.select.js new file mode 100644 index 0000000..7f1135e --- /dev/null +++ b/test/mongo/mocked/odata.query.select.js @@ -0,0 +1,207 @@ +import 'should'; +import sinon from 'sinon'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from '../../support/setup'; +import data from '../../support/books.json'; +import { BookModel } from '../../support/books.model'; +import mongoose from 'mongoose'; + +const Schema = mongoose.Schema; + +describe('mongo.mocked.odata.query.select', () => { + const query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + select: () => { }, + sort: () => { }, + exec: () => { }, + model: BookModel + }; + let httpServer, modelMock, queryMock, server; + + afterEach(() => { + httpServer.close(); + modelMock?.restore(); + queryMock?.restore(); + }); + + it('should select anyone field', async function () { + const books = data.map(item => ({ + price: item.price + })); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').returns(query); + queryMock.expects('select').once().withArgs({ + _id: 0, + price: 1 + }); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + server = odata(); + server.mongoEntity('book', BookModel); + httpServer = server.listen(port); + + const res = await request(host).get('/book?$select=price'); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + it('should select multiple field', async function () { + const books = data.map(item => ({ + price: item.price, + title: item.title + })); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').returns(query); + queryMock.expects('select').once().withArgs({ + _id: 0, + price: 1, + title: 1 + }); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + server = odata(); + server.mongoEntity('book', BookModel); + httpServer = server.listen(port); + + const res = await request(host).get('/book?$select=price,title'); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + it('should select multiple field with blank space', async function () { + const books = data.map(item => ({ + price: item.price, + title: item.title + })); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').returns(query); + queryMock.expects('select').once().withArgs({ + _id: 0, + price: 1, + title: 1 + }); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ toObject: () => item }))))); + server = odata(); + server.mongoEntity('book', BookModel); + httpServer = server.listen(port); + + const res = await request(host).get('/book?$select=price, title'); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + it('should select id field', async function () { + const books = data.map(item => ({ + price: item.price, + title: item.title, + id: item.id + })); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').returns(query); + queryMock.expects('select').once().withArgs({ + _id: 1, + price: 1, + title: 1 + }); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(books.map(item => ({ + toObject: () => ({ + price: item.price, + title: item.title, + _id: item.id + }) + }))))); + server = odata(); + server.mongoEntity('book', BookModel); + httpServer = server.listen(port); + + const res = await request(host).get('/book?$select=price,title,id'); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: books + }); + }); + it('should ignore when select not exist field', async function () { + modelMock = sinon.mock(BookModel); + modelMock.expects('find').never(); + server = odata(); + server.mongoEntity('book', BookModel); + httpServer = server.listen(port); + + const res = await request(host).get('/book?$select=not-exist-field'); + + modelMock.verify(); + res.status.should.be.equal(400); + }); + + it('should select deep field', async function () { + const result = [{ + name: { + first: 'Max' + } + }]; + const UserSchema = new Schema({ + name: { + first: { + type: String + }, + last: { + type: String + } + } + }); + const UserModel = mongoose.model('user', UserSchema); + const userQuery = { + ...query, + model: UserModel + }; + + modelMock = sinon.mock(UserModel); + queryMock = sinon.mock(userQuery); + modelMock.expects('find').returns(userQuery); + queryMock.expects('select').once().withArgs({ + _id: 0, + "name.first": 1 + }); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(result.map(item => ({ toObject: () => item }))))); + server = odata(); + server.mongoEntity('user', UserModel); + httpServer = server.listen(port); + + const res = await request(host).get('/user?$select=name/first'); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual({ + value: result + }); + }); +}); diff --git a/test/mongo/mocked/odata.query.skip.js b/test/mongo/mocked/odata.query.skip.js new file mode 100644 index 0000000..1a2acd7 --- /dev/null +++ b/test/mongo/mocked/odata.query.skip.js @@ -0,0 +1,83 @@ +import 'should'; +import sinon from 'sinon'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from '../../support/setup'; +import { BookModel } from '../../support/books.model'; +import data from '../../support/books.json'; + +describe('mongo.mocked.odata.query.skip', () => { + const query = { + $where: () => { }, + where: () => { }, + skip: () => { }, + select: () => { }, + sort: () => { }, + exec: () => { }, + model: BookModel + }; + let httpServer, modelMock, queryMock; + + before(async function() { + const server = odata(); + + server.mongoEntity('book', BookModel) + httpServer = server.listen(port); + + }); + + after(() => { + httpServer.close(); + }); + + afterEach(() => { + modelMock?.restore(); + queryMock?.restore(); + }); + + it('should skip items', async function() { + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').returns(query); + queryMock.expects('skip').once().withArgs(1); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(data.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get('/book?$skip=1'); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + }); + it('should ignore when skip over count of items', async function() { + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').returns(query); + queryMock.expects('skip').once().withArgs(1024); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(data.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get('/book?$skip=1024'); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + }); + it('should ignore when skip not a number', async function() { + modelMock = sinon.mock(BookModel); + modelMock.expects('find').never(); + + const res = await request(host).get('/book?$skip=not-a-number'); + + modelMock.verify(); + res.status.should.be.equal(400); + }); + return it('should ignore when skip not a positive number', async function() { + modelMock = sinon.mock(BookModel); + modelMock.expects('find').never(); + + const res = await request(host).get('/book?$skip=-1'); + + modelMock.verify(); + res.status.should.be.equal(400); + }); +}); diff --git a/test/mongo/mocked/odata.query.top.js b/test/mongo/mocked/odata.query.top.js new file mode 100644 index 0000000..8ceec9b --- /dev/null +++ b/test/mongo/mocked/odata.query.top.js @@ -0,0 +1,68 @@ +import 'should'; +import sinon from 'sinon'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from '../../support/setup'; +import { BookModel } from '../../support/books.model'; +import data from '../../support/books.json'; + +describe('mongo.mocked.odata.query.top', () => { + const query = { + $where: () => { }, + limit: () => { }, + skip: () => { }, + select: () => { }, + sort: () => { }, + exec: () => { }, + model: BookModel + }; + let httpServer, modelMock, queryMock; + + before(async function() { + const server = odata(); + + server.mongoEntity('book', BookModel) + httpServer = server.listen(port); + }); + + after(() => { + httpServer.close(); + }); + + afterEach(() => { + modelMock?.restore(); + queryMock?.restore(); + }); + + it('should top items', async function() { + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('find').returns(query); + queryMock.expects('limit').once().withArgs(1); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(data.map(item => ({ toObject: () => item }))))); + + const res = await request(host).get('/book?$top=1'); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + }); + it('should iginre when top not a number', async function() { + modelMock = sinon.mock(BookModel); + modelMock.expects('find').never(); + + const res = await request(host).get('/book?$top=not-a-number'); + + modelMock.verify(); + res.status.should.be.equal(400); + }); + it('should ignore when top not a positive number', async function() { + modelMock = sinon.mock(BookModel); + modelMock.expects('find').never(); + + const res = await request(host).get('/book?$top=-1'); + + modelMock.verify(); + res.status.should.be.equal(400); + }); +}); diff --git a/test/mongo/mocked/rest.delete.js b/test/mongo/mocked/rest.delete.js new file mode 100644 index 0000000..65fa792 --- /dev/null +++ b/test/mongo/mocked/rest.delete.js @@ -0,0 +1,50 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from '../../support/setup'; +import { BookModel } from '../../support/books.model'; +import sinon from 'sinon'; + +describe('mongo.mocked.rest.delete', function() { + let httpServer, modelMock; + + before(async function() { + const server = odata(); + server.mongoEntity('book', BookModel) + httpServer = server.listen(port); + }); + + after(() => { + httpServer.close(); + }); + + afterEach(() => { + modelMock?.restore(); + }); + + it('should delete resource if it exist', async function() { + modelMock = sinon.mock(BookModel); + modelMock.expects('deleteOne').once().withArgs({_id: '1'}) + .returns(new Promise(resolve => resolve(JSON.stringify({n:1})))); + + const res = await request(host).del(`/book('1')`); + + assertSuccess(res); + res.status.should.be.equal(204); + modelMock.verify(); + }); + it('should be 404 if resource not exist', async function() { + modelMock = sinon.mock(BookModel); + modelMock.expects('deleteOne').once().withArgs({_id: '666'}) + .returns(new Promise(resolve => resolve(JSON.stringify({n:0})))); + + const res = await request(host).del(`/book('666')`); + + res.status.should.be.equal(404); + modelMock.verify(); + }); + it('should be 404 if without id', async function() { + const res = await request(host).del(`/book`); + + res.status.should.be.equal(404); + }); +}); diff --git a/test/mongo/mocked/rest.get.js b/test/mongo/mocked/rest.get.js new file mode 100644 index 0000000..50c6e97 --- /dev/null +++ b/test/mongo/mocked/rest.get.js @@ -0,0 +1,103 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port } from '../../support/setup'; +import { BookModel } from '../../support/books.model'; +import mongoose from 'mongoose'; +import sinon from 'sinon'; + +const Schema = mongoose.Schema; + +describe('mongo.mocked.rest.get', () => { + const query = { + $where: () => { }, + limit: () => { }, + skip: () => { }, + select: () => { }, + sort: () => { }, + exec: () => { } + }; + const bookQuery = { + ...query, + model: BookModel + }; + + let httpServer, modelMock, queryMock, ComplexModel; + + before(async function() { + const server = odata(); + server.mongoEntity('book', BookModel); + const ComplexModelSchema = new Schema({ + p1: { + p2: { + type: String + } + } + }); + + mongoose.set('overwriteModels', true); + ComplexModel = mongoose.model('complex-type', ComplexModelSchema); + + server.mongoEntity('complex-type', ComplexModel); + httpServer = server.listen(port); + + }); + + after(() => { + httpServer.close(); + }); + + afterEach(() => { + modelMock?.restore(); + queryMock?.restore(); + }); + + it('should return all of the resources', async function() { + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(bookQuery); + modelMock.expects('find').once().returns(bookQuery); + queryMock.expects('exec').once().returns(new Promise(resolve => resolve([]))); + + const res = await request(host).get(`/book`); + + res.body.should.be.have.property('value'); + res.body.value.length.should.be.equal(0); + modelMock.verify(); + queryMock.verify(); + }); + it('should return special resource', async function() { + modelMock = sinon.mock(BookModel); + modelMock.expects('findById').once().withArgs('1') + .returns(new Promise(resolve => resolve({toObject: () => ({title: 'Krieg und Frieden'})}))); + + const res = await request(host).get(`/book('1')`); + + res.body.should.be.have.property('title'); + res.body.title.should.be.equal('Krieg und Frieden'); + modelMock.verify(); + }); + it('should be 404 if resouce name not declare', async function() { + const res = await request(host).get(`/not-exist-resource`); + res.status.should.be.equal(404); + }); + it('should be 404 if resource not exist', async function() { + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(bookQuery); + modelMock.expects('findById').once().withArgs('1') + .returns(new Promise(resolve => resolve())); + + const res = await request(host).get(`/book('1')`); + res.status.should.be.equal(404); + modelMock.verify(); + }); + it('should return deep structure', async function() { + modelMock = sinon.mock(ComplexModel); + modelMock.expects('findById').once().withArgs('1') + .returns(new Promise(resolve => resolve({toObject: () => ({p1:{p2: 'Krieg und Frieden'}})}))); + + const res = await request(host).get(`/complex-type('1')`); + res.body.should.be.have.property('p1'); + res.body.p1.should.be.have.property('p2'); + res.body.p1.p2.should.be.equal('Krieg und Frieden'); + modelMock.verify(); + }); +}); diff --git a/test/mongo/mocked/rest.put.js b/test/mongo/mocked/rest.put.js new file mode 100644 index 0000000..c370a42 --- /dev/null +++ b/test/mongo/mocked/rest.put.js @@ -0,0 +1,87 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port } from '../../support/setup'; +import books from '../../support/books.json'; +import { BookModel } from '../../support/books.model'; +import sinon from 'sinon'; + +describe('mongo.mocked.rest.put', () => { + let httpServer, modelMock, bookInstanceMock; + + before(async function () { + const server = odata(); + + server.mongoEntity('book', BookModel); + httpServer = server.listen(port); + }); + + after(() => { + httpServer.close(); + }); + + beforeEach(() => { + modelMock?.restore(); + bookInstanceMock?.restore(); + }); + + it('should modify resource', async function () { + const book = JSON.parse(JSON.stringify(books[0])); + + book.title = 'modify book'; + modelMock = sinon.mock(BookModel); + modelMock.expects('findOne').once().withArgs({_id: '1'}) + .returns(new Promise((resolve, reject) => resolve(JSON.parse(JSON.stringify({ + ...books[0], + _id: books[0].id + }))))); + modelMock.expects('findByIdAndUpdate').once().withArgs('1', book) + .returns(new Promise(resolve => resolve())); + + const res = await request(host) + .put(`/book('${book.id}')`) + .send(book); + + modelMock.verify(); + res.body.should.be.have.property('title'); + res.body.title.should.be.equal(book.title); + }); + it('should create resource if send with a id which not exist', async function () { + const book = JSON.parse(JSON.stringify(books[0])); + + book.id = '12345678-1234-1234-A123-123456789012'; + book.title = 'new book'; + modelMock = sinon.mock(BookModel); + modelMock.expects('findOne').once().withArgs({_id: book.id}) + .returns(new Promise(resolve => resolve())) + // mocking save method of created with new instance + bookInstanceMock = sinon.mock(BookModel.prototype); + bookInstanceMock.expects('save').once() + .returns(new Promise(resolve => resolve())) + + const res = await request(host) + .put(`/book('${book.id}')`) + .send({ title: book.title }); + + res.body.should.be.have.property('title'); + res.body.title.should.be.equal(book.title); + res.body.should.be.have.property('id'); + modelMock.verify(); + }); + it('should be 404 if without id', async function () { + const res = await request(host).put(`/book`).send(books[0]); + res.status.should.be.equal(404); + }); + it("should 400 if with a wrong id", async function () { + const book = JSON.parse(JSON.stringify(books[0])); + + book.title = 'new book'; + modelMock = sinon.mock(BookModel); + modelMock.expects('findOne').once().withArgs({_id: book.id}) + .returns(new Promise(resolve => resolve())) + + const res = await request(host).put(`/book('1')`).send(books[0]); + + res.status.should.be.equal(400); + modelMock.verify(); + }); +}); diff --git a/test/mongo/mocked/singelton.js b/test/mongo/mocked/singelton.js new file mode 100644 index 0000000..24e59f6 --- /dev/null +++ b/test/mongo/mocked/singelton.js @@ -0,0 +1,189 @@ +import 'should'; +import sinon from 'sinon'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from '../../support/setup'; +import data from '../../support/books.json'; +import { BookModel } from '../../support/books.model'; +import mongoose from 'mongoose'; + +const Schema = mongoose.Schema; + +const ConfigSchema = new Schema({ + isAutoLogOffActive: { + type: Boolean, + default: true + }, +}, + { + timestamps: true, + toObject: { + virtuals: true, + }, + toJSON: { + virtuals: true, + }, + }); + +const ConfigModel = mongoose.model('Config', ConfigSchema); + +describe('mongo.mocked.singleton', () => { + let httpServer, modelMock, queryMock, instanceMock, server; + + beforeEach(async function () { + server = odata(); + }); + + afterEach(() => { + httpServer.close(); + modelMock?.restore(); + queryMock?.restore(); + instanceMock?.restore(); + }); + + it('should select anyone field', async function () { + const query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + select: () => { }, + sort: () => { }, + exec: () => { }, + model: BookModel + }; + const books = data.map(item => ({ + price: item.price + })); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('findOne').once().returns(query); + queryMock.expects('select').once().withArgs({ + _id: 0, + price: 1 + }); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve({ toObject: () => books[0] }))); + server.mongoSingleton('book', BookModel); + httpServer = server.listen(port); + + const res = await request(host).get('/book?$select=price'); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + res.body.should.deepEqual(books[0]); + }); + + it('should select anyone field for upsert', async function () { + const query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + select: () => { }, + sort: () => { }, + exec: () => { }, + model: BookModel + }; + const books = data.map(item => ({ + price: item.price + })); + + modelMock = sinon.mock(BookModel); + queryMock = sinon.mock(query); + modelMock.expects('findOne').once().returns(query); + queryMock.expects('select').once().withArgs({ + _id: 0, + price: 1 + }); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(undefined))); + instanceMock = sinon.mock(BookModel.prototype); + instanceMock.expects('toObject').once().returns(JSON.parse(JSON.stringify(data[0]))); + server.mongoSingleton('book', BookModel); + httpServer = server.listen(port); + + const res = await request(host).get('/book?$select=price'); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + instanceMock.verify(); + res.body.should.deepEqual(books[0]); + }); + + it('should return default value', async function () { + const query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + select: () => { }, + sort: () => { }, + exec: () => { }, + model: ConfigModel + }; + + modelMock = sinon.mock(ConfigModel); + queryMock = sinon.mock(query); + modelMock.expects('findOne').once().returns(query); + queryMock.expects('select').once().withArgs({ + _id: 1, + isAutoLogOffActive: 1 + }); + queryMock.expects('exec').once() + .returns(new Promise(resolve => resolve(undefined))); + instanceMock = sinon.mock(ConfigModel.prototype); + instanceMock.expects('toObject').once().returns(JSON.parse(JSON.stringify({ isAutoLogOffActive: true, _id: '1' }))); + server.mongoSingleton('config', ConfigModel); + httpServer = server.listen(port); + + const res = await request(host).get('/config?$select=id,isAutoLogOffActive'); + + assertSuccess(res); + modelMock.verify(); + queryMock.verify(); + instanceMock.verify(); + res.body.should.deepEqual({ + id: null, + isAutoLogOffActive: true + }); + }); + + it('should supports upsert', async function () { + const now = new Date(); + const query = { + $where: () => { }, + where: () => { }, + equals: () => { }, + select: () => { }, + sort: () => { }, + exec: () => { }, + model: ConfigModel + }; + + modelMock = sinon.mock(ConfigModel); + modelMock.expects('findOne').once().returns(new Promise((resolve) => resolve())); + instanceMock = sinon.mock(ConfigModel.prototype); + instanceMock.expects('save').once().returns(new Promise((resolve) => resolve())); + instanceMock.expects('toObject').once().returns({ + isAutoLogOffActive: false, + _id: '1', + createdAt: now + }); + server.mongoSingleton('config', ConfigModel); + httpServer = server.listen(port); + + const res = await request(host).patch('/config').send({ + isAutoLogOffActive: false + }); + + assertSuccess(res); + modelMock.verify(); + instanceMock.verify(); + res.body.should.deepEqual({ + id: '1', + isAutoLogOffActive: false, + createdAt: now.toISOString().replace(/\.[0-9]{3}/, ''), + updatedAt: null + }); + }); +}); diff --git a/test/odata.actions.js b/test/odata.actions.js index 14ecb23..5085513 100644 --- a/test/odata.actions.js +++ b/test/odata.actions.js @@ -1,43 +1,110 @@ import 'should'; import request from 'supertest'; -import { odata, host, port, bookSchema } from './support/setup'; -import data from './support/books.json'; -import FakeDb from './support/fake-db'; +import { odata, host, port, assertSuccess } from './support/setup'; +import { BookMetadata } from './support/books.model'; +import should from 'should'; function requestToHalfPrice(id) { - return request(host).post(`/book(${id})/50off`); -} - -function halfPrice(price) { - return +(price / 2).toFixed(2); + return request(host).post(`/book('${id}')/50off`); } describe('odata.actions', () => { - let httpServer, books; - - before(async function() { - const db = new FakeDb(); - const server = odata(db); - server - .resource('book', bookSchema) - .action('/50off', (req, res, next) => { - server.resources.book.model.findById(req.params.id, (err, book) => { - book.price = halfPrice(book.price); - book.save((err) => res.jsonp(book)); + let httpServer, server; + + beforeEach(async function () { + server = odata(); + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + }); + + it('should work with bound action', async function () { + server.entity('book', undefined, BookMetadata) + .action('50off', (req, res, next) => { + res.$odata.status = 200; + res.$odata.result = {}; + req.$odata.$Key.id.should.be.equal('AFFE'); + next(); + }, { + binding: 'entity' }); - }); - books = JSON.parse( JSON.stringify( db.addData('book', data))); httpServer = server.listen(port); + + const res = await requestToHalfPrice('AFFE'); + assertSuccess(res); }); - after(() => { - httpServer.close(); + it('should work with unbound action', async function () { + server.action('salam-aleikum', async (req, res) => { + res.$odata.result = { result: 'Wa aleikum assalam' }; + }) + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.salam-aleikum`); + + if (!res.ok) { + res.res.statusMessage.should.be.equal(''); + } + + res.body.result.should.be.equal('Wa aleikum assalam'); }); - it('should work', async function() { - const item = books[0]; - const res = await requestToHalfPrice(item.id); - const price = halfPrice(item.price); - res.body.price.should.be.equal(price); + it('should return 404 for action url without namespace', async function () { + server.action('salam-aleikum', async (req, res) => { + res.$odata.result = { result: 'Wa aleikum assalam' }; + }) + httpServer = server.listen(port); + + const res = await request(host).post(`/salam-aleikum`); + + res.res.statusMessage.should.be.equal('Not Found'); + + }); + + it('should throw error for not supported option', async function () { + should(() => { + server.action('salam-aleikum', async (req, res) => { + res.$odata.result = { result: 'Wa aleikum assalam' }; + }, { + unsupportedOption: true + }); + }).throw(`Option 'unsupportedOption' is not supported`); + + }); + + it('should work with complex parameters', async function () { + const name = { + first: 'Max', + last: 'Mustermann' + }; + + server.complexType('fullName', { + first: { + $Type: 'Edm.String' + }, + last: { + $Type: 'Edm.String' + } + }); + server.action('someThing', async (req, res) => { + req.$odata.$Parameter.should.have.property('name'); + req.$odata.$Parameter.name.should.deepEqual(name) + res.$odata.status = 204; + }, { + $Parameter: [{ + $Name: 'name', + $Type: 'node.odata.fullName' + }] + }) + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.someThing`).send({name}); + + assertSuccess(res); + res.status.should.be.equal(204); + }); }); diff --git a/test/odata.actions.parameter.js b/test/odata.actions.parameter.js new file mode 100644 index 0000000..f45be9f --- /dev/null +++ b/test/odata.actions.parameter.js @@ -0,0 +1,71 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port } from './support/setup'; + +describe('odata.actions', () => { + let httpServer, server; + + beforeEach(async function () { + server = odata(); + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + }); + + + it('should parse given parameter', async function () { + const parameter = { + newPassword: 'All parameters given', + repeat: 'Content is everything, but not yet' + }; + + server.action('change-password', (req, res, next) => { + req.$odata.$Parameter.should.deepEqual(parameter); + res.$odata.status = 204; + next(); + }, { + $Parameter: [{ + $Type: 'Edm.String', + $Name: 'newPassword' + }, { + $Type: 'Edm.String', + $Name: 'repeat' + }] + }); + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.change-password`).send(parameter); + res.statusCode.should.equal(204); + }); + + it('should fail if required parameter is not given', async function () { + server.action('change-password', (req, res, next) => { + should.fail(false, true, 'Not aborted although required parameters were not specified'); + next(); + }, { + $Parameter: [{ + $Type: 'Edm.String', + $Name: 'newPassword' + }, { + $Type: 'Edm.String', + $Name: 'repeat' + }] + }); + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.change-password`).send({ + newPassword: 'Not all parameters given' + }); + res.statusCode.should.equal(400); + res.body.should.deepEqual({ + error: { + code: '400', + message: `Obligatory parameter 'repeat' not given` + } + }); + }); + +}); diff --git a/test/odata.batch.js b/test/odata.batch.js new file mode 100644 index 0000000..2e594b3 --- /dev/null +++ b/test/odata.batch.js @@ -0,0 +1,460 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from './support/setup'; +import data from './support/books.json'; +import { BookMetadata } from './support/books.model'; + +describe('odata.batch', () => { + const books = data; + let httpServer, resource, sandbox; + + afterEach(() => { + httpServer.close(); + }); + + it('should work with get lists', async function () { + const result = books.filter(item => item.title.indexOf('Guide') >= 0) + .map(item => ({ title: item.title })); + const server = odata(); + + server.entity('book', { + list: (req, res, next) => { + req.$odata.$filter.should.deepEqual({ + title: { + $function: { + $name: 'contains', + $parameter: 'Guide', + $operator: undefined, + $value: undefined + } + } + }); + req.$odata.$select.should.deepEqual(['title']); + res.$odata.result = { + value: result + }; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).post(`/$batch`).send({ + requests: [{ + id: "1", + method: "get", + url: `/book?$filter=contains(title, 'Guide')&$select=title` + }] + }); + assertSuccess(res); + res.body.should.deepEqual({ + responses: [{ + id: "1", + status: 200, + statusText: 'OK', + headers: { + 'OData-Version': '4.0', + 'content-type': 'application/json' + }, + body: { + value: result + } + }] + }); + }); + + it('should work with get entity', async function () { + const server = odata(); + + server.entity('book', { + get: (req, res, next) => { + req.$odata.$Key.id.should.be.equal(books[0].id); + res.$odata.result = books[0]; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).post(`/$batch`).send({ + requests: [{ + id: "1", + method: "get", + url: `/book('${books[0].id}')` + }] + }); + assertSuccess(res); + res.body.should.deepEqual({ + responses: [{ + id: "1", + status: 200, + statusText: 'OK', + headers: { + 'OData-Version': '4.0', + 'content-type': 'application/json' + }, + body: books[0] + }] + }); + }); + + it('should work with get one of multiple entity types', async function () { + const server = odata(); + + server.entity('affe', null, BookMetadata); + + server.entity('book', { + get: (req, res, next) => { + req.$odata.$Key.id.should.be.equal(books[0].id); + res.$odata.result = books[0]; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).post(`/$batch`).send({ + requests: [{ + id: "1", + method: "get", + url: `/book('${books[0].id}')` + }] + }); + assertSuccess(res); + res.body.should.deepEqual({ + responses: [{ + id: "1", + status: 200, + statusText: 'OK', + headers: { + 'OData-Version': '4.0', + 'content-type': 'application/json' + }, + body: books[0] + }] + }); + }); + + it('should work with post entity', async function () { + const result = { + title: "War and peace", + createdAt: null, + updatedAt: null + }; + const server = odata(); + + server.entity('book', { + post: (req, res, next) => { + req.$odata.body.should.deepEqual(result); + res.$odata.result = { + id: "AFFE", + ...result + }; + res.$odata.status = 201; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).post(`/$batch`).send({ + requests: [{ + id: "1", + method: "post", + url: `/book`, + body: result + }] + }); + assertSuccess(res); + res.body.should.deepEqual({ + responses: [{ + id: "1", + status: 201, + statusText: 'Created', + headers: { + 'OData-Version': '4.0', + 'content-type': 'application/json' + }, + body: { + id: "AFFE", + ...result + } + }] + }); + }); + + it('should work with put entity', async function () { + const result = { + id: "1", + title: "War and peace" + }; + const server = odata(); + + server.entity('book', { + put: (req, res, next) => { + req.$odata.body.should.deepEqual(result); + req.$odata.$Key.id.should.be.equal(result.id); + res.$odata.result = result; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).post(`/$batch`).send({ + requests: [{ + id: "1", + method: "put", + url: `/book('1')`, + body: result + }] + }); + assertSuccess(res); + res.body.should.deepEqual({ + responses: [{ + id: "1", + status: 200, + statusText: "OK", + headers: { + 'OData-Version': '4.0', + 'content-type': 'application/json' + }, + body: result + }] + }); + }); + + + it('should work with patch entity', async function () { + const result = { + id: "1", + title: "War and peace" + }; + const server = odata(); + + server.entity('book', { + patch: (req, res, next) => { + req.$odata.body.should.deepEqual(result); + req.$odata.$Key.id.should.be.equal(result.id); + res.$odata.result = result; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).post(`/$batch`).send({ + requests: [{ + id: "1", + method: "patch", + url: `/book('1')`, + body: result + }] + }); + assertSuccess(res); + res.body.should.deepEqual({ + responses: [{ + id: "1", + status: 200, + statusText: "OK", + headers: { + "OData-Version": "4.0", + "content-type": "application/json" + }, + body: result + }] + }); + }); + + + it('should work with delete entity', async function () { + const server = odata(); + + server.entity('book', { + delete: (req, res, next) => { + req.$odata.$Key.id.should.be.equal('1'); + res.$odata.status = 204; + delete res.$odata.result; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).post(`/$batch`).send({ + requests: [{ + id: "1", + method: "delete", + url: `/book('1')` + }] + }); + assertSuccess(res); + res.body.should.deepEqual({ + responses: [{ + id: "1", + status: 204, + statusText: "No Content" + }] + }); + }); + + it('should work with unbound action', async function () { + const server = odata(); + + server.action('unbound-action', (req, res, next) => { + res.$odata.result = { result: 'Hello! I am an unbound action.' }; + next(); + }); + httpServer = server.listen(port); + + const res = await request(host).post(`/$batch`).send({ + requests: [{ + id: "1", + method: "post", + url: `/unbound-action` + }] + }); + assertSuccess(res); + res.body.should.deepEqual({ + responses: [{ + id: "1", + status: 200, + statusText: "OK", + headers: { + "OData-Version": "4.0", + "content-type": "application/json" + }, + body: { + result: 'Hello! I am an unbound action.' + } + }] + }); + }); + + it('should work with action, that bound to entity', async function () { + const server = odata(); + const resource = server.entity('book', { + }, BookMetadata); + resource.action('entity-action', (req, res, next) => { + req.$odata.$Key.id.should.be.equal(books[0].id); + res.$odata.result = { result: 'Hello! I am an action, that bound to entity.' }; + next(); + }, { binding: 'entity' }); + + httpServer = server.listen(port); + + const res = await request(host).post(`/$batch`).send({ + requests: [{ + id: "1", + method: "post", + url: `/book('${books[0].id}')/entity-action` + }] + }); + assertSuccess(res); + res.body.should.deepEqual({ + responses: [{ + id: "1", + status: 200, + statusText: "OK", + headers: { + "OData-Version": "4.0", + "content-type": "application/json" + }, + body: { + result: 'Hello! I am an action, that bound to entity.' + } + }] + }); + }); + + it('Calls to bevore hooks should be done synchronously', async function () { + const server = odata(); + const resource = server.entity('book', { + delete: (req, res, next) => { + req.$odata.$Key.id.should.be.equal('1'); + res.$odata.status = 204; + next(); + } + }, BookMetadata); + + resource.addBefore([(req, res, next) => { + res.$odata.should.not.have.property('result'); + res.$odata.result = 0; + next(); + },(req, res, next) => { + res.$odata.result.should.be.equal(0); + res.$odata.result = 1; + next(); + }, async (req, res, next) => { + res.$odata.result.should.be.equal(1); + + const promise = new Promise((resolve, reject) => { + setTimeout(() => { + resolve(2); + }, 0); + }); + res.$odata.result = await promise; + }, async (req, res, next) => { + res.$odata.result.should.be.equal(2); + + const promise = new Promise((resolve, reject) => { + setTimeout(() => { + resolve(3); + }, 0); + }); + res.$odata.result = await promise; + next(); + }, (req, res, next) => { + res.$odata.result.should.be.equal(3); + next(); + }]) + + httpServer = server.listen(port); + + const res = await request(host).post(`/$batch`).send({ + requests: [{ + id: "1", + method: "delete", + url: `/book('1')` + }] + }); + assertSuccess(res); + res.body.should.deepEqual({ + responses: [{ + id: "1", + status: 204, + statusText: "No Content" + }] + }); + }); + /* + it('should work with multipart request body', async function () { + const result = { + title: "War and peace" + }; + const res = await request(host) + .post(`/$batch`) + .send({}) + .set('Content-Type', 'multipart/mixed; boundary=batch_1') + .set('Host', host) + .serialize(() => ` + --batch_1 + Content-Type: application/http + + POST /book + Host: ${host} + Content-Type: application/json + Content-Length: ${JSON.stringify(result).length} + + ${JSON.stringify(result)} + --batch_1-- + `); + + assertSuccess(res); + + res.text.should.equal(` + --batch-1 + Content-Type: application/http + + HTTP/1.1 200 Ok + Content-Type: application/json + Content-Length: ${JSON.stringify(result).length} + + ${JSON.stringify(result)} + --batch-1— + `); + });*/ +}); diff --git a/test/odata.entity.js b/test/odata.entity.js new file mode 100644 index 0000000..074270d --- /dev/null +++ b/test/odata.entity.js @@ -0,0 +1,157 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from './support/setup'; + +describe('odata.entity', () => { + let httpServer, server; + + beforeEach(async function () { + server = odata(); + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + }); + + it('should work with custom implementation', async function () { + const result = [{ + "id": '1', + "price": 44.95, + "title": "XML Developer's Guide" + }, + { + "id": '1', + "price": 5.95, + "title": "Midnight Rain" + }]; + server.entity('book', { + list: (req, res, next) => { + res.$odata.result = { + value: result + }; + next(); + } + }, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + title: { + $Type: 'Edm.String' + }, + price: { + $Type: 'Edm.Decimal', + $Precision: 10, + $Scale: 2 + } + }); + httpServer = server.listen(port); + + const res = await request(host).get(`/book`); + + if (!res.ok) { + res.res.statusMessage.should.be.equal(''); + } + + res.body.should.deepEqual({ + value: result + }); + }); + + it('should return 501 for not implemented methods', async function () { + const result = [{ + "id": '1', + "price": 44.95, + "title": "XML Developer's Guide" + }, + { + "id": '1', + "price": 5.95, + "title": "Midnight Rain" + }]; + server.entity('book', null, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + title: { + $Type: 'Edm.String' + }, + price: { + $Type: 'Edm.Decimal', + $Precision: 10, + $Scale: 2 + } + }); + httpServer = server.listen(port); + + const res = await request(host).get(`/book`); + + res.res.statusMessage.should.be.equal('Not Implemented'); + + res.body.should.deepEqual({ error: { code: '501', message: 'Not Implemented' } }); + }); + + it('should return datetimeoffsets without milliseconds', async function () { + server.entity('book', { + get: (req, res, next) => { + res.$odata.result = { + "id": '1', + "createdAt": new Date(Date.parse("2019-01-01T00:00:00.000Z")) + }; + next(); + } + }, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + createdAt: { + $Type: 'Edm.DateTimeOffset' + } + }); + httpServer = server.listen(port); + + const res = await request(host).get(`/book('1')`); + + res.body.should.deepEqual({ + "id": '1', + "createdAt": "2019-01-01T00:00:00Z" + }); + }); + + it('should return null for nullable values automatically', async function () { + server.entity('book', { + get: (req, res, next) => { + res.$odata.result = { + "id": '1' + }; + next(); + } + }, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + createdAt: { + $Type: 'Edm.DateTimeOffset', + $Nullable: true + } + }); + httpServer = server.listen(port); + + const res = await request(host).get(`/book('1')`); + + res.body.should.deepEqual({ + "id": '1', + "createdAt": null + }); + }); + +}); diff --git a/test/odata.error.js b/test/odata.error.js new file mode 100644 index 0000000..b8e5fdf --- /dev/null +++ b/test/odata.error.js @@ -0,0 +1,80 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port } from './support/setup'; + +describe('odata.actions', () => { + let httpServer, server; + + beforeEach(async function () { + server = odata(); + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + }); + + it('should return odata error object with status 500 if no status given', async function () { + server.action('server-error', (req, res, next) => { + throw new Error("This message should not go to client"); + }); + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.server-error`) + + res.status.should.be.equal(500); + res.res.statusMessage.should.be.equal('Internal Server Error'); + res.body.should.deepEqual({ + error: { + code: "500", + message: "Internal Server Error" + } + + }); + }); + + it('should not return custom message if status is bigger or equal 500', async function () { + server.action('server-error', (req, res, next) => { + const error = new Error("This message should not go to client"); + + error.status = 501; + throw error; + }); + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.server-error`) + + res.status.should.be.equal(501); + res.res.statusMessage.should.be.equal('Not Implemented'); + res.body.should.deepEqual({ + error: { + code: "501", + message: "Not Implemented" + } + + }); + }); + + it('should not return custom message if status is letter or equal 500', async function () { + server.action('server-error', (req, res, next) => { + const error = new Error("I can only brew tea"); + + error.status = 418; + throw error; + }); + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.server-error`) + + res.status.should.be.equal(418); + res.res.statusMessage.should.be.equal('I\'m a Teapot'); + res.body.should.deepEqual({ + error: { + code: "418", + message: "I can only brew tea" + } + + }); + }); +}); diff --git a/test/odata.filter.js b/test/odata.filter.js new file mode 100644 index 0000000..658112b --- /dev/null +++ b/test/odata.filter.js @@ -0,0 +1,290 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from './support/setup'; +import { BookMetadata } from './support/books.model'; + +describe('odata.filter', () => { + let httpServer, server; + + beforeEach(async function () { + server = odata(); + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + }); + + it('should work with single string equals', async function () { + server.entity('book', { + list: (req, res, next) => { + req.$odata.$filter.should.deepEqual({ title: { $eq: 'Midnight Rain' } }); + res.$odata.result = { value: [] }; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).get(`/book?$filter=title eq 'Midnight Rain'`); + + assertSuccess(res); + + }); + + it('should work with single $lt operator', async function () { + server.entity('book', { + list: (req, res, next) => { + req.$odata.$filter.should.deepEqual({ price: { $lt: 5.95 } }); + res.$odata.result = { value: [] }; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).get(`/book?$filter=price lt 5.95`); + + assertSuccess(res); + + }); + + it('should work with single $ge operator', async function () { + server.entity('book', { + list: (req, res, next) => { + req.$odata.$filter.should.deepEqual({ price: { $gte: 5.95 } }); + res.$odata.result = { value: [] }; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).get(`/book?$filter=price ge 5.95`); + + assertSuccess(res); + + }); + + it('should work with single $le operator', async function () { + server.entity('book', { + list: (req, res, next) => { + req.$odata.$filter.should.deepEqual({ price: { $lte: 5.95 } }); + res.$odata.result = { value: [] }; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).get(`/book?$filter=price le 5.95`); + + assertSuccess(res); + + }); + + it('should filter items when it has extra spaces at begin', async function () { + server.entity('book', { + list: (req, res, next) => { + req.$odata.$filter.should.deepEqual({ title: { $eq: 'Midnight Rain' } }); + res.$odata.result = { value: [] }; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).get(`/book?$filter= title eq 'Midnight Rain'`); + + assertSuccess(res); + }); + it('should filter items when it has extra spaces at mid', async function () { + server.entity('book', { + list: (req, res, next) => { + req.$odata.$filter.should.deepEqual({ title: { $eq: 'Midnight Rain' } }); + res.$odata.result = { value: [] }; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).get(`/book?$filter=title eq 'Midnight Rain'`); + + assertSuccess(res); + }); + it('should filter items when it has extra spaces at end', async function () { + server.entity('book', { + list: (req, res, next) => { + req.$odata.$filter.should.deepEqual({ title: { $eq: 'Midnight Rain' } }); + res.$odata.result = { value: [] }; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).get(`/book?$filter=title eq 'Midnight Rain' `); + + assertSuccess(res); + }); + it('should filter items when use chinese keyword', async function () { + server.entity('book', { + list: (req, res, next) => { + req.$odata.$filter.should.deepEqual({ title: { $eq: '代码大全' } }); + res.$odata.result = { value: [] }; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).get(encodeURI(`/book?$filter=title eq '代码大全'`)); + + assertSuccess(res); + }); + + it(`should work with 'and' and two conditions on same property`, async function () { + server.entity('book', { + list: (req, res, next) => { + req.$odata.$filter.should.deepEqual({ + price: { + $lte: 5.95, + $gte: 4 + } + }); + res.$odata.result = { value: [] }; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).get(`/book?$filter=price le 5.95 and price ge 4`); + + assertSuccess(res); + + }); + + it("[and] should filter items when it has extra spaces", async function () { + server.entity('book', { + list: (req, res, next) => { + req.$odata.$filter.should.deepEqual({ + $and: [{ + title: { $ne: 'Midnight Rain' } + }, { + price: { $gte: 36.95 }, + }] + }); + res.$odata.result = { value: [] }; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).get(`/book?$filter=title ne 'Midnight Rain' and price ge 36.95`); + + assertSuccess(res); + }); + + it(`should work with 'and' and two conditions on different properties`, async function () { + server.entity('book', { + list: (req, res, next) => { + req.$odata.$filter.should.deepEqual({ + $and: [{ + price: { + $lte: 5.95 + } + }, { + author: { + $ne: 'Knorr, Stefan' + } + }] + }); + res.$odata.result = { value: [] }; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).get(`/book?$filter=price le 5.95 and author ne 'Knorr, Stefan'`); + + assertSuccess(res); + + }); + + it(`should work with 'or'`, async function () { + server.entity('book', { + list: (req, res, next) => { + req.$odata.$filter.should.deepEqual({ + $or: [{ + price: { + $lte: 5.95 + } + }, { + author: { + $ne: 'Knorr, Stefan' + } + }] + }); + res.$odata.result = { value: [] }; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).get(`/book?$filter=price le 5.95 or author ne 'Knorr, Stefan'`); + + assertSuccess(res); + + }); + + it(`should work with 'and' and 'or'`, async function () { + server.entity('book', { + list: (req, res, next) => { + req.$odata.$filter.should.deepEqual({ + $or: [{ + $and: [{ + price: { + $lte: 5.95 + } + }, { + author: { + $ne: 'Knorr, Stefan' + } + }] + }, { + $and: [{ + price: { + $gte: 5.95 + } + }, { + author: { + $eq: 'Knorr, Stefan' + } + }] + }] + + }); + res.$odata.result = { value: [] }; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).get(`/book?$filter=price le 5.95 and author ne 'Knorr, Stefan' or price ge 5.95 and author eq 'Knorr, Stefan'`); + + assertSuccess(res); + + }); + it('should use mapping', async function () { + const book = server.entity('book', { + list: (req, res, next) => { + req.$odata.$filter.should.deepEqual({ _id: { $eq: '2' } }); + res.$odata.result = { value: [] }; + next(); + } + }, BookMetadata, null); + + book.mapping.id = { + intern: '_id' + }; + httpServer = server.listen(port); + + const res = await request(host).get(encodeURI(`/book?$filter=id eq '2'`)); + + assertSuccess(res); + }); +}); diff --git a/test/odata.functions.js b/test/odata.functions.js index 6353209..1b2b9c3 100644 --- a/test/odata.functions.js +++ b/test/odata.functions.js @@ -1,7 +1,6 @@ import 'should'; import request from 'supertest'; import { odata, host, port, assertSuccess } from './support/setup'; -import FakeDb from './support/fake-db'; describe('odata.functions', () => { ['get', 'post', 'put', 'delete'].map((method) => { @@ -9,7 +8,7 @@ describe('odata.functions', () => { let httpServer; before(() => { - const server = odata(new FakeDb()); + const server = odata(); server.function('test', (req, res, next) => res.jsonp({ test: 'ok' }), { method }); diff --git a/test/odata.messages.js b/test/odata.messages.js new file mode 100644 index 0000000..02c9778 --- /dev/null +++ b/test/odata.messages.js @@ -0,0 +1,163 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from './support/setup'; + +// https://sapui5.hana.ondemand.com/sdk/#/topic/fbe1cb5613cf4a40a841750bf813238e.html + +describe('odata.actions', () => { + let httpServer, server; + + beforeEach(async function () { + server = odata(); + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + }); + + it('should return message header', async function () { + server.action('server-message', (req, res, next) => { + try { + res.$odata.messages.push({ + code: '0815', + message: 'Some message', + numericSeverity: 1 // 1 - success, 2 - info, 3 - warning, 4 - error + }); + res.$odata.status = 204; + next(); + + } catch (error) { + next(error); + } + }); + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.server-message`) + + assertSuccess(res); + res.headers.should.have.property('sap-messages'); + JSON.parse(res.headers['sap-messages']).should.deepEqual([{ + code: '0815', + message: 'Some message', + numericSeverity: 1 + }]); + }); + + it('should fail if code missing', async function () { + server.action('server-message', (req, res, next) => { + try { + res.$odata.messages.push({ + message: 'Some message', + numericSeverity: 1 // 1 - success, 2 - info, 3 - warning, 4 - error + }); + res.$odata.status = 204; + next(); + + } catch (error) { + next(error); + } + }); + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.server-message`) + + res.status.should.be.equal(500); + res.res.statusMessage.should.be.equal('Internal Server Error'); + res.body.should.deepEqual({ + error: { + code: "500", + message: "Internal Server Error" + } + + }); + }); + + it('should fail if message property missing', async function () { + server.action('server-message', (req, res, next) => { + try { + res.$odata.messages.push({ + code: '0815', + numericSeverity: 1 // 1 - success, 2 - info, 3 - warning, 4 - error + }); + res.$odata.status = 204; + next(); + + } catch (error) { + next(error); + } + }); + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.server-message`) + + res.status.should.be.equal(500); + res.res.statusMessage.should.be.equal('Internal Server Error'); + res.body.should.deepEqual({ + error: { + code: "500", + message: "Internal Server Error" + } + + }); + }); + + it('should fail if severity property not given', async function () { + server.action('server-message', (req, res, next) => { + try { + res.$odata.messages.push({ + code: '0815', + message: 'Some message' + }); + res.$odata.status = 204; + next(); + + } catch (error) { + next(error); + } + }); + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.server-message`) + + res.status.should.be.equal(500); + res.res.statusMessage.should.be.equal('Internal Server Error'); + res.body.should.deepEqual({ + error: { + code: "500", + message: "Internal Server Error" + } + + }); + }); + it('should fail if invalid severity given', async function () { + server.action('server-message', (req, res, next) => { + try { + res.$odata.messages.push({ + code: '0815', + message: 'Some message', + numericSeverity: 99 + }); + res.$odata.status = 204; + next(); + + } catch (error) { + next(error); + } + }); + httpServer = server.listen(port); + + const res = await request(host).post(`/node.odata.server-message`) + + res.status.should.be.equal(500); + res.res.statusMessage.should.be.equal('Internal Server Error'); + res.body.should.deepEqual({ + error: { + code: "500", + message: "Internal Server Error" + } + + }); + }); +}); diff --git a/test/odata.query.count.js b/test/odata.query.count.js deleted file mode 100644 index 164451e..0000000 --- a/test/odata.query.count.js +++ /dev/null @@ -1,36 +0,0 @@ -import 'should'; -import request from 'supertest'; -import { odata, host, port, bookSchema } from './support/setup'; -import books from './support/books.json'; -import FakeDb from './support/fake-db'; - -describe('odata.query.count', function() { - let httpServer; - - before(async function() { - const db = new FakeDb(); - const server = odata(db); - server.resource('book', bookSchema); - db.addData('book', books); - httpServer = server.listen(port); - }); - - after(() => { - httpServer.close(); - }); - - it('should get count', async function() { - const res = await request(host).get('/book?$count=true'); - res.body.should.be.have.property('@odata.count'); - res.body.should.be.have.property('value'); - res.body['@odata.count'].should.be.equal(res.body.value.length); - }); - it('should not get count', async function() { - const res = await request(host).get('/book?$count=false'); - res.body.should.be.not.have.property('@odata.count'); - }); - it('should 500 when $count isn\'t \'true\' or \'false\'', async function() { - const res = await request(host).get('/book?$count=1'); - res.error.status.should.be.equal(500); - }); -}); diff --git a/test/odata.query.filter.functions.js b/test/odata.query.filter.functions.js deleted file mode 100644 index 705ee4e..0000000 --- a/test/odata.query.filter.functions.js +++ /dev/null @@ -1,63 +0,0 @@ -import 'should'; -import sinon from 'sinon'; -import request from 'supertest'; -import { odata, host, port, bookSchema } from './support/setup'; -import data from './support/books.json'; -import FakeDb from './support/fake-db'; - -describe('odata.query.filter.functions', function () { - let httpServer, mock, resource; - - before(async function () { - const db = new FakeDb(); - const server = odata(db); - resource = server.resource('book', bookSchema) - httpServer = server.listen(port); - db.addData('book', data); - }); - - after(() => { - httpServer.close(); - }); - - describe('[contains]', () => { - it('should filter items', async function () { - mock = sinon.mock(resource.model); - mock.expects('$where').once().withArgs(`this.title.indexOf('i') != -1`).returns(resource.model); - await request(host).get(`/book?$filter=contains(title,'i')`); - mock.verify(); - }); - it('should filter items when it has extra spaces in query string', async function () { - mock = sinon.mock(resource.model); - mock.expects('$where').once().withArgs(`this.title.indexOf('Visual Studio') != -1`).returns(resource.model); - await request(host).get(`/book?$filter=contains(title,'Visual Studio')`); - mock.verify(); - }); - }); - - describe('[indexof]', () => { - it('should filter items', async function () { - mock = sinon.mock(resource.model); - mock.expects('$where').once().withArgs(`this.title.indexOf('i') >= 1`).returns(resource.model); - await request(host).get(`/book?$filter=indexof(title,'i') ge 1`); - mock.verify(); - }); - it('should filter items when it has extra spaces in query string', async function () { - mock = sinon.mock(resource.model); - mock.expects('$where').once().withArgs(`this.title.indexOf('Visual Studio') >= 0`).returns(resource.model); - const res = await request(host).get(`/book?$filter=indexof(title,'Visual Studio') ge 0`); - mock.verify(); - }); - }); - - describe('[year]', () => { - it('should filter items', async function () { - mock = sinon.mock(resource.model); - mock.expects('where').once().withArgs(`publish_date`).returns(resource.model); - mock.expects('gte').once().withArgs(new Date(2000, 0, 1)).returns(resource.model); - mock.expects('lt').once().withArgs(new Date(2001, 0, 1)).returns(resource.model); - const res = await request(host).get(`/book?$filter=year(publish_date) eq 2000`); - mock.verify(); - }); - }); -}); diff --git a/test/odata.query.filter.js b/test/odata.query.filter.js deleted file mode 100644 index 17ab8ac..0000000 --- a/test/odata.query.filter.js +++ /dev/null @@ -1,150 +0,0 @@ -import 'should'; -import sinon from 'sinon'; -import request from 'supertest'; -import { odata, host, port, bookSchema } from './support/setup'; -import data from './support/books.json'; -import FakeDb from './support/fake-db'; - -describe('odata.query.filter', function() { - let httpServer, books, resource, mock; - - before(async function() { - const db = new FakeDb(); - const server = odata(db); - server.resource('book', bookSchema); - resource = server.resources.book; - httpServer = server.listen(port); - books = db.addData('book', data); - }); - - after(() => { - httpServer.close(); - }); - - afterEach(() => { - mock.restore(); - }); - - describe('[Equal]', () => { - it('should filter items', async function(){ - mock = sinon.mock(resource.model); - mock.expects('where').once().withArgs('title').returns(resource.model); - mock.expects('equals').once().withArgs(data[1].title).returns(resource.model); - await request(host).get(`/book?$filter=title eq '${data[1].title}'`); - mock.verify(); - }); - it('should filter items when field has keyword', async function(){ - mock = sinon.mock(resource.model); - mock.expects('where').once().withArgs('author').returns(resource.model); - mock.expects('equals').once().withArgs('Ralls, Kim').returns(resource.model); - await request(host).get(`/book?$filter=author eq 'Ralls, Kim'`); - mock.verify(); - }); - it('should filter items when it has extra spaces at begin', async function(){ - mock = sinon.mock(resource.model); - mock.expects('where').once().withArgs('title').returns(resource.model); - mock.expects('equals').once().withArgs(data[1].title).returns(resource.model); - await request(host).get(`/book?$filter= title eq '${data[1].title}'`); - mock.verify(); - }); - it('should filter items when it has extra spaces at mid', async function(){ - mock = sinon.mock(resource.model); - mock.expects('where').once().withArgs('title').returns(resource.model); - mock.expects('equals').once().withArgs(data[1].title).returns(resource.model); - await request(host).get(`/book?$filter=title eq '${data[1].title}'`); - mock.verify(); - }); - it('should filter items when it has extra spaces at end', async function(){ - mock = sinon.mock(resource.model); - mock.expects('where').once().withArgs('title').returns(resource.model); - mock.expects('equals').once().withArgs(data[1].title).returns(resource.model); - await request(host).get(`/book?$filter=title eq '${data[1].title}' `); - mock.verify(); - }); - it('should filter items when use chinese keyword', async function(){ - mock = sinon.mock(resource.model); - mock.expects('where').once().withArgs('title').returns(resource.model); - mock.expects('equals').once().withArgs('代码大全').returns(resource.model); - await request(host).get(encodeURI(`/book?$filter=title eq '代码大全'`)); - mock.verify(); - }); - it('should filter items when use id', async function(){ - mock = sinon.mock(resource.model); - mock.expects('where').once().withArgs('_id').returns(resource.model); - mock.expects('equals').once().withArgs(books[1].id).returns(resource.model); - await request(host).get(encodeURI(`/book?$filter=id eq '${books[1].id}'`)); - mock.verify(); - }); - }); - - describe("[Not equal]", () => { - it('should filter items', async function(){ - mock = sinon.mock(resource.model); - mock.expects('where').once().withArgs('title').returns(resource.model); - mock.expects('ne').once().withArgs(data[1].title).returns(resource.model); - await request(host).get(`/book?$filter=title ne '${data[1].title}'`); - mock.verify(); - }); - }); - - describe("[Greater than]", () => { - it('should filter items', async function(){ - mock = sinon.mock(resource.model); - mock.expects('where').once().withArgs('price').returns(resource.model); - mock.expects('gt').once().withArgs(36.95).returns(resource.model); - await request(host).get(`/book?$filter=price gt 36.95`); - mock.verify(); - }); - }); - - describe('[Greater than or equal]', () => { - it('should filter items', async function(){ - mock = sinon.mock(resource.model); - mock.expects('where').once().withArgs('price').returns(resource.model); - mock.expects('gte').once().withArgs(36.95).returns(resource.model); - await request(host).get(`/book?$filter=price ge 36.95`); - mock.verify(); - }); - }); - - describe('[Less than]', () => { - it('should filter items', async function() { - mock = sinon.mock(resource.model); - mock.expects('where').once().withArgs('price').returns(resource.model); - mock.expects('lt').once().withArgs(36.95).returns(resource.model); - await request(host).get(`/book?$filter=price lt 36.95`); - mock.verify(); - }); - }); - - describe('[Less than or equal]', () => { - it('should filter items', async function() { - mock = sinon.mock(resource.model); - mock.expects('where').once().withArgs('price').returns(resource.model); - mock.expects('lte').once().withArgs(36.95).returns(resource.model); - await request(host).get(`/book?$filter=price le 36.95`); - mock.verify(); - }); - }); - - describe('[Logical and]', () => { - it("should filter items", async function() { - mock = sinon.mock(resource.model); - mock.expects('where').withArgs('title').returns(resource.model); - mock.expects('where').withArgs('price').returns(resource.model); - mock.expects('ne').once().withArgs(data[1].title).returns(resource.model); - mock.expects('gte').once().withArgs(36.95).returns(resource.model); - await request(host).get(`/book?$filter=title ne '${data[1].title}' and price ge 36.95`); - mock.verify(); - }); - it("should filter items when it has extra spaces", async function() { - mock = sinon.mock(resource.model); - mock.expects('where').withArgs('title').returns(resource.model); - mock.expects('where').withArgs('price').returns(resource.model); - mock.expects('ne').once().withArgs(data[1].title).returns(resource.model); - mock.expects('gte').once().withArgs(36.95).returns(resource.model); - await request(host).get(`/book?$filter=title ne '${data[1].title}' and price ge 36.95`); - mock.verify(); - }); - }); -}); diff --git a/test/odata.query.orderby.js b/test/odata.query.orderby.js deleted file mode 100644 index e2b1a3c..0000000 --- a/test/odata.query.orderby.js +++ /dev/null @@ -1,72 +0,0 @@ -import 'should'; -import sinon from 'sinon'; -import request from 'supertest'; -import { odata, host, port, bookSchema } from './support/setup'; -import data from './support/books.json'; -import FakeDb from './support/fake-db'; - -describe('odata.query.orderby', () => { - let httpServer, mock, resource; - - before(async function() { - const db = new FakeDb(); - const server = odata(db); - resource = server.resource('book', bookSchema) - httpServer = server.listen(port); - db.addData('book', data); - }); - - after(() => { - httpServer.close(); - }); - - afterEach(() => { - mock.restore(); - }); - - it('should default let items order with asc', async function() { - mock = sinon.mock(resource.model); - mock.expects('sort').once().withArgs({ - price: 'asc' - }).returns(resource.model); - await request(host).get('/book?$orderby=price'); - mock.verify(); - }); - - it('should let items order asc', async function() { - mock = sinon.mock(resource.model); - mock.expects('sort').once().withArgs({ - price: 'asc' - }).returns(resource.model); - await request(host).get('/book?$orderby=price asc'); - mock.verify(); - }); - - it('should let items order desc', async function() { - mock = sinon.mock(resource.model); - mock.expects('sort').once().withArgs({ - price: 'desc' - }).returns(resource.model); - await request(host).get('/book?$orderby=price desc'); - mock.verify(); - }); - - it('should let items order when use multiple fields', async function() { - mock = sinon.mock(resource.model); - mock.expects('sort').once().withArgs({ - price: 'asc', - title: 'asc' - }).returns(resource.model); - await request(host).get('/book?$orderby=price,title'); - mock.verify(); - }); - - it("should be ignore when order by not exist field", async function() { - mock = sinon.mock(resource.model); - mock.expects('sort').once().withArgs({ - 'not-exist-field': 'asc' - }).returns(resource.model); - await request(host).get('/book?$orderby=not-exist-field'); - mock.verify(); - }); -}); diff --git a/test/odata.query.select.js b/test/odata.query.select.js deleted file mode 100644 index fe9e567..0000000 --- a/test/odata.query.select.js +++ /dev/null @@ -1,83 +0,0 @@ -import 'should'; -import sinon from 'sinon'; -import request from 'supertest'; -import { odata, host, port, bookSchema } from './support/setup'; -import data from './support/books.json'; -import FakeDb from './support/fake-db'; - -describe('odata.query.select', () => { - let httpServer, mock, resource; - - before(async function() { - const db = new FakeDb(); - const server = odata(db); - resource = server.resource('book', bookSchema); - resource.model.model.schema.tree = { - id: { - select: true - }, - price: { - select: true - }, - title: { - select: true - } - } - httpServer = server.listen(port); - db.addData('book', data); - }); - - after(() => { - httpServer.close(); - }); - - afterEach(() => { - mock.restore(); - }); - - it('should select anyone field', async function() { - mock = sinon.mock(resource.model); - mock.expects('select').once().withArgs({ - _id: 0, - price: 1 - }).returns(resource.model); - await request(host).get('/book?$select=price'); - mock.verify(); - }); - it('should select multiple field', async function() { - mock = sinon.mock(resource.model); - mock.expects('select').once().withArgs({ - _id: 0, - price: 1, - title: 1 - }).returns(resource.model); - await request(host).get('/book?$select=price,title'); - mock.verify(); - }); - it('should select multiple field with blank space', async function() { - mock = sinon.mock(resource.model); - mock.expects('select').once().withArgs({ - _id: 0, - price: 1, - title: 1 - }).returns(resource.model); - await request(host).get('/book?$select=price, title'); - mock.verify(); - }); - it('should select id field', async function() { - mock = sinon.mock(resource.model); - mock.expects('select').once().withArgs({ - _id: 1, - price: 1, - title: 1 - }).returns(resource.model); - await request(host).get('/book?$select=price,title,id'); - mock.verify(); - }); - it('should ignore when select not exist field', async function() { - mock = sinon.mock(resource.model); - mock.expects('select').never(); - await request(host).get('/book?$select=not-exist-field'); - mock.verify(); - }); -}); diff --git a/test/odata.query.skip.js b/test/odata.query.skip.js deleted file mode 100644 index ae146c5..0000000 --- a/test/odata.query.skip.js +++ /dev/null @@ -1,50 +0,0 @@ -import 'should'; -import sinon from 'sinon'; -import request from 'supertest'; -import { odata, host, port, books, bookSchema } from './support/setup'; -import FakeDb from './support/fake-db'; - -describe('odata.query.skip', () => { - let httpServer, mock, resource; - - before(async function() { - const db = new FakeDb(); - const server = odata(db); - resource = server.resource('book', bookSchema) - httpServer = server.listen(port); - db.addData('book', books); - }); - - after(() => { - httpServer.close(); - }); - - afterEach(() => { - mock.restore(); - }); - - it('should skip items', async function() { - mock = sinon.mock(resource.model); - mock.expects('skip').once().withArgs(1).returns(resource.model); - await request(host).get('/book?$skip=1'); - mock.verify(); - }); - it('should ignore when skip over count of items', async function() { - mock = sinon.mock(resource.model); - mock.expects('skip').once().withArgs(1024).returns(resource.model); - await request(host).get('/book?$skip=1024'); - mock.verify(); - }); - it('should ignore when skip not a number', async function() { - mock = sinon.mock(resource.model); - mock.expects('skip').never(); - await request(host).get('/book?$skip=not-a-number'); - mock.verify(); - }); - return it('should ignore when skip not a positive number', async function() { - mock = sinon.mock(resource.model); - mock.expects('skip').never(); - await request(host).get('/book?$skip=-1'); - mock.verify(); - }); -}); diff --git a/test/odata.query.top.js b/test/odata.query.top.js deleted file mode 100644 index 334225b..0000000 --- a/test/odata.query.top.js +++ /dev/null @@ -1,44 +0,0 @@ -import 'should'; -import sinon from 'sinon'; -import request from 'supertest'; -import FakeDb from './support/fake-db'; -import { odata, host, port, books, bookSchema } from './support/setup'; - -describe('odata.query.top', () => { - let httpServer, mock, resource; - - before(async function() { - const db = new FakeDb() - const server = odata(db); - resource = server.resource('book', bookSchema) - httpServer = server.listen(port); - db.addData('book', books); - }); - - after(() => { - httpServer.close(); - }); - - afterEach(() => { - mock.restore(); - }); - - it('should top items', async function() { - mock = sinon.mock(resource.model); - mock.expects('limit').once().withArgs(1).returns(resource.model); - const res = await request(host).get('/book?$top=1'); - mock.verify(); - }); - it('should iginre when top not a number', async function() { - mock = sinon.mock(resource.model); - mock.expects('limit').never(); - const res = await request(host).get('/book?$top=not-a-number'); - mock.verify(); - }); - it('should ignore when top not a positive number', async function() { - mock = sinon.mock(resource.model); - mock.expects('limit').never(); - const res = await request(host).get('/book?$top=-1'); - mock.verify(); - }); -}); diff --git a/test/odata.select.js b/test/odata.select.js new file mode 100644 index 0000000..7a29b5f --- /dev/null +++ b/test/odata.select.js @@ -0,0 +1,51 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port, assertSuccess } from './support/setup'; + +describe('odata.select', () => { + let httpServer, server; + + beforeEach(async function () { + server = odata(); + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + }); + + it('should work deep property', async function () { + server.complexType('fullName', { + first: { + $Type: 'Edm.String' + }, + last: { + $Type: 'Edm.String' + } + }); + server.entity('user', { + list: (req, res, next) => { + req.$odata.$select.should.deepEqual(['name.first']) + res.$odata.status = 204; + next(); + } + }, { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24, + $Nullable: true + }, + name: { + $Type: 'node.odata.fullName' + } + }); + httpServer = server.listen(port); + + const res = await request(host).get(`/user?$select=name/first`); + + assertSuccess(res); + }); + +}); diff --git a/test/options.maxSkip.js b/test/options.maxSkip.js index 5cce70f..8a5d2f5 100644 --- a/test/options.maxSkip.js +++ b/test/options.maxSkip.js @@ -1,63 +1,99 @@ import 'should'; -import sinon from 'sinon'; import request from 'supertest'; -import { odata, host, port, books, bookSchema } from './support/setup'; -import FakeDb from './support/fake-db'; +import { odata, host, port, assertSuccess } from './support/setup'; +import { BookMetadata } from './support/books.model'; describe('options.maxSkip', () => { - let httpServer, server, mock, resource; + let httpServer, server; beforeEach(async function() { - const db = new FakeDb(); - server = odata(db); - resource = server.resource('book', bookSchema); - db.addData('book', books); + server = odata(); + }); afterEach(() => { httpServer.close(); - mock.restore(); }); it('global-limit should work', async function() { - mock = sinon.mock(resource.model); - mock.expects('skip').once().withArgs(1).returns(resource.model); + server.entity('book', { + list: (req, res, next) => { + res.$odata.result = []; + res.$odata.status = 200; + req.$odata.$skip.should.be.equal(1); + next(); + } + }, BookMetadata); server.set('maxSkip', 1); httpServer = server.listen(port); - await request(host).get('/book?$skip=100'); - mock.verify(); + + const res = await request(host).get('/book?$skip=100'); + + assertSuccess(res); }); it('resource-limit should work', async function() { - mock = sinon.mock(resource.model); - mock.expects('skip').once().withArgs(1).returns(resource.model); - resource.maxSkip(1); + const entity = server.entity('book', { + list: (req, res, next) => { + res.$odata.result = []; + res.$odata.status = 200; + req.$odata.$skip.should.be.equal(1); + next(); + } + }, BookMetadata); + entity.set('maxSkip', 1); httpServer = server.listen(port); - await request(host).get('/book?$skip=100'); - mock.verify(); + + const res = await request(host).get('/book?$skip=100'); + + assertSuccess(res); }); it('should use resource-limit even global-limit already set', async function() { - mock = sinon.mock(resource.model); - mock.expects('skip').once().withArgs(1).returns(resource.model); + const entity = server.entity('book', { + list: (req, res, next) => { + res.$odata.result = []; + res.$odata.status = 200; + req.$odata.$skip.should.be.equal(1); + next(); + } + }, BookMetadata); server.set('maxSkip', 2); - resource.maxSkip(1); + entity.set('maxSkip', 1); httpServer = server.listen(port); - await request(host).get('/book?$skip=100'); - mock.verify(); + + const res = await request(host).get('/book?$skip=100'); + + assertSuccess(res); }); it('should use query-limit if it is minimum global-limit', async function() { - mock = sinon.mock(resource.model); - mock.expects('skip').once().withArgs(1).returns(resource.model); + server.entity('book', { + list: (req, res, next) => { + res.$odata.result = []; + res.$odata.status = 200; + req.$odata.$skip.should.be.equal(1); + next(); + } + }, BookMetadata); server.set('maxSkip', 2); httpServer = server.listen(port); - await request(host).get('/book?$skip=1'); - mock.verify(); + + const res = await request(host).get('/book?$skip=1'); + + assertSuccess(res); }); it('should use query-limit if it is minimum resource-limit', async function() { - mock = sinon.mock(resource.model); - mock.expects('skip').once().withArgs(1).returns(resource.model); - resource.maxSkip(2); + const entity = server.entity('book', { + list: (req, res, next) => { + res.$odata.result = []; + res.$odata.status = 200; + req.$odata.$skip.should.be.equal(1); + next(); + } + }, BookMetadata); + entity.set('maxSkip', 2); httpServer = server.listen(port); - await request(host).get('/book?$skip=1'); - mock.verify(); + + const res = await request(host).get('/book?$skip=1'); + + assertSuccess(res); }); }); diff --git a/test/options.maxTop.js b/test/options.maxTop.js index 34143d5..50cfb30 100644 --- a/test/options.maxTop.js +++ b/test/options.maxTop.js @@ -1,62 +1,99 @@ import 'should'; import sinon from 'sinon'; import request from 'supertest'; -import { odata, host, port, bookSchema } from './support/setup'; -import FakeDb from './support/fake-db'; +import { odata, host, port, assertSuccess } from './support/setup'; +import { BookMetadata } from './support/books.model'; describe('options.maxTop', () => { - let httpServer, server, resource, mock; + let httpServer, server; beforeEach(async function() { - const db = new FakeDb(); - server = odata(db); - resource = server.resource('book', bookSchema); + server = odata(); }); afterEach(() => { httpServer.close(); - mock.restore(); }); it('global-limit should work', async function() { - mock = sinon.mock(resource.model); - mock.expects('limit').once().withArgs(1).returns(resource.model); + server.entity('book', { + list: (req, res, next) => { + res.$odata.result = []; + res.$odata.status = 200; + req.$odata.$top.should.be.equal(1); + next(); + } + }, BookMetadata); server.set('maxTop', 1); httpServer = server.listen(port); - await request(host).get('/book?$top=100'); - mock.verify(); + + const res = await request(host).get('/book?$top=100'); + + assertSuccess(res); }); it('resource-limit should work', async function() { - mock = sinon.mock(resource.model); - mock.expects('limit').once().withArgs(1).returns(resource.model); - resource.maxTop(1); + const entity = server.entity('book', { + list: (req, res, next) => { + res.$odata.result = []; + res.$odata.status = 200; + req.$odata.$top.should.be.equal(1); + next(); + } + }, BookMetadata); + entity.set('maxTop', 1); httpServer = server.listen(port); - await request(host).get('/book?$top=2'); - mock.verify(); + + const res = await request(host).get('/book?$top=2'); + + assertSuccess(res); }); it('should use resource-limit even global-limit already set', async function() { - mock = sinon.mock(resource.model); - mock.expects('limit').once().withArgs(1).returns(resource.model); + const entity = server.entity('book', { + list: (req, res, next) => { + res.$odata.result = []; + res.$odata.status = 200; + req.$odata.$top.should.be.equal(1); + next(); + } + }, BookMetadata); server.set('maxTop', 2); - resource.maxTop(1); + entity.set('maxTop', 1); httpServer = server.listen(port); - await request(host).get('/book?$top=100'); - mock.verify(); + + const res = await request(host).get('/book?$top=100'); + + assertSuccess(res); }); it('should use query-limit if it is minimum global-limit', async function() { - mock = sinon.mock(resource.model); - mock.expects('limit').once().withArgs(1).returns(resource.model); + const entity = server.entity('book', { + list: (req, res, next) => { + res.$odata.result = []; + res.$odata.status = 200; + req.$odata.$top.should.be.equal(1); + next(); + } + }, BookMetadata); server.set('maxTop', 2); httpServer = server.listen(port); - await request(host).get('/book?$top=1'); - mock.verify(); + + const res = await request(host).get('/book?$top=1'); + + assertSuccess(res); }); it('should use query-limit if it is minimum resource-limit', async function() { - mock = sinon.mock(resource.model); - mock.expects('limit').once().withArgs(1).returns(resource.model); - resource.maxTop(2); + const entity = server.entity('book', { + list: (req, res, next) => { + res.$odata.result = []; + res.$odata.status = 200; + req.$odata.$top.should.be.equal(1); + next(); + } + }, BookMetadata); + entity.set('maxTop', 2); httpServer = server.listen(port); - await request(host).get('/book?$top=1'); - mock.verify(); + + const res = await request(host).get('/book?$top=1'); + + assertSuccess(res); }); }); diff --git a/test/options.prefix.js b/test/options.prefix.js index f188d38..c08dee5 100644 --- a/test/options.prefix.js +++ b/test/options.prefix.js @@ -1,13 +1,23 @@ import 'should'; import request from 'supertest'; -import { odata, host, port, bookSchema } from './support/setup'; -import FakeDb from './support/fake-db'; +import { odata, host, port, assertSuccess } from './support/setup'; +import { BookMetadata } from './support/books.model'; describe('options.prefix', () => { - let httpServer, db; + let httpServer, server; + function initEntity(server) { + server.entity('book', { + list: (req, res, next) => { + res.$odata.result = []; + res.$odata.status = 200; + next(); + } + }, BookMetadata); + } before(() => { - db = new FakeDb(); + server = odata(); + initEntity(server); }); afterEach(() => { @@ -15,26 +25,28 @@ describe('options.prefix', () => { }); it('should be work', async function() { - const server = odata(db); - server.resource('book', bookSchema); server.set('prefix', '/api'); httpServer = server.listen(port); + const res = await request(host).get('/api/book'); - res.status.should.be.equal(200); + + assertSuccess(res); }); it('should be 200 when do not add `/`', async function() { - const server = odata(db); - server.resource('book', bookSchema); server.set('prefix', 'api'); httpServer = server.listen(port); + const res = await request(host).get('/api/book'); - res.status.should.be.equal(200); + + assertSuccess(res); }); it('should be 200 when set it at init-function', async function() { - const server = odata(db, '/api'); - server.resource('book', bookSchema); + server = odata('/api'); + initEntity(server); httpServer = server.listen(port); + const res = await request(host).get('/api/book'); - res.status.should.be.equal(200); + + assertSuccess(res); }); }); diff --git a/test/rest.delete.js b/test/rest.delete.js deleted file mode 100644 index 9760a54..0000000 --- a/test/rest.delete.js +++ /dev/null @@ -1,41 +0,0 @@ -import 'should'; -import request from 'supertest'; -import { odata, host, port, bookSchema, assertSuccess } from './support/setup'; -import books from './support/books.json'; -import FakeDb from './support/fake-db'; - -describe('rest.delete', function() { - let data, httpServer; - - before(async function() { - const db = new FakeDb(); - const server = odata(db); - server.resource('book', bookSchema) - httpServer = server.listen(port); - data = db.addData('book', books); - }); - - after(() => { - httpServer.close(); - }); - - it('should delete resource if it exist', async function() { - const res = await request(host).del(`/book(${data[0].id})`); - assertSuccess(res); - res.status.should.be.equal(204); - }); - it('should be 404 if resource not exist', async function() { - const res = await request(host).del(`/book(not-exist-id)`); - res.status.should.be.equal(404); - }); - it('should be 404 if without id', async function() { - const res = await request(host).del(`/book`); - res.status.should.be.equal(404); - }); - it('should 404 if try to delete a resource twice', async function() { - const id = data[0].id; - await request(host).del(`/book(${id})`); - const res = await request(host).del(`/book(${id})`); - res.status.should.be.equal(404); - }); -}); diff --git a/test/rest.get.js b/test/rest.get.js deleted file mode 100644 index 81f6de9..0000000 --- a/test/rest.get.js +++ /dev/null @@ -1,40 +0,0 @@ -import 'should'; -import request from 'supertest'; -import { odata, host, port, bookSchema } from './support/setup'; -import books from './support/books.json'; -import FakeDb from './support/fake-db'; - -describe('rest.get', () => { - let data, httpServer; - - before(async function() { - const db = new FakeDb(); - const server = odata(db); - server.resource('book', bookSchema) - httpServer = server.listen(port); - data = db.addData('book', books); - }); - - after(() => { - httpServer.close(); - }); - - it('should return all of the resources', async function() { - const res = await request(host).get(`/book`); - res.body.should.be.have.property('value'); - res.body.value.length.should.be.equal(data.length); - }); - it('should return special resource', async function() { - const res = await request(host).get(`/book(${data[0].id})`); - res.body.should.be.have.property('title'); - res.body.title.should.be.equal(data[0].title); - }); - it('should be 404 if resouce name not declare', async function() { - const res = await request(host).get(`/not-exist-resource`); - res.status.should.be.equal(404); - }); - it('should be 404 if resource not exist', async function() { - const res = await request(host).get(`/book(not-exist-id)`); - res.status.should.be.equal(404); - }); -}); diff --git a/test/rest.put.js b/test/rest.put.js deleted file mode 100644 index 29bf1b4..0000000 --- a/test/rest.put.js +++ /dev/null @@ -1,53 +0,0 @@ -import * as uuid from 'uuid'; -import 'should'; -import request from 'supertest'; -import { odata, host, port, bookSchema } from './support/setup'; -import books from './support/books.json'; -import FakeDb from './support/fake-db'; - -describe('rest.put', () => { - let data, httpServer; - - before(async function() { - const db = new FakeDb(); - const server = odata(db); - server.resource('book', bookSchema) - httpServer = server.listen(port); - data = db.addData('book', books); - }); - - after(() => { - httpServer.close(); - }); - - it('should modify resource', async function() { - const book = data[0]; - book.title = 'modify book'; - const res = await request(host) - .put(`/book(${book.id})`) - .send(book); - res.body.should.be.have.property('title'); - res.body.title.should.be.equal(book.title); - }); - it('should create resource if send with a id which not exist', async function() { - const book = { - id: uuid.v4(), - title: 'new book', - }; - const res = await request(host) - .put(`/book(${book.id})`) - .send({ title: book.title }); - res.body.should.be.have.property('title'); - res.body.title.should.be.equal(book.title); - res.body.should.be.have.property('id'); - res.body.id.should.be.equal(book.id); - }); - it('should be 404 if without id', async function() { - const res = await request(host).put(`/book`).send(data[0]); - res.status.should.be.equal(404); - }); - it("should 400 if with a wrong id", async function() { - const res = await request(host).put(`/book(wrong-id)`).send(data[0]); - res.status.should.be.equal(400); - }); -}); diff --git a/test/service.document/entity.js b/test/service.document/entity.js new file mode 100644 index 0000000..e2ab579 --- /dev/null +++ b/test/service.document/entity.js @@ -0,0 +1,50 @@ +import 'should'; +import request from 'supertest'; +import { host, port, odata, assertSuccess } from '../support/setup'; +import { BookMetadata } from '../support/books.model'; +import checkContentType from '../support/checkContentType'; + +describe('service.document.entity', () => { + let httpServer, server, db; + + const jsonDocument = { + '@context': 'http://localhost:3000/$metadata', + value: [{ + kind: 'EntitySet', + name: 'book', + url: 'book' + }] + }; + beforeEach(async function() { + server = odata(); + server.entity('book', null, BookMetadata); + + }); + + afterEach(() => { + httpServer.close(); + }); + + it('should return json if no format given', async function() { + httpServer = server.listen(port); + const res = await request(host).get('/'); + assertSuccess(res); + checkContentType(res, 'application/json'); + res.body.should.deepEqual(jsonDocument); + }); + + it('should return json if asterix pattern match', async function() { + httpServer = server.listen(port); + const res = await request(host).get('/').set('accept', '*/*'); + assertSuccess(res); + checkContentType(res, 'application/json'); + res.body.should.deepEqual(jsonDocument); + }); + + it('should return 406 if other than json format requested', async function() { + httpServer = server.listen(port); + const res = await request(host).get('/').set('accept', 'application/xml'); + res.status.should.be.equal(406); + }); + +}); \ No newline at end of file diff --git a/test/service.document/singleton.js b/test/service.document/singleton.js new file mode 100644 index 0000000..7956d51 --- /dev/null +++ b/test/service.document/singleton.js @@ -0,0 +1,38 @@ +import 'should'; +import request from 'supertest'; +import { host, port, odata, assertSuccess } from '../support/setup'; +import { BookMetadata } from '../support/books.model'; +import checkContentType from '../support/checkContentType'; + +describe('service.document.singleton', () => { + let httpServer, server; + + const jsonDocument = { + '@context': 'http://localhost:3000/$metadata', + value: [{ + kind: 'Singleton', + name: 'book', + url: 'book' + }] + }; + beforeEach(async function() { + server = odata(); + server.singleton('book', null, BookMetadata); + + }); + + afterEach(() => { + httpServer.close(); + }); + + it('should return json if no format given', async function() { + httpServer = server.listen(port); + const res = await request(host).get('/'); + assertSuccess(res); + checkContentType(res, 'application/json'); + res.body.should.deepEqual(jsonDocument); + }); + +}); + + diff --git a/test/singleton.js b/test/singleton.js new file mode 100644 index 0000000..d3d1fa6 --- /dev/null +++ b/test/singleton.js @@ -0,0 +1,66 @@ +import 'should'; +import request from 'supertest'; +import { odata, host, port } from './support/setup'; +import { BookMetadata } from './support/books.model'; + +describe('singleton', () => { + let httpServer, server; + + beforeEach(async function () { + server = odata(); + }); + + afterEach(() => { + if (httpServer) { + httpServer.close(); + } + }); + + it('should work with get', async function () { + const result = { + "id": '1', + "price": 44.95, + "title": "XML Developer's Guide" + }; + server.singleton('book', { + get: (req, res, next) => { + res.$odata.result = result; + next(); + } + }, BookMetadata); + httpServer = server.listen(port); + + const res = await request(host).get(`/book`); + + if (!res.ok) { + res.res.statusMessage.should.be.equal(''); + } + + res.body.should.deepEqual(result); + }); + + it('should work if entityset and singleton defined', async function () { + const result = { + "id": '1', + "price": 44.95, + "title": "XML Developer's Guide" + }; + const book = server.entity('book', null, BookMetadata); + server.singletonFrom('current-book', { + get: (req, res, next) => { + res.$odata.result = result; + next(); + } + }, book); + httpServer = server.listen(port); + + const res = await request(host).get(`/current-book`); + + if (!res.ok) { + res.res.statusMessage.should.be.equal(''); + } + + res.body.should.deepEqual(result); + }); + +}); diff --git a/test/support/books.json b/test/support/books.json index b8c35b5..7635cbc 100644 --- a/test/support/books.json +++ b/test/support/books.json @@ -1,5 +1,6 @@ [ { + "id": "1", "author": "Gambardella, Matthew", "description": "An in-depth look at creating applications \n with XML.", "genre": "Computer", @@ -8,6 +9,7 @@ "title": "XML Developer's Guide" }, { + "id": "2", "author": "Ralls, Kim", "description": "A former architect battles corporate zombies, \n an evil sorceress, and her own childhood to become queen \n of the world.", "genre": "Fantasy", @@ -16,6 +18,7 @@ "title": "Midnight Rain" }, { + "id": "3", "author": "Corets, Eva", "description": "After the collapse of a nanotechnology \n society in England, the young survivors lay the \n foundation for a new society.", "genre": "Fantasy", @@ -24,6 +27,7 @@ "title": "Maeve Ascendant" }, { + "id": "4", "author": "Corets, Eva", "description": "In post-apocalypse England, the mysterious \n agent known only as Oberon helps to create a new life \n for the inhabitants of London. Sequel to Maeve \n Ascendant.", "genre": "Fantasy", @@ -32,6 +36,7 @@ "title": "Oberon's Legacy" }, { + "id": "5", "author": "Corets, Eva", "description": "The two daughters of Maeve, half-sisters, \n battle one another for control of England. Sequel to \n Oberon's Legacy.", "genre": "Fantasy", @@ -40,6 +45,7 @@ "title": "The Sundered Grail" }, { + "id": "6", "author": "Randall, Cynthia", "description": "When Carla meets Paul at an ornithology \n conference, tempers fly as feathers get ruffled.", "genre": "Romance", @@ -48,6 +54,7 @@ "title": "Lover Birds" }, { + "id": "7", "author": "Thurman, Paula", "description": "A deep sea diver finds true love twenty \n thousand leagues beneath the sea.", "genre": "Romance", @@ -56,6 +63,7 @@ "title": "Splish Splash" }, { + "id": "8", "author": "Knorr, Stefan", "description": "An anthology of horror stories about roaches,\n centipedes, scorpions and other insects.", "genre": "Horror", @@ -64,6 +72,7 @@ "title": "Creepy Crawlies" }, { + "id": "9", "author": "Kress, Peter", "description": "After an inadvertant trip through a Heisenberg\n Uncertainty Device, James Salway discovers the problems \n of being quantum.", "genre": "Science Fiction", @@ -72,6 +81,7 @@ "title": "Paradox Lost" }, { + "id": "A", "author": "O'Brien, Tim", "description": "Microsoft's .NET initiative is explored in \n detail in this deep programmer's reference.", "genre": "Computer", @@ -80,6 +90,7 @@ "title": "Microsoft .NET: The Programming Bible" }, { + "id": "B", "author": "O'Brien, Tim", "description": "The Microsoft MSXML3 parser is covered in \n detail, with attention to XML DOM interfaces, XSLT processing, \n SAX and more.", "genre": "Computer", @@ -88,6 +99,7 @@ "title": "MSXML3: A Comprehensive Guide" }, { + "id": "C", "author": "Galos, Mike", "description": "Microsoft Visual Studio 7 is explored in depth,\n looking at how Visual Basic, Visual C++, C#, and ASP+ are \n integrated into a comprehensive development \n environment.", "genre": "Computer", @@ -96,6 +108,7 @@ "title": "Visual Studio 7: A Comprehensive Guide" }, { + "id": "D", "author": "史蒂夫·迈克康奈尔", "description": "第2版的《代码大全》是著名IT畅销书作者史蒂夫·迈克康奈尔11年前的经典著作的全新演绎:第2版不是第一版的简单修订增补,而是完全进行了重写;增加了很多与时俱进的内容。这也是一本完整的软件构建手册,涵盖了软件构建过程中的所有细节。它从软件质量和编程思想等方面论述了软件构建的各个问题,并详细论述了紧跟潮流的新技术、高屋建瓴的观点、通用的概念,还含有丰富而典型的程序示例。这本书中所论述的技术不仅填补了初级与高级编程技术之间的空白,而且也为程序员们提供了一个有关编程技巧的信息来源。这本书对经验丰富的程序员、技术带头人、自学的程序员及几乎不懂太多编程技巧的学生们都是大有裨益的。可以说,无论是什么背景的读者,阅读这本书都有助于在更短的时间内、更容易地写出更好的程序。", "genre": "计算机", diff --git a/test/support/books.model.js b/test/support/books.model.js new file mode 100644 index 0000000..bb9b551 --- /dev/null +++ b/test/support/books.model.js @@ -0,0 +1,54 @@ +import mongoose from 'mongoose'; + +const Schema = mongoose.Schema; + +export const BookSchema = new Schema({ + author: String, + description: String, + genre: String, + price: Number, + publish_date: Date, + title: String +}, + { + timestamps: true, + toObject: { + virtuals: true, + }, + toJSON: { + virtuals: true, + }, + }); + +export const BookModel = mongoose.model('Book', BookSchema); + +export const BookMetadata = { + $Key: ['id'], + id: { + $Type: 'Edm.String', + $MaxLength: 24 + }, + author: { + $Type: 'Edm.String' + }, + genre: { + $Type: 'Edm.String' + }, + price: { + $Type: 'Edm.Double' + }, + publish_date: { + $Type: 'Edm.DateTimeOffset' + }, + title: { + $Type: 'Edm.String' + }, + createdAt: { + $Type: 'Edm.DateTimeOffset', + $Nullable: true + }, + updatedAt: { + $Type: 'Edm.DateTimeOffset', + $Nullable: true + } +}; \ No newline at end of file diff --git a/test/support/checkContentType.js b/test/support/checkContentType.js new file mode 100644 index 0000000..52d7230 --- /dev/null +++ b/test/support/checkContentType.js @@ -0,0 +1,6 @@ +import 'should'; + +export default function checkContentType(res, value) { + res.header.should.have.property('content-type'); + res.header['content-type'].should.containEql(value); +} \ No newline at end of file diff --git a/test/support/db.js b/test/support/db.js new file mode 100644 index 0000000..45229e0 --- /dev/null +++ b/test/support/db.js @@ -0,0 +1,27 @@ + +import mongoose from 'mongoose'; +import { conn } from '../support/setup'; +import error from '../../src/mongo/middlewares/error'; + +export function init(server) { + server.error = error; + server.addBefore((req, res, next) => { + req.$odata = { + ...req.$odata, + mongo: mongoose.default.connection + }; + next(); + }); +} + +export async function connect(server) { + try { + await mongoose.connect(process.env.DATABASE || conn); + init(server); + + } catch(err) { + console.error(err.message); + console.error('Failed to connect to database on startup.'); + process.exit(); + } +} \ No newline at end of file diff --git a/test/support/fake-db-model.js b/test/support/fake-db-model.js deleted file mode 100644 index 95315a2..0000000 --- a/test/support/fake-db-model.js +++ /dev/null @@ -1,219 +0,0 @@ -export default class Model { - constructor(name, model) { - this._name = name; - this._data = []; - this._count = 1; - this.model = { - schema: { - ...model, - tree: { - id: { select: true }, - ...model - }, - paths: Model.toPath(model) - } - }; - } - - static toPath(model, prefix) { - let result = {}; - - Object.keys(model).forEach((item) => { - const propName = prefix ? `${prefix}.${item}` : item; - - if (Array.isArray(model[item])) { - result[propName] = { - path: propName, - instance: 'Array' - }; - if (model[item][0].name) { - // Array of primitive Types - result[propName].options = { - type: [{ - name: model[item][0].name - }] - }; - } else { - // Array of objects - result[propName].schema = { - paths: Model.toPath(model[item][0]) - }; - } - } else if ( typeof model[item] === 'object' ) { - const subSchema = Model.toPath(model[item], propName); - - result = { - ...result, - ...subSchema - }; - } else { - result[propName] = { - path: propName, - instance: model[item].name - }; - } - }); - - return result; - } - - addData(data) { - this._data = data.map(item => ({ - ...item, - id: (this._count++).toString() - })); - - return this._data; - } - - create(data) { - const newItem = { - ...data, - id: data.id || (this._count++).toString(), - save: callback => { - const result = this._data.find(item => item.id === newItem.id); - - if (result._id) { - result.id = result._id; - } - callback(); - } - }; - - this._data.push(newItem); - - return newItem; - } - - exec(callback) { - callback(null, this._data); - } - - find() { - return this; - } - - findById(id, callback) { - let idInternal = 0; - - switch (this.model.schema.id) { - case Number: - idInternal = +id; - break; - - default: - idInternal = id; - break; - } - - let result = this._data.find(item => item.id === idInternal); - - if (result) { - result.save = (callback) => { - callback(); - }; - } - callback(null, result); - } - - findByIdAndUpdate(id, data, callback) { - const result = this._data.find(item => item.id === id); - const index = this._data.indexOf(result); - - this._data[index] = { - ...result, - ...data - }; - callback(); - - } - - findOne(filter, callback) { - const result = this._data.find(item => item.id === filter._id); - callback(null, result); - } - - remove(filter, callback) { - const toDelete = this._data.find(item => item.id === filter._id); - const deleteItem = item => { - const index = this._data.indexOf(item); - this._data.splice(index, 1); - }; - - if (toDelete) { - if (Array.isArray(toDelete)) { - toDelete.forEach(deleteItem); - callback(null, JSON.stringify({ n: toDelete.length })); - } else { - deleteItem(toDelete); - callback(null, JSON.stringify({ n: 1 })); - } - } else { - callback(null, JSON.stringify({ n: 0 })); - } - } - - limit() { - return this; - } - - select() { - return this; - } - - skip() { - return this; - } - - sort() { - return this; - } - - where() { - return this; - } - - $where(value) { - return this; - } - - gt() { - return this; - } - - gte() { - return this; - } - - lt() { - return this; - } - - lte() { - return this; - } - - equals() { - return this; - } - - ne() { - return this; - } - - exists() { - return this; - } - - or() { - return this; - } - - and() { - return this; - } - - count(callback) { - callback(null, this._data.length); - } -} \ No newline at end of file diff --git a/test/support/fake-db.js b/test/support/fake-db.js deleted file mode 100644 index 2f088d0..0000000 --- a/test/support/fake-db.js +++ /dev/null @@ -1,24 +0,0 @@ -import Model from './fake-db-model'; - -export default class { - constructor() { - this._models = {}; - } - - addData(name, data) { - return this._models[name].addData(data); - } - - createConnection() { - return this; - } - - register(name, model) { - this._models[name] = new Model(name, model); - return this._models[name]; - } - - on(name, event) { - - } -} \ No newline at end of file diff --git a/test/support/setup.js b/test/support/setup.js index 92e5ec8..ed55a12 100644 --- a/test/support/setup.js +++ b/test/support/setup.js @@ -1,52 +1,13 @@ -import mongoose from 'mongoose'; -import id from '../../lib/model/idPlugin'; - export odata from '../../src'; export const host = 'http://localhost:3000'; export const port = '3000'; export const conn = 'mongodb://localhost/odata-test'; -export const bookSchema = { - author: String, - description: String, - genre: String, - price: Number, - publish_date: Date, - title: String -}; - -export const books = require('./books.json'); - -export function initData() { - return new Promise((resolve, reject) => { - const conf = { - _id: false, - versionKey: false, - collection: 'book', - }; +const { BookModel } = require('./books.model'); - const db = mongoose.createConnection(conn); - const schema = new mongoose.Schema(bookSchema, conf); - schema.plugin(id); - const model = db.model('book', schema); +export const model = BookModel; - function clear() { - return new Promise((resolve) => { - model.remove({}, resolve); - }); - } - - function insert(item) { - return new Promise((resolve) => { - const entity = new model(item); - entity.save((err, result) => resolve(result)); - }); - } - - const promises = books.map(insert); - clear().then(() => Promise.all(promises).then(resolve)); - }); -} +export const books = require('./books.json'); export function assertSuccess(res) { if (res.error) {