From 6eb757ebecec9c21f0226af527f735cd7941010f Mon Sep 17 00:00:00 2001 From: filipenevola Date: Wed, 8 Nov 2023 08:44:44 -0500 Subject: [PATCH 01/10] Meteor 3 - wip - missing to really migrate schema usage of collection (from collection2) --- collections.js | 8 +- package.js | 18 +- schema.js | 770 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 787 insertions(+), 9 deletions(-) create mode 100644 schema.js diff --git a/collections.js b/collections.js index eb9835d..5882152 100644 --- a/collections.js +++ b/collections.js @@ -5,6 +5,9 @@ import { getSettings } from 'meteor/quave:settings'; import { CustomTypeCollection } from './CustomTypeCollection'; +// to load attachSchema +import './schema'; + const PACKAGE_NAME = 'quave:collections'; const settings = getSettings({ packageName: PACKAGE_NAME }); @@ -90,11 +93,6 @@ export const createCollection = ({ Object.assign(dbCollection, collection); Object.assign(dbCollection, compose(...composers)(dbCollection)); if (schema) { - if (!dbCollection.attachSchema) { - throw new Error( - "attachSchema function is not present in your collection so you can't use 'schema' option, use https://github.com/Meteor-Community-Packages/meteor-collection2 if you want to have it." - ); - } dbCollection.attachSchema(schema); } dbCollection.definition = definition; diff --git a/package.js b/package.js index 932de00..bc3015d 100644 --- a/package.js +++ b/package.js @@ -5,15 +5,25 @@ Package.describe({ git: 'https://github.com/quavedev/collections', }); -Package.onUse(function(api) { - api.versionsFrom('1.10.2'); +Npm.depends({ + 'lodash.isempty': '4.4.0', + 'lodash.isequal': '4.5.0', + 'lodash.isobject': '3.0.2', +}); - api.use('ecmascript'); +Package.onUse(function(api) { + api.versionsFrom('2.13.3'); api.use('mongo'); + api.imply('mongo'); + api.use('minimongo'); api.use('ejson'); - + api.use('raix:eventemitter@1.0.0'); + api.use('ecmascript'); + api.use('tmeasday:check-npm-versions@1.0.2'); api.use('quave:settings@1.0.0'); api.mainModule('collections.js'); + + api.export('Collection2'); }); diff --git a/schema.js b/schema.js new file mode 100644 index 0000000..52fd378 --- /dev/null +++ b/schema.js @@ -0,0 +1,770 @@ +/* this code was copied from https://github.com/Meteor-Community-Packages/meteor-collection2/tree/master/package/collection2 + * to make quave:collections compatible with Meteor 3 + */ +import { EventEmitter } from 'meteor/raix:eventemitter'; +import { Meteor } from 'meteor/meteor'; +import { Mongo } from 'meteor/mongo'; +import { checkNpmVersions } from 'meteor/tmeasday:check-npm-versions'; +import { EJSON } from 'meteor/ejson'; +import isEmpty from 'lodash.isempty'; +import isEqual from 'lodash.isequal'; +import isObject from 'lodash.isobject'; + +function flattenSelector(selector) { + // If selector uses $and format, convert to plain object selector + if (Array.isArray(selector.$and)) { + selector.$and.forEach(sel => { + Object.assign(selector, flattenSelector(sel)); + }); + + delete selector.$and + } + + const obj = {} + + Object.entries(selector).forEach(([key, value]) => { + // Ignoring logical selectors (https://docs.mongodb.com/manual/reference/operator/query/#logical) + if (!key.startsWith("$")) { + if (typeof value === 'object' && value !== null) { + if (value.$eq !== undefined) { + obj[key] = value.$eq + } else if (Array.isArray(value.$in) && value.$in.length === 1) { + obj[key] = value.$in[0] + } else if (Object.keys(value).every(v => !(typeof v === "string" && v.startsWith("$")))) { + obj[key] = value + } + } else { + obj[key] = value + } + } + }) + + return obj +} +checkNpmVersions({ 'simpl-schema': '>=0.0.0' }, 'aldeed:collection2'); + +const SimpleSchema = require('simpl-schema').default; + +// Exported only for listening to events +const Collection2 = new EventEmitter(); + +Collection2.cleanOptions = { + filter: true, + autoConvert: true, + removeEmptyStrings: true, + trimStrings: true, + removeNullsFromArrays: false, +}; + +/** + * Mongo.Collection.prototype.attachSchema + * @param {SimpleSchema|Object} ss - SimpleSchema instance or a schema definition object + * from which to create a new SimpleSchema instance + * @param {Object} [options] + * @param {Boolean} [options.transform=false] Set to `true` if your document must be passed + * through the collection's transform to properly validate. + * @param {Boolean} [options.replace=false] Set to `true` to replace any existing schema instead of combining + * @return {undefined} + * + * Use this method to attach a schema to a collection created by another package, + * such as Meteor.users. It is most likely unsafe to call this method more than + * once for a single collection, or to call this for a collection that had a + * schema object passed to its constructor. + */ +Mongo.Collection.prototype.attachSchema = function c2AttachSchema(ss, options) { + options = options || {}; + + // Allow passing just the schema object + if (!SimpleSchema.isSimpleSchema(ss)) { + ss = new SimpleSchema(ss); + } + + function attachTo(obj) { + // we need an array to hold multiple schemas + // position 0 is reserved for the "base" schema + obj._c2 = obj._c2 || {}; + obj._c2._simpleSchemas = obj._c2._simpleSchemas || [ null ]; + + if (typeof options.selector === "object") { + // Selector Schemas + + // Extend selector schema with base schema + const baseSchema = obj._c2._simpleSchemas[0]; + if (baseSchema) { + ss = extendSchema(baseSchema.schema, ss); + } + + // Index of existing schema with identical selector + let schemaIndex; + + // Loop through existing schemas with selectors, + for (schemaIndex = obj._c2._simpleSchemas.length - 1; 0 < schemaIndex; schemaIndex--) { + const schema = obj._c2._simpleSchemas[schemaIndex]; + if (schema && isEqual(schema.selector, options.selector)) break; + } + + if (schemaIndex <= 0) { + // We didn't find the schema in our array - push it into the array + obj._c2._simpleSchemas.push({ + schema: ss, + selector: options.selector, + }); + } else { + // We found a schema with an identical selector in our array, + if (options.replace === true) { + // Replace existing selector schema with new selector schema + obj._c2._simpleSchemas[schemaIndex].schema = ss; + } else { + // Extend existing selector schema with new selector schema. + obj._c2._simpleSchemas[schemaIndex].schema = extendSchema(obj._c2._simpleSchemas[schemaIndex].schema, ss); + } + } + } else { + // Base Schema + if (options.replace === true) { + // Replace base schema and delete all other schemas + obj._c2._simpleSchemas = [{ + schema: ss, + selector: options.selector, + }]; + } else { + // Set base schema if not yet set + if (!obj._c2._simpleSchemas[0]) { + return obj._c2._simpleSchemas[0] = { schema: ss, selector: undefined }; + } + // Extend base schema and therefore extend all schemas + obj._c2._simpleSchemas.forEach((schema, index) => { + if (obj._c2._simpleSchemas[index]) { + obj._c2._simpleSchemas[index].schema = extendSchema(obj._c2._simpleSchemas[index].schema, ss); + } + }); + } + } + } + + attachTo(this); + // Attach the schema to the underlying LocalCollection, too + if (this._collection instanceof LocalCollection) { + this._collection._c2 = this._collection._c2 || {}; + attachTo(this._collection); + } + + defineDeny(this, options); + keepInsecure(this); + + Collection2.emit('schema.attached', this, ss, options); +}; + +[Mongo.Collection, LocalCollection].forEach((obj) => { + /** + * simpleSchema + * @description function detect the correct schema by given params. If it + * detect multi-schema presence in the collection, then it made an attempt to find a + * `selector` in args + * @param {Object} doc - It could be on update/upsert or document + * itself on insert/remove + * @param {Object} [options] - It could be on update/upsert etc + * @param {Object} [query] - it could be on update/upsert + * @return {Object} Schema + */ + obj.prototype.simpleSchema = function (doc, options, query) { + if (!this._c2) return null; + if (this._c2._simpleSchema) return this._c2._simpleSchema; + + const schemas = this._c2._simpleSchemas; + if (schemas && schemas.length > 0) { + + let schema, selector, target; + // Position 0 reserved for base schema + for (var i = 1; i < schemas.length; i++) { + schema = schemas[i]; + selector = Object.keys(schema.selector)[0]; + + // We will set this to undefined because in theory you might want to select + // on a null value. + target = undefined; + // here we are looking for selector in different places + // $set should have more priority here + if (doc.$set && typeof doc.$set[selector] !== 'undefined') { + target = doc.$set[selector]; + } else if (typeof doc[selector] !== 'undefined') { + target = doc[selector]; + } else if (options && options.selector) { + target = options.selector[selector]; + } else if (query && query[selector]) { // on upsert/update operations + target = query[selector]; + } + + // we need to compare given selector with doc property or option to + // find right schema + if (target !== undefined && target === schema.selector[selector]) { + return schema.schema; + } + } + if (schemas[0]) { + return schemas[0].schema; + } else { + throw new Error("No default schema"); + } + } + + return null; + }; +}); + +// Wrap DB write operation methods +['insert', 'update'].forEach((methodName) => { + const _super = Mongo.Collection.prototype[methodName]; + Mongo.Collection.prototype[methodName] = function(...args) { + let options = (methodName === "insert") ? args[1] : args[2]; + + // Support missing options arg + if (!options || typeof options === "function") { + options = {}; + } + + if (this._c2 && options.bypassCollection2 !== true) { + let userId = null; + try { // https://github.com/aldeed/meteor-collection2/issues/175 + userId = Meteor.userId(); + } catch (err) {} + + args = doValidate( + this, + methodName, + args, + Meteor.isServer || this._connection === null, // getAutoValues + userId, + Meteor.isServer // isFromTrustedCode + ); + if (!args) { + // doValidate already called the callback or threw the error so we're done. + // But insert should always return an ID to match core behavior. + return methodName === "insert" ? this._makeNewID() : undefined; + } + } else { + // We still need to adjust args because insert does not take options + if (methodName === "insert" && typeof args[1] !== 'function') args.splice(1, 1); + } + + return _super.apply(this, args); + }; +}); + +/* + * Private + */ + +function doValidate(collection, type, args, getAutoValues, userId, isFromTrustedCode) { + let doc, callback, error, options, isUpsert, selector, last, hasCallback; + + if (!args.length) { + throw new Error(type + " requires an argument"); + } + + // Gather arguments and cache the selector + if (type === "insert") { + doc = args[0]; + options = args[1]; + callback = args[2]; + + // The real insert doesn't take options + if (typeof options === "function") { + args = [doc, options]; + } else if (typeof callback === "function") { + args = [doc, callback]; + } else { + args = [doc]; + } + } else if (type === "update") { + selector = args[0]; + doc = args[1]; + options = args[2]; + callback = args[3]; + } else { + throw new Error("invalid type argument"); + } + + const validatedObjectWasInitiallyEmpty = isEmpty(doc); + + // Support missing options arg + if (!callback && typeof options === "function") { + callback = options; + options = {}; + } + options = options || {}; + + last = args.length - 1; + + hasCallback = (typeof args[last] === 'function'); + + // If update was called with upsert:true, flag as an upsert + isUpsert = (type === "update" && options.upsert === true); + + // we need to pass `doc` and `options` to `simpleSchema` method, that's why + // schema declaration moved here + let schema = collection.simpleSchema(doc, options, selector); + const isLocalCollection = (collection._connection === null); + + // On the server and for local collections, we allow passing `getAutoValues: false` to disable autoValue functions + if ((Meteor.isServer || isLocalCollection) && options.getAutoValues === false) { + getAutoValues = false; + } + + // Process pick/omit options if they are present + const picks = Array.isArray(options.pick) ? options.pick : null; + const omits = Array.isArray(options.omit) ? options.omit : null; + + if (picks && omits) { + // Pick and omit cannot both be present in the options + throw new Error('pick and omit options are mutually exclusive'); + } else if (picks) { + schema = schema.pick(...picks); + } else if (omits) { + schema = schema.omit(...omits); + } + + // Determine validation context + let validationContext = options.validationContext; + if (validationContext) { + if (typeof validationContext === 'string') { + validationContext = schema.namedContext(validationContext); + } + } else { + validationContext = schema.namedContext(); + } + + // Add a default callback function if we're on the client and no callback was given + if (Meteor.isClient && !callback) { + // Client can't block, so it can't report errors by exception, + // only by callback. If they forget the callback, give them a + // default one that logs the error, so they aren't totally + // baffled if their writes don't work because their database is + // down. + callback = function(err) { + if (err) { + Meteor._debug(type + " failed: " + (err.reason || err.stack)); + } + }; + } + + // If client validation is fine or is skipped but then something + // is found to be invalid on the server, we get that error back + // as a special Meteor.Error that we need to parse. + if (Meteor.isClient && hasCallback) { + callback = args[last] = wrapCallbackForParsingServerErrors(validationContext, callback); + } + + const schemaAllowsId = schema.allowsKey("_id"); + if (type === "insert" && !doc._id && schemaAllowsId) { + doc._id = collection._makeNewID(); + } + + // Get the docId for passing in the autoValue/custom context + let docId; + if (type === 'insert') { + docId = doc._id; // might be undefined + } else if (type === "update" && selector) { + docId = typeof selector === 'string' || selector instanceof Mongo.ObjectID ? selector : selector._id; + } + + // If _id has already been added, remove it temporarily if it's + // not explicitly defined in the schema. + let cachedId; + if (doc._id && !schemaAllowsId) { + cachedId = doc._id; + delete doc._id; + } + + const autoValueContext = { + isInsert: (type === "insert"), + isUpdate: (type === "update" && options.upsert !== true), + isUpsert, + userId, + isFromTrustedCode, + docId, + isLocalCollection + }; + + const extendAutoValueContext = { + ...((schema._cleanOptions || {}).extendAutoValueContext || {}), + ...autoValueContext, + ...options.extendAutoValueContext, + }; + + const cleanOptionsForThisOperation = {}; + ["autoConvert", "filter", "removeEmptyStrings", "removeNullsFromArrays", "trimStrings"].forEach(prop => { + if (typeof options[prop] === "boolean") { + cleanOptionsForThisOperation[prop] = options[prop]; + } + }); + + // Preliminary cleaning on both client and server. On the server and for local + // collections, automatic values will also be set at this point. + schema.clean(doc, { + mutate: true, // Clean the doc/modifier in place + isModifier: (type !== "insert"), + // Start with some Collection2 defaults, which will usually be overwritten + ...Collection2.cleanOptions, + // The extend with the schema-level defaults (from SimpleSchema constructor options) + ...(schema._cleanOptions || {}), + // Finally, options for this specific operation should take precedence + ...cleanOptionsForThisOperation, + extendAutoValueContext, // This was extended separately above + getAutoValues, // Force this override + }); + + // We clone before validating because in some cases we need to adjust the + // object a bit before validating it. If we adjusted `doc` itself, our + // changes would persist into the database. + let docToValidate = {}; + for (var prop in doc) { + // We omit prototype properties when cloning because they will not be valid + // and mongo omits them when saving to the database anyway. + if (Object.prototype.hasOwnProperty.call(doc, prop)) { + docToValidate[prop] = doc[prop]; + } + } + + // On the server, upserts are possible; SimpleSchema handles upserts pretty + // well by default, but it will not know about the fields in the selector, + // which are also stored in the database if an insert is performed. So we + // will allow these fields to be considered for validation by adding them + // to the $set in the modifier, while stripping out query selectors as these + // don't make it into the upserted document and break validation. + // This is no doubt prone to errors, but there probably isn't any better way + // right now. + if (Meteor.isServer && isUpsert && isObject(selector)) { + const set = docToValidate.$set || {}; + docToValidate.$set = flattenSelector(selector); + + if (!schemaAllowsId) delete docToValidate.$set._id; + Object.assign(docToValidate.$set, set); + } + // Set automatic values for validation on the client. + // On the server, we already updated doc with auto values, but on the client, + // we will add them to docToValidate for validation purposes only. + // This is because we want all actual values generated on the server. + if (Meteor.isClient && !isLocalCollection) { + schema.clean(docToValidate, { + autoConvert: false, + extendAutoValueContext, + filter: false, + getAutoValues: true, + isModifier: (type !== "insert"), + mutate: true, // Clean the doc/modifier in place + removeEmptyStrings: false, + removeNullsFromArrays: false, + trimStrings: false, + }); + } + + // XXX Maybe move this into SimpleSchema + if (!validatedObjectWasInitiallyEmpty && isEmpty(docToValidate)) { + throw new Error('After filtering out keys not in the schema, your ' + + (type === 'update' ? 'modifier' : 'object') + + ' is now empty'); + } + + // Validate doc + let isValid; + if (options.validate === false) { + isValid = true; + } else { + isValid = validationContext.validate(docToValidate, { + modifier: (type === "update" || type === "upsert"), + upsert: isUpsert, + extendedCustomContext: { + isInsert: (type === "insert"), + isUpdate: (type === "update" && options.upsert !== true), + isUpsert, + userId, + isFromTrustedCode, + docId, + isLocalCollection, + ...(options.extendedCustomContext || {}), + }, + }); + } + + if (isValid) { + // Add the ID back + if (cachedId) { + doc._id = cachedId; + } + + // Update the args to reflect the cleaned doc + // XXX not sure this is necessary since we mutate + if (type === "insert") { + args[0] = doc; + } else { + args[1] = doc; + } + + // If callback, set invalidKey when we get a mongo unique error + if (Meteor.isServer && hasCallback) { + args[last] = wrapCallbackForParsingMongoValidationErrors(validationContext, args[last]); + } + + return args; + } else { + error = getErrorObject(validationContext, Meteor.settings?.packages?.collection2?.disableCollectionNamesInValidation ? '' : `in ${collection._name} ${type}`); + if (callback) { + // insert/update/upsert pass `false` when there's an error, so we do that + callback(error, false); + } else { + throw error; + } + } +} + +function getErrorObject(context, appendToMessage = '') { + let message; + const invalidKeys = (typeof context.validationErrors === 'function') ? context.validationErrors() : context.invalidKeys(); + if (invalidKeys.length) { + const firstErrorKey = invalidKeys[0].name; + const firstErrorMessage = context.keyErrorMessage(firstErrorKey); + + // If the error is in a nested key, add the full key to the error message + // to be more helpful. + if (firstErrorKey.indexOf('.') === -1) { + message = firstErrorMessage; + } else { + message = `${firstErrorMessage} (${firstErrorKey})`; + } + } else { + message = "Failed validation"; + } + message = `${message} ${appendToMessage}`.trim(); + const error = new Error(message); + error.invalidKeys = invalidKeys; + error.validationContext = context; + // If on the server, we add a sanitized error, too, in case we're + // called from a method. + if (Meteor.isServer) { + error.sanitizedError = new Meteor.Error(400, message, EJSON.stringify(error.invalidKeys)); + } + return error; +} + +function addUniqueError(context, errorMessage) { + const name = errorMessage.split('c2_')[1].split(' ')[0]; + const val = errorMessage.split('dup key:')[1].split('"')[1]; + + const addValidationErrorsPropName = (typeof context.addValidationErrors === 'function') ? 'addValidationErrors' : 'addInvalidKeys'; + context[addValidationErrorsPropName]([{ + name: name, + type: 'notUnique', + value: val + }]); +} + +function wrapCallbackForParsingMongoValidationErrors(validationContext, cb) { + return function wrappedCallbackForParsingMongoValidationErrors(...args) { + const error = args[0]; + if (error && + ((error.name === "MongoError" && error.code === 11001) || error.message.indexOf('MongoError: E11000') !== -1) && + error.message.indexOf('c2_') !== -1) { + addUniqueError(validationContext, error.message); + args[0] = getErrorObject(validationContext); + } + return cb.apply(this, args); + }; +} + +function wrapCallbackForParsingServerErrors(validationContext, cb) { + const addValidationErrorsPropName = (typeof validationContext.addValidationErrors === 'function') ? 'addValidationErrors' : 'addInvalidKeys'; + return function wrappedCallbackForParsingServerErrors(...args) { + const error = args[0]; + // Handle our own validation errors + if (error instanceof Meteor.Error && + error.error === 400 && + error.reason === "INVALID" && + typeof error.details === "string") { + const invalidKeysFromServer = EJSON.parse(error.details); + validationContext[addValidationErrorsPropName](invalidKeysFromServer); + args[0] = getErrorObject(validationContext); + } + // Handle Mongo unique index errors, which are forwarded to the client as 409 errors + else if (error instanceof Meteor.Error && + error.error === 409 && + error.reason && + error.reason.indexOf('E11000') !== -1 && + error.reason.indexOf('c2_') !== -1) { + addUniqueError(validationContext, error.reason); + args[0] = getErrorObject(validationContext); + } + return cb.apply(this, args); + }; +} + +let alreadyInsecure = {}; +function keepInsecure(c) { + // If insecure package is in use, we need to add allow rules that return + // true. Otherwise, it would seemingly turn off insecure mode. + if (Package && Package.insecure && !alreadyInsecure[c._name]) { + c.allow({ + insert: function() { + return true; + }, + update: function() { + return true; + }, + remove: function () { + return true; + }, + fetch: [], + transform: null + }); + alreadyInsecure[c._name] = true; + } + // If insecure package is NOT in use, then adding the two deny functions + // does not have any effect on the main app's security paradigm. The + // user will still be required to add at least one allow function of her + // own for each operation for this collection. And the user may still add + // additional deny functions, but does not have to. +} + +let alreadyDefined = {}; +function defineDeny(c, options) { + if (!alreadyDefined[c._name]) { + + const isLocalCollection = (c._connection === null); + + // First define deny functions to extend doc with the results of clean + // and auto-values. This must be done with "transform: null" or we would be + // extending a clone of doc and therefore have no effect. + c.deny({ + insert: function(userId, doc) { + // Referenced doc is cleaned in place + c.simpleSchema(doc).clean(doc, { + mutate: true, + isModifier: false, + // We don't do these here because they are done on the client if desired + filter: false, + autoConvert: false, + removeEmptyStrings: false, + trimStrings: false, + extendAutoValueContext: { + isInsert: true, + isUpdate: false, + isUpsert: false, + userId: userId, + isFromTrustedCode: false, + docId: doc._id, + isLocalCollection: isLocalCollection + } + }); + + return false; + }, + update: function(userId, doc, fields, modifier) { + // Referenced modifier is cleaned in place + c.simpleSchema(modifier).clean(modifier, { + mutate: true, + isModifier: true, + // We don't do these here because they are done on the client if desired + filter: false, + autoConvert: false, + removeEmptyStrings: false, + trimStrings: false, + extendAutoValueContext: { + isInsert: false, + isUpdate: true, + isUpsert: false, + userId: userId, + isFromTrustedCode: false, + docId: doc && doc._id, + isLocalCollection: isLocalCollection + } + }); + + return false; + }, + fetch: ['_id'], + transform: null + }); + + // Second define deny functions to validate again on the server + // for client-initiated inserts and updates. These should be + // called after the clean/auto-value functions since we're adding + // them after. These must *not* have "transform: null" if options.transform is true because + // we need to pass the doc through any transforms to be sure + // that custom types are properly recognized for type validation. + c.deny({ + insert: function(userId, doc) { + // We pass the false options because we will have done them on client if desired + doValidate( + c, + "insert", + [ + doc, + { + trimStrings: false, + removeEmptyStrings: false, + filter: false, + autoConvert: false + }, + function(error) { + if (error) { + throw new Meteor.Error(400, 'INVALID', EJSON.stringify(error.invalidKeys)); + } + } + ], + false, // getAutoValues + userId, + false // isFromTrustedCode + ); + + return false; + }, + update: function(userId, doc, fields, modifier) { + // NOTE: This will never be an upsert because client-side upserts + // are not allowed once you define allow/deny functions. + // We pass the false options because we will have done them on client if desired + doValidate( + c, + "update", + [ + {_id: doc && doc._id}, + modifier, + { + trimStrings: false, + removeEmptyStrings: false, + filter: false, + autoConvert: false + }, + function(error) { + if (error) { + throw new Meteor.Error(400, 'INVALID', EJSON.stringify(error.invalidKeys)); + } + } + ], + false, // getAutoValues + userId, + false // isFromTrustedCode + ); + + return false; + }, + fetch: ['_id'], + ...(options.transform === true ? {} : {transform: null}), + }); + + // note that we've already done this collection so that we don't do it again + // if attachSchema is called again + alreadyDefined[c._name] = true; + } +} + +function extendSchema(s1, s2) { + if (s2.version >= 2) { + const ss = new SimpleSchema(s1); + ss.extend(s2); + return ss; + } else { + return new SimpleSchema([ s1, s2 ]); + } +} + +export default Collection2; \ No newline at end of file From dd7e3a70ff9baac2274b517320f0073b18ee08cf Mon Sep 17 00:00:00 2001 From: filipenevola Date: Sun, 12 Nov 2023 23:39:38 -0500 Subject: [PATCH 02/10] Adapts code from this PR to bring collection2 to collections - https://github.com/Meteor-Community-Packages/meteor-collection2/pull/443/files#diff-1bc97b15b1e837743f590899c1c0fd36eab5a1bf21df692490899220dca7b160 We still need to decide if we want to bring all the tests and support multiple versions of Meteor, probably only Meteor 3 support would be better --- schema.js | 1512 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 866 insertions(+), 646 deletions(-) diff --git a/schema.js b/schema.js index 52fd378..e1df2b7 100644 --- a/schema.js +++ b/schema.js @@ -10,38 +10,53 @@ import isEmpty from 'lodash.isempty'; import isEqual from 'lodash.isequal'; import isObject from 'lodash.isobject'; -function flattenSelector(selector) { - // If selector uses $and format, convert to plain object selector - if (Array.isArray(selector.$and)) { - selector.$and.forEach(sel => { - Object.assign(selector, flattenSelector(sel)); - }); +/* global LocalCollection, Package */ - delete selector.$and - } +const isInsertType = function (type) { + return ['insert', 'insertAsync'].includes(type); +}; +const isUpdateType = function (type) { + return ['update', 'updateAsync'].includes(type); +}; +const isUpsertType = function (type) { + return ['upsert', 'upsertAsync'].includes(type); +}; +function flattenSelector(selector) { + // If selector uses $and format, convert to plain object selector + if (Array.isArray(selector.$and)) { + selector.$and.forEach((sel) => { + Object.assign(selector, flattenSelector(sel)); + }); - const obj = {} - - Object.entries(selector).forEach(([key, value]) => { - // Ignoring logical selectors (https://docs.mongodb.com/manual/reference/operator/query/#logical) - if (!key.startsWith("$")) { - if (typeof value === 'object' && value !== null) { - if (value.$eq !== undefined) { - obj[key] = value.$eq - } else if (Array.isArray(value.$in) && value.$in.length === 1) { - obj[key] = value.$in[0] - } else if (Object.keys(value).every(v => !(typeof v === "string" && v.startsWith("$")))) { - obj[key] = value - } - } else { - obj[key] = value - } + delete selector.$and; + } + + const obj = {}; + + Object.entries(selector).forEach(([key, value]) => { + // Ignoring logical selectors (https://docs.mongodb.com/manual/reference/operator/query/#logical) + if (!key.startsWith('$')) { + if (typeof value === 'object' && value !== null) { + if (value.$eq !== undefined) { + obj[key] = value.$eq; + } else if (Array.isArray(value.$in) && value.$in.length === 1) { + obj[key] = value.$in[0]; + } else if ( + Object.keys(value).every( + (v) => !(typeof v === 'string' && v.startsWith('$')) + ) + ) { + obj[key] = value; } - }) + } else { + obj[key] = value; + } + } + }); - return obj + return obj; } -checkNpmVersions({ 'simpl-schema': '>=0.0.0' }, 'aldeed:collection2'); +checkNpmVersions({ 'simpl-schema': '>=0.0.0' }); const SimpleSchema = require('simpl-schema').default; @@ -49,11 +64,11 @@ const SimpleSchema = require('simpl-schema').default; const Collection2 = new EventEmitter(); Collection2.cleanOptions = { - filter: true, - autoConvert: true, - removeEmptyStrings: true, - trimStrings: true, - removeNullsFromArrays: false, + filter: true, + autoConvert: true, + removeEmptyStrings: true, + trimStrings: true, + removeNullsFromArrays: false, }; /** @@ -64,6 +79,7 @@ Collection2.cleanOptions = { * @param {Boolean} [options.transform=false] Set to `true` if your document must be passed * through the collection's transform to properly validate. * @param {Boolean} [options.replace=false] Set to `true` to replace any existing schema instead of combining + * @param {Object} [options.selector] * @return {undefined} * * Use this method to attach a schema to a collection created by another package, @@ -72,699 +88,903 @@ Collection2.cleanOptions = { * schema object passed to its constructor. */ Mongo.Collection.prototype.attachSchema = function c2AttachSchema(ss, options) { - options = options || {}; - - // Allow passing just the schema object - if (!SimpleSchema.isSimpleSchema(ss)) { - ss = new SimpleSchema(ss); - } - - function attachTo(obj) { - // we need an array to hold multiple schemas - // position 0 is reserved for the "base" schema - obj._c2 = obj._c2 || {}; - obj._c2._simpleSchemas = obj._c2._simpleSchemas || [ null ]; - - if (typeof options.selector === "object") { - // Selector Schemas - - // Extend selector schema with base schema - const baseSchema = obj._c2._simpleSchemas[0]; - if (baseSchema) { - ss = extendSchema(baseSchema.schema, ss); - } - - // Index of existing schema with identical selector - let schemaIndex; - - // Loop through existing schemas with selectors, - for (schemaIndex = obj._c2._simpleSchemas.length - 1; 0 < schemaIndex; schemaIndex--) { - const schema = obj._c2._simpleSchemas[schemaIndex]; - if (schema && isEqual(schema.selector, options.selector)) break; - } - - if (schemaIndex <= 0) { - // We didn't find the schema in our array - push it into the array - obj._c2._simpleSchemas.push({ - schema: ss, - selector: options.selector, - }); - } else { - // We found a schema with an identical selector in our array, - if (options.replace === true) { - // Replace existing selector schema with new selector schema - obj._c2._simpleSchemas[schemaIndex].schema = ss; - } else { - // Extend existing selector schema with new selector schema. - obj._c2._simpleSchemas[schemaIndex].schema = extendSchema(obj._c2._simpleSchemas[schemaIndex].schema, ss); - } - } + options = options || {}; + + // Allow passing just the schema object + if (!SimpleSchema.isSimpleSchema(ss)) { + ss = new SimpleSchema(ss); + } + + function attachTo(obj) { + // we need an array to hold multiple schemas + // position 0 is reserved for the 'base' schema + obj._c2 = obj._c2 || {}; + obj._c2._simpleSchemas = obj._c2._simpleSchemas || [null]; + + if (typeof options.selector === 'object') { + // Selector Schemas + + // Extend selector schema with base schema + const baseSchema = obj._c2._simpleSchemas[0]; + if (baseSchema) { + ss = extendSchema(baseSchema.schema, ss); + } + + // Index of existing schema with identical selector + let schemaIndex; + + // Loop through existing schemas with selectors, + for ( + schemaIndex = obj._c2._simpleSchemas.length - 1; + schemaIndex > 0; + schemaIndex-- + ) { + const schema = obj._c2._simpleSchemas[schemaIndex]; + if (schema && isEqual(schema.selector, options.selector)) break; + } + + if (schemaIndex <= 0) { + // We didn't find the schema in our array - push it into the array + obj._c2._simpleSchemas.push({ + schema: ss, + selector: options.selector, + }); + } else { + // We found a schema with an identical selector in our array, + if (options.replace === true) { + // Replace existing selector schema with new selector schema + obj._c2._simpleSchemas[schemaIndex].schema = ss; } else { - // Base Schema - if (options.replace === true) { - // Replace base schema and delete all other schemas - obj._c2._simpleSchemas = [{ - schema: ss, - selector: options.selector, - }]; - } else { - // Set base schema if not yet set - if (!obj._c2._simpleSchemas[0]) { - return obj._c2._simpleSchemas[0] = { schema: ss, selector: undefined }; - } - // Extend base schema and therefore extend all schemas - obj._c2._simpleSchemas.forEach((schema, index) => { - if (obj._c2._simpleSchemas[index]) { - obj._c2._simpleSchemas[index].schema = extendSchema(obj._c2._simpleSchemas[index].schema, ss); - } - }); - } + // Extend existing selector schema with new selector schema. + obj._c2._simpleSchemas[schemaIndex].schema = extendSchema( + obj._c2._simpleSchemas[schemaIndex].schema, + ss + ); + } + } + } else { + // Base Schema + if (options.replace === true) { + // Replace base schema and delete all other schemas + obj._c2._simpleSchemas = [ + { + schema: ss, + selector: options.selector, + }, + ]; + } else { + // Set base schema if not yet set + if (!obj._c2._simpleSchemas[0]) { + obj._c2._simpleSchemas[0] = { schema: ss, selector: undefined }; + return obj._c2._simpleSchemas[0]; } + // Extend base schema and therefore extend all schemas + obj._c2._simpleSchemas.forEach((schema, index) => { + if (obj._c2._simpleSchemas[index]) { + obj._c2._simpleSchemas[index].schema = extendSchema( + obj._c2._simpleSchemas[index].schema, + ss + ); + } + }); + } } + } - attachTo(this); - // Attach the schema to the underlying LocalCollection, too - if (this._collection instanceof LocalCollection) { - this._collection._c2 = this._collection._c2 || {}; - attachTo(this._collection); - } + attachTo(this); + // Attach the schema to the underlying LocalCollection, too + if (this._collection instanceof LocalCollection) { + this._collection._c2 = this._collection._c2 || {}; + attachTo(this._collection); + } - defineDeny(this, options); - keepInsecure(this); + defineDeny(this, options); + keepInsecure(this); - Collection2.emit('schema.attached', this, ss, options); + Collection2.emit('schema.attached', this, ss, options); }; [Mongo.Collection, LocalCollection].forEach((obj) => { - /** - * simpleSchema - * @description function detect the correct schema by given params. If it - * detect multi-schema presence in the collection, then it made an attempt to find a - * `selector` in args - * @param {Object} doc - It could be on update/upsert or document - * itself on insert/remove - * @param {Object} [options] - It could be on update/upsert etc - * @param {Object} [query] - it could be on update/upsert - * @return {Object} Schema - */ - obj.prototype.simpleSchema = function (doc, options, query) { - if (!this._c2) return null; - if (this._c2._simpleSchema) return this._c2._simpleSchema; - - const schemas = this._c2._simpleSchemas; - if (schemas && schemas.length > 0) { - - let schema, selector, target; - // Position 0 reserved for base schema - for (var i = 1; i < schemas.length; i++) { - schema = schemas[i]; - selector = Object.keys(schema.selector)[0]; - - // We will set this to undefined because in theory you might want to select - // on a null value. - target = undefined; - // here we are looking for selector in different places - // $set should have more priority here - if (doc.$set && typeof doc.$set[selector] !== 'undefined') { - target = doc.$set[selector]; - } else if (typeof doc[selector] !== 'undefined') { - target = doc[selector]; - } else if (options && options.selector) { - target = options.selector[selector]; - } else if (query && query[selector]) { // on upsert/update operations - target = query[selector]; - } - - // we need to compare given selector with doc property or option to - // find right schema - if (target !== undefined && target === schema.selector[selector]) { - return schema.schema; - } - } - if (schemas[0]) { - return schemas[0].schema; - } else { - throw new Error("No default schema"); - } - } - - return null; - }; -}); - -// Wrap DB write operation methods -['insert', 'update'].forEach((methodName) => { - const _super = Mongo.Collection.prototype[methodName]; - Mongo.Collection.prototype[methodName] = function(...args) { - let options = (methodName === "insert") ? args[1] : args[2]; - - // Support missing options arg - if (!options || typeof options === "function") { - options = {}; + /** + * simpleSchema + * @description function detect the correct schema by given params. If it + * detects multi-schema presence in the collection, then it made an attempt to find a + * `selector` in args + * @param {Object} doc - It could be on update/upsert or document + * itself on insert/remove + * @param {Object} [options] - It could be on update/upsert etc + * @param {Object} [query] - it could be on update/upsert + * @return {Object} Schema + */ + obj.prototype.simpleSchema = function (doc, options, query) { + if (!this._c2) return null; + if (this._c2._simpleSchema) return this._c2._simpleSchema; + + const schemas = this._c2._simpleSchemas; + if (schemas && schemas.length > 0) { + let schema, selector, target; + // Position 0 reserved for base schema + for (let i = 1; i < schemas.length; i++) { + schema = schemas[i]; + selector = Object.keys(schema.selector)[0]; + + // We will set this to undefined because in theory, you might want to select + // on a null value. + target = undefined; + // here we are looking for selector in different places + // $set should have more priority here + if (doc.$set && typeof doc.$set[selector] !== 'undefined') { + target = doc.$set[selector]; + } else if (typeof doc[selector] !== 'undefined') { + target = doc[selector]; + } else if (options && options.selector) { + target = options.selector[selector]; + } else if (query && query[selector]) { + // on upsert/update operations + target = query[selector]; } - if (this._c2 && options.bypassCollection2 !== true) { - let userId = null; - try { // https://github.com/aldeed/meteor-collection2/issues/175 - userId = Meteor.userId(); - } catch (err) {} - - args = doValidate( - this, - methodName, - args, - Meteor.isServer || this._connection === null, // getAutoValues - userId, - Meteor.isServer // isFromTrustedCode - ); - if (!args) { - // doValidate already called the callback or threw the error so we're done. - // But insert should always return an ID to match core behavior. - return methodName === "insert" ? this._makeNewID() : undefined; - } - } else { - // We still need to adjust args because insert does not take options - if (methodName === "insert" && typeof args[1] !== 'function') args.splice(1, 1); + // we need to compare given selector with doc property or option to + // find the right schema + if (target !== undefined && target === schema.selector[selector]) { + return schema.schema; } + } + if (schemas[0]) { + return schemas[0].schema; + } else { + throw new Error('No default schema'); + } + } - return _super.apply(this, args); - }; + return null; + }; }); -/* - * Private - */ +function _methodMutation(async, methodName) { + const _super = Meteor.isFibersDisabled + ? Mongo.Collection.prototype[methodName] + : Mongo.Collection.prototype[methodName.replace('Async', '')]; + + if (!_super) return; -function doValidate(collection, type, args, getAutoValues, userId, isFromTrustedCode) { - let doc, callback, error, options, isUpsert, selector, last, hasCallback; + Mongo.Collection.prototype[methodName] = function (...args) { + let options = isInsertType(methodName) ? args[1] : args[2]; - if (!args.length) { - throw new Error(type + " requires an argument"); + // Support missing options arg + if (!options || typeof options === 'function') { + options = {}; } - // Gather arguments and cache the selector - if (type === "insert") { - doc = args[0]; - options = args[1]; - callback = args[2]; - - // The real insert doesn't take options - if (typeof options === "function") { - args = [doc, options]; - } else if (typeof callback === "function") { - args = [doc, callback]; - } else { - args = [doc]; - } - } else if (type === "update") { - selector = args[0]; - doc = args[1]; - options = args[2]; - callback = args[3]; + let validationContext = {}; + let error; + if (this._c2 && options.bypassCollection2 !== true) { + let userId = null; + try { + // https://github.com/aldeed/meteor-collection2/issues/175 + userId = Meteor.userId(); + } catch (err) {} + + [args, validationContext] = doValidate( + this, + methodName, + args, + Meteor.isServer || this._connection === null, // getAutoValues + userId, + Meteor.isServer, // isFromTrustedCode + async + ); + + if (!args) { + // doValidate already called the callback or threw the error, so we're done. + // But insert should always return an ID to match core behavior. + return isInsertType(methodName) ? this._makeNewID() : undefined; + } } else { - throw new Error("invalid type argument"); + // We still need to adjust args because insert does not take options + if (isInsertType(methodName) && typeof args[1] !== 'function') + args.splice(1, 1); } - const validatedObjectWasInitiallyEmpty = isEmpty(doc); - - // Support missing options arg - if (!callback && typeof options === "function") { - callback = options; - options = {}; + if (async && !Meteor.isFibersDisabled) { + try { + this[methodName.replace('Async', '')].isCalledFromAsync = true; + _super.isCalledFromAsync = true; + return Promise.resolve(_super.apply(this, args)); + } catch (err) { + const addValidationErrorsPropName = + typeof validationContext.addValidationErrors === 'function' + ? 'addValidationErrors' + : 'addInvalidKeys'; + parsingServerError( + [err], + validationContext, + addValidationErrorsPropName + ); + error = getErrorObject(validationContext, err.message); + return Promise.reject(error); + } + } else { + return _super.apply(this, args); } - options = options || {}; - - last = args.length - 1; - - hasCallback = (typeof args[last] === 'function'); - - // If update was called with upsert:true, flag as an upsert - isUpsert = (type === "update" && options.upsert === true); - - // we need to pass `doc` and `options` to `simpleSchema` method, that's why - // schema declaration moved here - let schema = collection.simpleSchema(doc, options, selector); - const isLocalCollection = (collection._connection === null); + }; +} - // On the server and for local collections, we allow passing `getAutoValues: false` to disable autoValue functions - if ((Meteor.isServer || isLocalCollection) && options.getAutoValues === false) { - getAutoValues = false; - } +function _methodMutationAsync(methodName) { + const _super = Mongo.Collection.prototype[methodName]; + Mongo.Collection.prototype[methodName] = async function (...args) { + let options = isInsertType(methodName) ? args[1] : args[2]; - // Process pick/omit options if they are present - const picks = Array.isArray(options.pick) ? options.pick : null; - const omits = Array.isArray(options.omit) ? options.omit : null; - - if (picks && omits) { - // Pick and omit cannot both be present in the options - throw new Error('pick and omit options are mutually exclusive'); - } else if (picks) { - schema = schema.pick(...picks); - } else if (omits) { - schema = schema.omit(...omits); + // Support missing options arg + if (!options || typeof options === 'function') { + options = {}; } - // Determine validation context - let validationContext = options.validationContext; - if (validationContext) { - if (typeof validationContext === 'string') { - validationContext = schema.namedContext(validationContext); - } + let validationContext = {}; + if (this._c2 && options.bypassCollection2 !== true) { + let userId = null; + try { + // https://github.com/aldeed/meteor-collection2/issues/175 + userId = Meteor.userId(); + } catch (err) {} + + [args, validationContext] = doValidate( + this, + methodName, + args, + Meteor.isServer || this._connection === null, // getAutoValues + userId, + Meteor.isServer, // isFromTrustedCode + true + ); + + if (!args) { + // doValidate already called the callback or threw the error, so we're done. + // But insert should always return an ID to match core behavior. + return isInsertType(methodName) ? this._makeNewID() : undefined; + } } else { - validationContext = schema.namedContext(); + // We still need to adjust args because insert does not take options + if (methodName === 'insert' && typeof args[1] !== 'function') + args.splice(1, 1); } - // Add a default callback function if we're on the client and no callback was given - if (Meteor.isClient && !callback) { - // Client can't block, so it can't report errors by exception, - // only by callback. If they forget the callback, give them a - // default one that logs the error, so they aren't totally - // baffled if their writes don't work because their database is - // down. - callback = function(err) { - if (err) { - Meteor._debug(type + " failed: " + (err.reason || err.stack)); - } - }; + try { + return await _super.apply(this, args); + } catch (err) { + const addValidationErrorsPropName = + typeof validationContext.addValidationErrors === 'function' + ? 'addValidationErrors' + : 'addInvalidKeys'; + parsingServerError([err], validationContext, addValidationErrorsPropName); + throw getErrorObject(validationContext, err.message); } + }; +} - // If client validation is fine or is skipped but then something - // is found to be invalid on the server, we get that error back - // as a special Meteor.Error that we need to parse. - if (Meteor.isClient && hasCallback) { - callback = args[last] = wrapCallbackForParsingServerErrors(validationContext, callback); - } +// Wrap DB write operation methods +if (Mongo.Collection.prototype.insertAsync) { + if (Meteor.isFibersDisabled) { + ['insertAsync', 'updateAsync'].forEach(_methodMutationAsync.bind(this)); + } else { + ['insertAsync', 'updateAsync'].forEach(_methodMutation.bind(this, true)); + } +} +['insert', 'update'].forEach(_methodMutation.bind(this, false)); - const schemaAllowsId = schema.allowsKey("_id"); - if (type === "insert" && !doc._id && schemaAllowsId) { - doc._id = collection._makeNewID(); - } +/* + * Private + */ - // Get the docId for passing in the autoValue/custom context - let docId; - if (type === 'insert') { - docId = doc._id; // might be undefined - } else if (type === "update" && selector) { - docId = typeof selector === 'string' || selector instanceof Mongo.ObjectID ? selector : selector._id; +function doValidate( + collection, + type, + args, + getAutoValues, + userId, + isFromTrustedCode, + async +) { + let doc, callback, error, options, selector; + + if (!args.length) { + throw new Error(type + ' requires an argument'); + } + + // Gather arguments and cache the selector + if (isInsertType(type)) { + doc = args[0]; + options = args[1]; + callback = args[2]; + + // The real insert doesn't take options + if (typeof options === 'function') { + args = [doc, options]; + } else if (typeof callback === 'function') { + args = [doc, callback]; + } else { + args = [doc]; } - - // If _id has already been added, remove it temporarily if it's - // not explicitly defined in the schema. - let cachedId; - if (doc._id && !schemaAllowsId) { - cachedId = doc._id; - delete doc._id; + } else if (isUpdateType(type)) { + selector = args[0]; + doc = args[1]; + options = args[2]; + callback = args[3]; + } else { + throw new Error('invalid type argument'); + } + + const validatedObjectWasInitiallyEmpty = isEmpty(doc); + + // Support missing options arg + if (!callback && typeof options === 'function') { + callback = options; + options = {}; + } + options = options || {}; + + const last = args.length - 1; + + const hasCallback = typeof args[last] === 'function'; + + // If update was called with upsert:true, flag as an upsert + const isUpsert = isUpdateType(type) && options.upsert === true; + + // we need to pass `doc` and `options` to `simpleSchema` method, that's why + // schema declaration moved here + let schema = collection.simpleSchema(doc, options, selector); + const isLocalCollection = collection._connection === null; + + // On the server and for local collections, we allow passing `getAutoValues: false` to disable autoValue functions + if ( + (Meteor.isServer || isLocalCollection) && + options.getAutoValues === false + ) { + getAutoValues = false; + } + + // Process pick/omit options if they are present + const picks = Array.isArray(options.pick) ? options.pick : null; + const omits = Array.isArray(options.omit) ? options.omit : null; + + if (picks && omits) { + // Pick and omit cannot both be present in the options + throw new Error('pick and omit options are mutually exclusive'); + } else if (picks) { + schema = schema.pick(...picks); + } else if (omits) { + schema = schema.omit(...omits); + } + + // Determine validation context + let validationContext = options.validationContext; + if (validationContext) { + if (typeof validationContext === 'string') { + validationContext = schema.namedContext(validationContext); } - - const autoValueContext = { - isInsert: (type === "insert"), - isUpdate: (type === "update" && options.upsert !== true), + } else { + validationContext = schema.namedContext(); + } + + // Add a default callback function if we're on the client and no callback was given + if (Meteor.isClient && !callback && !async) { + // Client can't block, so it can't report errors by exception, + // only by callback. If they forget the callback, give them a + // default one that logs the error, so they aren't totally + // baffled if their writing doesn't work because their database is + // down. + callback = function (err) { + if (err) { + Meteor._debug(type + ' failed: ' + (err.reason || err.stack)); + } + }; + } + + // If client validation is fine or is skipped but then something + // is found to be invalid on the server, we get that error back + // as a special Meteor.Error that we need to parse. + if (Meteor.isClient && hasCallback) { + callback = args[last] = wrapCallbackForParsingServerErrors( + validationContext, + callback + ); + } + + const schemaAllowsId = schema.allowsKey('_id'); + if (isInsertType(type) && !doc._id && schemaAllowsId) { + doc._id = collection._makeNewID(); + } + + // Get the docId for passing in the autoValue/custom context + let docId; + if (isInsertType(type)) { + docId = doc._id; // might be undefined + } else if (isUpdateType(type) && selector) { + docId = + typeof selector === 'string' || selector instanceof Mongo.ObjectID + ? selector + : selector._id; + } + + // If _id has already been added, remove it temporarily if it's + // not explicitly defined in the schema. + let cachedId; + if (doc._id && !schemaAllowsId) { + cachedId = doc._id; + delete doc._id; + } + + const autoValueContext = { + isInsert: isInsertType(type), + isUpdate: isUpdateType(type) && options.upsert !== true, + isUpsert, + userId, + isFromTrustedCode, + docId, + isLocalCollection, + }; + + const extendAutoValueContext = { + ...((schema._cleanOptions || {}).extendAutoValueContext || {}), + ...autoValueContext, + ...options.extendAutoValueContext, + }; + + const cleanOptionsForThisOperation = {}; + [ + 'autoConvert', + 'filter', + 'removeEmptyStrings', + 'removeNullsFromArrays', + 'trimStrings', + ].forEach((prop) => { + if (typeof options[prop] === 'boolean') { + cleanOptionsForThisOperation[prop] = options[prop]; + } + }); + + // Preliminary cleaning on both client and server. On the server and for local + // collections, automatic values will also be set at this point. + schema.clean(doc, { + mutate: true, // Clean the doc/modifier in place + isModifier: !isInsertType(type), + // Start with some Collection2 defaults, which will usually be overwritten + ...Collection2.cleanOptions, + // The extent with the schema-level defaults (from SimpleSchema constructor options) + ...(schema._cleanOptions || {}), + // Finally, options for this specific operation should take precedence + ...cleanOptionsForThisOperation, + extendAutoValueContext, // This was extended separately above + getAutoValues, // Force this override + }); + + // We clone before validating because in some cases, we need to adjust the + // object a bit before validating it. If we adjusted `doc` itself, our + // changes would persist into the database. + const docToValidate = {}; + for (const prop in doc) { + // We omit prototype properties when cloning because they will not be valid + // and mongo omits them when saving to the database anyway. + if (Object.prototype.hasOwnProperty.call(doc, prop)) { + docToValidate[prop] = doc[prop]; + } + } + + // On the server, upserts are possible; SimpleSchema handles upserts pretty + // well by default, but it will not know about the fields in the selector, + // which are also stored in the database if an insert is performed. So we + // will allow these fields to be considered for validation by adding them + // to the $set in the modifier, while stripping out query selectors as these + // don't make it into the upserted document and break validation. + // This is no doubt prone to errors, but there probably isn't any better way + // right now. + if (Meteor.isServer && isUpsert && isObject(selector)) { + const set = docToValidate.$set || {}; + docToValidate.$set = flattenSelector(selector); + + if (!schemaAllowsId) delete docToValidate.$set._id; + Object.assign(docToValidate.$set, set); + } + // Set automatic values for validation on the client. + // On the server, we already updated doc with auto values, but on the client, + // we will add them to docToValidate for validation purposes only. + // This is because we want all actual values generated on the server. + if (Meteor.isClient && !isLocalCollection) { + schema.clean(docToValidate, { + autoConvert: false, + extendAutoValueContext, + filter: false, + getAutoValues: true, + isModifier: !isInsertType(type), + mutate: true, // Clean the doc/modifier in place + removeEmptyStrings: false, + removeNullsFromArrays: false, + trimStrings: false, + }); + } + + // XXX Maybe move this into SimpleSchema + if (!validatedObjectWasInitiallyEmpty && isEmpty(docToValidate)) { + throw new Error( + 'After filtering out keys not in the schema, your ' + + (isUpdateType(type) ? 'modifier' : 'object') + + ' is now empty' + ); + } + + // Validate doc + let isValid; + if (options.validate === false) { + isValid = true; + } else { + isValid = validationContext.validate(docToValidate, { + modifier: isUpdateType(type) || isUpsertType(type), + upsert: isUpsert, + extendedCustomContext: { + isInsert: isInsertType(type), + isUpdate: isUpdateType(type) && options.upsert !== true, isUpsert, userId, isFromTrustedCode, docId, - isLocalCollection - }; - - const extendAutoValueContext = { - ...((schema._cleanOptions || {}).extendAutoValueContext || {}), - ...autoValueContext, - ...options.extendAutoValueContext, - }; - - const cleanOptionsForThisOperation = {}; - ["autoConvert", "filter", "removeEmptyStrings", "removeNullsFromArrays", "trimStrings"].forEach(prop => { - if (typeof options[prop] === "boolean") { - cleanOptionsForThisOperation[prop] = options[prop]; - } + isLocalCollection, + ...(options.extendedCustomContext || {}), + }, }); + } - // Preliminary cleaning on both client and server. On the server and for local - // collections, automatic values will also be set at this point. - schema.clean(doc, { - mutate: true, // Clean the doc/modifier in place - isModifier: (type !== "insert"), - // Start with some Collection2 defaults, which will usually be overwritten - ...Collection2.cleanOptions, - // The extend with the schema-level defaults (from SimpleSchema constructor options) - ...(schema._cleanOptions || {}), - // Finally, options for this specific operation should take precedence - ...cleanOptionsForThisOperation, - extendAutoValueContext, // This was extended separately above - getAutoValues, // Force this override - }); - - // We clone before validating because in some cases we need to adjust the - // object a bit before validating it. If we adjusted `doc` itself, our - // changes would persist into the database. - let docToValidate = {}; - for (var prop in doc) { - // We omit prototype properties when cloning because they will not be valid - // and mongo omits them when saving to the database anyway. - if (Object.prototype.hasOwnProperty.call(doc, prop)) { - docToValidate[prop] = doc[prop]; - } - } - - // On the server, upserts are possible; SimpleSchema handles upserts pretty - // well by default, but it will not know about the fields in the selector, - // which are also stored in the database if an insert is performed. So we - // will allow these fields to be considered for validation by adding them - // to the $set in the modifier, while stripping out query selectors as these - // don't make it into the upserted document and break validation. - // This is no doubt prone to errors, but there probably isn't any better way - // right now. - if (Meteor.isServer && isUpsert && isObject(selector)) { - const set = docToValidate.$set || {}; - docToValidate.$set = flattenSelector(selector); - - if (!schemaAllowsId) delete docToValidate.$set._id; - Object.assign(docToValidate.$set, set); - } - // Set automatic values for validation on the client. - // On the server, we already updated doc with auto values, but on the client, - // we will add them to docToValidate for validation purposes only. - // This is because we want all actual values generated on the server. - if (Meteor.isClient && !isLocalCollection) { - schema.clean(docToValidate, { - autoConvert: false, - extendAutoValueContext, - filter: false, - getAutoValues: true, - isModifier: (type !== "insert"), - mutate: true, // Clean the doc/modifier in place - removeEmptyStrings: false, - removeNullsFromArrays: false, - trimStrings: false, - }); - } - - // XXX Maybe move this into SimpleSchema - if (!validatedObjectWasInitiallyEmpty && isEmpty(docToValidate)) { - throw new Error('After filtering out keys not in the schema, your ' + - (type === 'update' ? 'modifier' : 'object') + - ' is now empty'); + if (isValid) { + // Add the ID back + if (cachedId) { + doc._id = cachedId; } - // Validate doc - let isValid; - if (options.validate === false) { - isValid = true; + // Update the args to reflect the cleaned doc + // XXX not sure if this is necessary since we mutate + if (isInsertType(type)) { + args[0] = doc; } else { - isValid = validationContext.validate(docToValidate, { - modifier: (type === "update" || type === "upsert"), - upsert: isUpsert, - extendedCustomContext: { - isInsert: (type === "insert"), - isUpdate: (type === "update" && options.upsert !== true), - isUpsert, - userId, - isFromTrustedCode, - docId, - isLocalCollection, - ...(options.extendedCustomContext || {}), - }, - }); + args[1] = doc; } - if (isValid) { - // Add the ID back - if (cachedId) { - doc._id = cachedId; - } - - // Update the args to reflect the cleaned doc - // XXX not sure this is necessary since we mutate - if (type === "insert") { - args[0] = doc; - } else { - args[1] = doc; - } - - // If callback, set invalidKey when we get a mongo unique error - if (Meteor.isServer && hasCallback) { - args[last] = wrapCallbackForParsingMongoValidationErrors(validationContext, args[last]); - } + // If callback, set invalidKey when we get a mongo unique error + if (Meteor.isServer && hasCallback) { + args[last] = wrapCallbackForParsingMongoValidationErrors( + validationContext, + args[last] + ); + } - return args; + return [args, validationContext]; + } else { + error = getErrorObject( + validationContext, + Meteor.settings?.packages?.collection2?.disableCollectionNamesInValidation + ? '' + : `in ${collection._name} ${type}` + ); + if (callback) { + // insert/update/upsert pass `false` when there's an error, so we do that + callback(error, false); + return []; } else { - error = getErrorObject(validationContext, Meteor.settings?.packages?.collection2?.disableCollectionNamesInValidation ? '' : `in ${collection._name} ${type}`); - if (callback) { - // insert/update/upsert pass `false` when there's an error, so we do that - callback(error, false); - } else { - throw error; - } + throw error; } + } } function getErrorObject(context, appendToMessage = '') { - let message; - const invalidKeys = (typeof context.validationErrors === 'function') ? context.validationErrors() : context.invalidKeys(); - if (invalidKeys.length) { - const firstErrorKey = invalidKeys[0].name; - const firstErrorMessage = context.keyErrorMessage(firstErrorKey); - - // If the error is in a nested key, add the full key to the error message - // to be more helpful. - if (firstErrorKey.indexOf('.') === -1) { - message = firstErrorMessage; - } else { - message = `${firstErrorMessage} (${firstErrorKey})`; - } + let message; + const invalidKeys = + typeof context.validationErrors === 'function' + ? context.validationErrors() + : context.invalidKeys(); + if (invalidKeys.length) { + const firstErrorKey = invalidKeys[0].name; + const firstErrorMessage = context.keyErrorMessage(firstErrorKey); + + // If the error is in a nested key, add the full key to the error message + // to be more helpful. + if (firstErrorKey.indexOf('.') === -1) { + message = firstErrorMessage; } else { - message = "Failed validation"; + message = `${firstErrorMessage} (${firstErrorKey})`; } - message = `${message} ${appendToMessage}`.trim(); - const error = new Error(message); - error.invalidKeys = invalidKeys; - error.validationContext = context; - // If on the server, we add a sanitized error, too, in case we're - // called from a method. - if (Meteor.isServer) { - error.sanitizedError = new Meteor.Error(400, message, EJSON.stringify(error.invalidKeys)); - } - return error; + } else { + message = 'Failed validation'; + } + message = `${message} ${appendToMessage}`.trim(); + const error = new Error(message); + error.invalidKeys = invalidKeys; + error.validationContext = context; + // If on the server, we add a sanitized error, too, in case we're + // called from a method. + if (Meteor.isServer) { + error.sanitizedError = new Meteor.Error( + 400, + message, + EJSON.stringify(error.invalidKeys) + ); + } + return error; } function addUniqueError(context, errorMessage) { - const name = errorMessage.split('c2_')[1].split(' ')[0]; - const val = errorMessage.split('dup key:')[1].split('"')[1]; - - const addValidationErrorsPropName = (typeof context.addValidationErrors === 'function') ? 'addValidationErrors' : 'addInvalidKeys'; - context[addValidationErrorsPropName]([{ - name: name, - type: 'notUnique', - value: val - }]); + const name = errorMessage.split('c2_')[1].split(' ')[0]; + const val = errorMessage.split('dup key:')[1].split('"')[1]; + + const addValidationErrorsPropName = + typeof context.addValidationErrors === 'function' + ? 'addValidationErrors' + : 'addInvalidKeys'; + context[addValidationErrorsPropName]([ + { + name, + type: 'notUnique', + value: val, + }, + ]); +} + +function parsingServerError( + args, + validationContext, + addValidationErrorsPropName +) { + const error = args[0]; + // Handle our own validation errors + if ( + error instanceof Meteor.Error && + error.error === 400 && + error.reason === 'INVALID' && + typeof error.details === 'string' + ) { + const invalidKeysFromServer = EJSON.parse(error.details); + validationContext[addValidationErrorsPropName](invalidKeysFromServer); + args[0] = getErrorObject(validationContext); + } else if ( + error instanceof Meteor.Error && + // Handle Mongo unique index errors, which are forwarded to the client as 409 errors + error.error === 409 && + error.reason && + error.reason.indexOf('E11000') !== -1 && + error.reason.indexOf('c2_') !== -1 + ) { + addUniqueError(validationContext, error.reason); + args[0] = getErrorObject(validationContext); + } } function wrapCallbackForParsingMongoValidationErrors(validationContext, cb) { - return function wrappedCallbackForParsingMongoValidationErrors(...args) { - const error = args[0]; - if (error && - ((error.name === "MongoError" && error.code === 11001) || error.message.indexOf('MongoError: E11000') !== -1) && - error.message.indexOf('c2_') !== -1) { - addUniqueError(validationContext, error.message); - args[0] = getErrorObject(validationContext); - } - return cb.apply(this, args); - }; + return function wrappedCallbackForParsingMongoValidationErrors(...args) { + const error = args[0]; + if ( + error && + ((error.name === 'MongoError' && error.code === 11001) || + error.message.indexOf('MongoError: E11000') !== -1) && + error.message.indexOf('c2_') !== -1 + ) { + addUniqueError(validationContext, error.message); + args[0] = getErrorObject(validationContext); + } + return cb.apply(this, args); + }; } function wrapCallbackForParsingServerErrors(validationContext, cb) { - const addValidationErrorsPropName = (typeof validationContext.addValidationErrors === 'function') ? 'addValidationErrors' : 'addInvalidKeys'; - return function wrappedCallbackForParsingServerErrors(...args) { - const error = args[0]; - // Handle our own validation errors - if (error instanceof Meteor.Error && - error.error === 400 && - error.reason === "INVALID" && - typeof error.details === "string") { - const invalidKeysFromServer = EJSON.parse(error.details); - validationContext[addValidationErrorsPropName](invalidKeysFromServer); - args[0] = getErrorObject(validationContext); - } - // Handle Mongo unique index errors, which are forwarded to the client as 409 errors - else if (error instanceof Meteor.Error && - error.error === 409 && - error.reason && - error.reason.indexOf('E11000') !== -1 && - error.reason.indexOf('c2_') !== -1) { - addUniqueError(validationContext, error.reason); - args[0] = getErrorObject(validationContext); - } - return cb.apply(this, args); - }; + const addValidationErrorsPropName = + typeof validationContext.addValidationErrors === 'function' + ? 'addValidationErrors' + : 'addInvalidKeys'; + return function wrappedCallbackForParsingServerErrors(...args) { + parsingServerError(args, validationContext, addValidationErrorsPropName); + return cb.apply(this, args); + }; } -let alreadyInsecure = {}; +const alreadyInsecure = {}; + function keepInsecure(c) { - // If insecure package is in use, we need to add allow rules that return - // true. Otherwise, it would seemingly turn off insecure mode. - if (Package && Package.insecure && !alreadyInsecure[c._name]) { - c.allow({ - insert: function() { - return true; - }, - update: function() { - return true; - }, - remove: function () { - return true; - }, - fetch: [], - transform: null - }); - alreadyInsecure[c._name] = true; + // If insecure package is in use, we need to add allow rules that return + // true. Otherwise, it would seemingly turn off insecure mode. + if (Package && Package.insecure && !alreadyInsecure[c._name]) { + const allow = { + insert: function () { + return true; + }, + update: function () { + return true; + }, + remove: function () { + return true; + }, + fetch: [], + transform: null, + }; + + if (Meteor.isFibersDisabled) { + Object.assign(allow, { + insertAsync: allow.insert, + updateAsync: allow.update, + removeAsync: allow.remove, + }); } - // If insecure package is NOT in use, then adding the two deny functions - // does not have any effect on the main app's security paradigm. The - // user will still be required to add at least one allow function of her - // own for each operation for this collection. And the user may still add - // additional deny functions, but does not have to. + + c.allow(allow); + + alreadyInsecure[c._name] = true; + } + // If insecure package is NOT in use, then adding the two deny functions + // does not have any effect on the main app's security paradigm. The + // user will still be required to add at least one allow function of her + // own for each operation for this collection. And the user may still add + // additional deny functions, but does not have to. } -let alreadyDefined = {}; +const alreadyDefined = {}; + function defineDeny(c, options) { - if (!alreadyDefined[c._name]) { - - const isLocalCollection = (c._connection === null); - - // First define deny functions to extend doc with the results of clean - // and auto-values. This must be done with "transform: null" or we would be - // extending a clone of doc and therefore have no effect. - c.deny({ - insert: function(userId, doc) { - // Referenced doc is cleaned in place - c.simpleSchema(doc).clean(doc, { - mutate: true, - isModifier: false, - // We don't do these here because they are done on the client if desired - filter: false, - autoConvert: false, - removeEmptyStrings: false, - trimStrings: false, - extendAutoValueContext: { - isInsert: true, - isUpdate: false, - isUpsert: false, - userId: userId, - isFromTrustedCode: false, - docId: doc._id, - isLocalCollection: isLocalCollection - } - }); - - return false; - }, - update: function(userId, doc, fields, modifier) { - // Referenced modifier is cleaned in place - c.simpleSchema(modifier).clean(modifier, { - mutate: true, - isModifier: true, - // We don't do these here because they are done on the client if desired - filter: false, - autoConvert: false, - removeEmptyStrings: false, - trimStrings: false, - extendAutoValueContext: { - isInsert: false, - isUpdate: true, - isUpsert: false, - userId: userId, - isFromTrustedCode: false, - docId: doc && doc._id, - isLocalCollection: isLocalCollection - } - }); - - return false; - }, - fetch: ['_id'], - transform: null + if (!alreadyDefined[c._name]) { + const isLocalCollection = c._connection === null; + + // First, define deny functions to extend doc with the results of clean + // and auto-values. This must be done with 'transform: null' or we would be + // extending a clone of doc and therefore have no effect. + const firstDeny = { + insert: function (userId, doc) { + // Referenced doc is cleaned in place + c.simpleSchema(doc).clean(doc, { + mutate: true, + isModifier: false, + // We don't do these here because they are done on the client if desired + filter: false, + autoConvert: false, + removeEmptyStrings: false, + trimStrings: false, + extendAutoValueContext: { + isInsert: true, + isUpdate: false, + isUpsert: false, + userId, + isFromTrustedCode: false, + docId: doc._id, + isLocalCollection, + }, }); - // Second define deny functions to validate again on the server - // for client-initiated inserts and updates. These should be - // called after the clean/auto-value functions since we're adding - // them after. These must *not* have "transform: null" if options.transform is true because - // we need to pass the doc through any transforms to be sure - // that custom types are properly recognized for type validation. - c.deny({ - insert: function(userId, doc) { - // We pass the false options because we will have done them on client if desired - doValidate( - c, - "insert", - [ - doc, - { - trimStrings: false, - removeEmptyStrings: false, - filter: false, - autoConvert: false - }, - function(error) { - if (error) { - throw new Meteor.Error(400, 'INVALID', EJSON.stringify(error.invalidKeys)); - } - } - ], - false, // getAutoValues - userId, - false // isFromTrustedCode - ); + return false; + }, + update: function (userId, doc, fields, modifier) { + // Referenced modifier is cleaned in place + c.simpleSchema(modifier).clean(modifier, { + mutate: true, + isModifier: true, + // We don't do these here because they are done on the client if desired + filter: false, + autoConvert: false, + removeEmptyStrings: false, + trimStrings: false, + extendAutoValueContext: { + isInsert: false, + isUpdate: true, + isUpsert: false, + userId, + isFromTrustedCode: false, + docId: doc && doc._id, + isLocalCollection, + }, + }); + + return false; + }, + fetch: ['_id'], + transform: null, + }; + + if (Meteor.isFibersDisabled) { + Object.assign(firstDeny, { + insertAsync: firstDeny.insert, + updateAsync: firstDeny.update, + }); + } - return false; + c.deny(firstDeny); + + // Second, define deny functions to validate again on the server + // for client-initiated inserts and updates. These should be + // called after the clean/auto-value functions since we're adding + // them after. These must *not* have 'transform: null' if options.transform is true because + // we need to pass the doc through any transforms to be sure + // that custom types are properly recognized for type validation. + const secondDeny = { + insert: function (userId, doc) { + // We pass the false options because we will have done them on the client if desired + doValidate( + c, + 'insert', + [ + doc, + { + trimStrings: false, + removeEmptyStrings: false, + filter: false, + autoConvert: false, }, - update: function(userId, doc, fields, modifier) { - // NOTE: This will never be an upsert because client-side upserts - // are not allowed once you define allow/deny functions. - // We pass the false options because we will have done them on client if desired - doValidate( - c, - "update", - [ - {_id: doc && doc._id}, - modifier, - { - trimStrings: false, - removeEmptyStrings: false, - filter: false, - autoConvert: false - }, - function(error) { - if (error) { - throw new Meteor.Error(400, 'INVALID', EJSON.stringify(error.invalidKeys)); - } - } - ], - false, // getAutoValues - userId, - false // isFromTrustedCode + function (error) { + if (error) { + throw new Meteor.Error( + 400, + 'INVALID', + EJSON.stringify(error.invalidKeys) ); - - return false; + } }, - fetch: ['_id'], - ...(options.transform === true ? {} : {transform: null}), - }); + ], + false, // getAutoValues + userId, + false // isFromTrustedCode + ); + + return false; + }, + update: function (userId, doc, fields, modifier) { + // NOTE: This will never be an upsert because client-side upserts + // are not allowed once you define allow/deny functions. + // We pass the false options because we will have done them on the client if desired + doValidate( + c, + 'update', + [ + { _id: doc && doc._id }, + modifier, + { + trimStrings: false, + removeEmptyStrings: false, + filter: false, + autoConvert: false, + }, + function (error) { + if (error) { + throw new Meteor.Error( + 400, + 'INVALID', + EJSON.stringify(error.invalidKeys) + ); + } + }, + ], + false, // getAutoValues + userId, + false // isFromTrustedCode + ); + + return false; + }, + fetch: ['_id'], + ...(options.transform === true ? {} : { transform: null }), + }; - // note that we've already done this collection so that we don't do it again - // if attachSchema is called again - alreadyDefined[c._name] = true; + if (Meteor.isFibersDisabled) { + Object.assign(secondDeny, { + insertAsync: secondDeny.insert, + updateAsync: secondDeny.update, + }); } -} -function extendSchema(s1, s2) { - if (s2.version >= 2) { - const ss = new SimpleSchema(s1); - ss.extend(s2); - return ss; - } else { - return new SimpleSchema([ s1, s2 ]); - } + c.deny(secondDeny); + + // note that we've already done this collection so that we don't do it again + // if attachSchema is called again + alreadyDefined[c._name] = true; + } } -export default Collection2; \ No newline at end of file +export function extendSchema(s1, s2) { + if (s2.version >= 2) { + const ss = new SimpleSchema(s1); + ss.extend(s2); + return ss; + } else { + return new SimpleSchema([s1, s2]); + } +} From e1952b67cf8e0ff125916c321388e00041abfac7 Mon Sep 17 00:00:00 2001 From: filipenevola Date: Wed, 15 Nov 2023 23:47:44 -0500 Subject: [PATCH 03/10] ### 2.0.0 (2023-11-15) - Compatible with Meteor 3.0 (hooks and helpers are still not supported tho) - Removes `definition` option (and types) --- .npm/package/.gitignore | 1 + .npm/package/README | 7 +++ .npm/package/npm-shrinkwrap.json | 20 +++++++ .versions | 99 +++++++++++++++++--------------- CHANGELOG.md | 5 ++ CustomType.js | 88 ---------------------------- CustomTypeCollection.js | 96 ------------------------------- EJSONType.js | 12 ---- README.md | 12 +--- collections.js | 25 ++------ package.js | 18 +++--- 11 files changed, 101 insertions(+), 282 deletions(-) create mode 100644 .npm/package/.gitignore create mode 100644 .npm/package/README create mode 100644 .npm/package/npm-shrinkwrap.json delete mode 100644 CustomType.js delete mode 100644 CustomTypeCollection.js delete mode 100644 EJSONType.js diff --git a/.npm/package/.gitignore b/.npm/package/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.npm/package/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/.npm/package/README b/.npm/package/README new file mode 100644 index 0000000..3d49255 --- /dev/null +++ b/.npm/package/README @@ -0,0 +1,7 @@ +This directory and the files immediately inside it are automatically generated +when you change this package's NPM dependencies. Commit the files in this +directory (npm-shrinkwrap.json, .gitignore, and this README) to source control +so that others run the same versions of sub-dependencies. + +You should NOT check in the node_modules directory that Meteor automatically +creates; if you are using git, the .gitignore file tells git to ignore it. diff --git a/.npm/package/npm-shrinkwrap.json b/.npm/package/npm-shrinkwrap.json new file mode 100644 index 0000000..190b5d3 --- /dev/null +++ b/.npm/package/npm-shrinkwrap.json @@ -0,0 +1,20 @@ +{ + "lockfileVersion": 4, + "dependencies": { + "lodash.isempty": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz", + "integrity": "sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg==" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, + "lodash.isobject": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", + "integrity": "sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA==" + } + } +} diff --git a/.versions b/.versions index 12b7f03..440fa57 100644 --- a/.versions +++ b/.versions @@ -1,48 +1,53 @@ -allow-deny@1.1.1 -babel-compiler@7.10.3 -babel-runtime@1.5.1 -base64@1.0.12 -binary-heap@1.0.11 -boilerplate-generator@1.7.1 -callback-hook@1.5.0 -check@1.3.2 -ddp@1.4.1 -ddp-client@2.6.1 -ddp-common@1.4.0 -ddp-server@2.6.0 -diff-sequence@1.1.2 -dynamic-import@0.7.2 -ecmascript@0.16.6 -ecmascript-runtime@0.8.0 -ecmascript-runtime-client@0.12.1 -ecmascript-runtime-server@0.11.0 -ejson@1.1.3 -fetch@0.1.3 -geojson-utils@1.0.11 -id-map@1.1.1 -inter-process-messaging@0.1.1 -logging@1.3.2 -meteor@1.11.1 -minimongo@1.9.2 -modern-browsers@0.1.9 -modules@0.19.0 -modules-runtime@0.13.1 -mongo@1.16.5 -mongo-decimal@0.1.3 -mongo-dev-server@1.1.0 -mongo-id@1.0.8 -npm-mongo@4.14.0 -ordered-dict@1.1.0 -promise@0.12.2 -quave:collections@1.1.0 +allow-deny@2.0.0-alpha300.18 +babel-compiler@7.11.0-alpha300.18 +babel-runtime@1.5.2-alpha300.18 +base64@1.0.13-alpha300.18 +binary-heap@1.0.12-alpha300.18 +boilerplate-generator@2.0.0-alpha300.18 +callback-hook@1.6.0-alpha300.18 +check@1.3.3-alpha300.18 +core-runtime@1.0.0-alpha300.18 +ddp@1.4.2-alpha300.18 +ddp-client@3.0.0-alpha300.18 +ddp-common@1.4.1-alpha300.18 +ddp-server@3.0.0-alpha300.18 +diff-sequence@1.1.3-alpha300.18 +dynamic-import@0.7.4-alpha300.18 +ecmascript@0.16.8-alpha300.18 +ecmascript-runtime@0.8.2-alpha300.18 +ecmascript-runtime-client@0.12.2-alpha300.18 +ecmascript-runtime-server@0.11.1-alpha300.18 +ejson@1.1.4-alpha300.18 +facts-base@1.0.2-alpha300.18 +fetch@0.1.4-alpha300.18 +geojson-utils@1.0.12-alpha300.18 +id-map@1.2.0-alpha300.18 +inter-process-messaging@0.1.2-alpha300.18 +logging@1.3.3-alpha300.18 +meteor@2.0.0-alpha300.18 +minimongo@2.0.0-alpha300.18 +modern-browsers@0.1.10-alpha300.18 +modules@0.19.1-alpha300.18 +modules-runtime@0.13.2-alpha300.18 +mongo@2.0.0-alpha300.18 +mongo-decimal@0.1.4-alpha300.18 +mongo-dev-server@1.1.1-alpha300.18 +mongo-id@1.0.9-alpha300.18 +npm-mongo@4.16.1-alpha300.18 +ordered-dict@1.2.0-alpha300.18 +promise@1.0.0-alpha300.18 +quave:collections@2.0.0 quave:settings@1.0.0 -random@1.2.1 -react-fast-refresh@0.2.6 -reload@1.3.1 -retry@1.1.0 -routepolicy@1.1.1 -socket-stream-client@0.5.0 -tracker@1.3.1 -underscore@1.0.12 -webapp@1.13.4 -webapp-hashing@1.1.1 +raix:eventemitter@1.0.0 +random@1.2.2-alpha300.18 +react-fast-refresh@0.2.8-alpha300.18 +reload@1.3.2-alpha300.18 +retry@1.1.1-alpha300.18 +routepolicy@1.1.2-alpha300.18 +socket-stream-client@0.5.2-alpha300.18 +tmeasday:check-npm-versions@1.0.2 +tracker@1.3.3-alpha300.18 +typescript@4.9.5-alpha300.18 +underscore@1.0.14-alpha300.18 +webapp@2.0.0-alpha300.18 +webapp-hashing@1.1.2-alpha300.18 diff --git a/CHANGELOG.md b/CHANGELOG.md index b020f92..2ff7d34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## CHANGELOG +### 2.0.0 (2023-11-15) + +- Compatible with Meteor 3.0 (hooks and helpers are still not supported tho) +- Removes `definition` option (and types) + ### 1.1.0 (2023-03-13) - Composer now receives the collection object from Meteor already assigned to the `collection` property. Before it was getting only the collection property. diff --git a/CustomType.js b/CustomType.js deleted file mode 100644 index 2ef1951..0000000 --- a/CustomType.js +++ /dev/null @@ -1,88 +0,0 @@ -import { EJSON } from 'meteor/ejson'; - -import { getSettings } from 'meteor/quave:settings'; - -const PACKAGE_NAME = 'quave:collections'; -const settings = getSettings({ packageName: PACKAGE_NAME }); - -const { isVerbose } = settings; - -export const CustomTypes = { - scalarAndEjson(type) { - return { - name: type.name(), - description: type.description(), - serialize: obj => obj, - parseValue: obj => obj, - }; - }, -}; - -/* eslint-disable class-methods-use-this */ -export class CustomType { - constructor() { - this.register(); - } - - register() { - // Type is already present - if (!EJSON._getTypes()[this.name()]) { - if (isVerbose) { - console.log( - `${PACKAGE_NAME} EJSON.addType ${this.name()} from TypeDef class` - ); - } - EJSON.addType(this.name(), json => this.fromJSONValue(json)); - } - } - - name() { - throw new Error( - `name() needs to be implemented in ${this.constructor.name}` - ); - } - - toSimpleSchema() { - throw new Error( - `toSimpleSchema() needs to be implemented in ${this.constructor.name}` - ); - } - - description() { - return ''; - } - - fromJSONValue(json) { - return json; - } - - toPersist(obj) { - if (obj !== undefined && obj !== null) { - return this.doToPersist(obj); - } - return obj; - } - - fromPersisted(obj) { - if (obj !== undefined && obj !== null) { - return this.doFromPersisted(obj); - } - return obj; - } - - doToPersist(obj) { - throw new Error(obj); - } - - doFromPersisted(obj) { - return obj; - } - - doParseLiteral(ast) { - if (ast.kind === 'IntValue') { - const result = parseInt(ast.value, 10); - return this.doFromPersisted(result); // ast value is always in string format - } - return null; - } -} diff --git a/CustomTypeCollection.js b/CustomTypeCollection.js deleted file mode 100644 index 1990ac8..0000000 --- a/CustomTypeCollection.js +++ /dev/null @@ -1,96 +0,0 @@ -import { Mongo } from 'meteor/mongo'; -import { EJSON } from 'meteor/ejson'; - -import { getSettings } from 'meteor/quave:settings'; - -const PACKAGE_NAME = 'quave:collections'; -const settings = getSettings({ packageName: PACKAGE_NAME }); - -const { isVerbose } = settings; - -const lookForTypesAndApply = (definition, obj, consumeType) => { - if (obj) { - Object.entries(definition.fields).forEach(([key, value]) => { - if (!(key in obj)) { - return; - } - if (!EJSON._getTypes()[value.typeName]) { - return; - } - - // is not a subtype - if (!value.fields) { - if (Array.isArray(value)) { - // eslint-disable-next-line no-param-reassign - obj[key] = obj[key].map(v => consumeType(value[0].customType, v)); - } else { - // eslint-disable-next-line no-param-reassign - obj[key] = consumeType(value.customType, obj[key]); - } - } else { - const subtype = value; - const arr = Array.isArray(obj[key]) ? obj[key] : [obj[key]]; - const newArr = []; - for (let i = 0; i < arr.length; i++) { - const v = { ...arr[i] }; - newArr.push(v); - lookForTypesAndApply(subtype, v, consumeType); - } - // eslint-disable-next-line no-param-reassign - obj[key] = Array.isArray(obj[key]) ? newArr : newArr[0]; - } - }); - } - return obj; -}; - -const onPersistCollection = (definition, obj) => { - return lookForTypesAndApply(definition, obj, (parser, value) => { - return parser.toPersist(value); - }); -}; - -const onLoadFromCollection = (definition, obj) => - lookForTypesAndApply(definition, obj, (parser, value) => - parser.fromPersisted(value) - ); - -export const CustomTypeCollection = { - createTypedCollection: (name, definition, opts) => { - if (!definition) { - throw new Error(`"definition" option was not found for "${name}"`); - } - const collection = new Mongo.Collection(name, { - transform: obj => onLoadFromCollection(definition, obj), - }); - if (!collection.before) { - console.warn( - 'If you want to automatically convert your types before persisting on MongoDB please add this package https://github.com/Meteor-Community-Packages/meteor-collection-hooks' - ); - } else { - // registerHooks - collection.before.insert((_, obj) => { - onPersistCollection(definition, obj); - }); - collection.before.update((userId, doc, fields, set) => { - onPersistCollection(definition, set.$set); - }); - } - - if (opts && opts.helpers && Object.keys(opts.helpers).length) { - // :-( private access - const transformType = collection._transform; - collection._transform = null; - if (!collection.helpers) { - throw new Error( - "You need to add this package https://github.com/dburles/meteor-collection-helpers to use 'helpers'" - ); - } - collection.helpers(opts.helpers); - const transformHelpers = collection._transform; - - collection._transform = doc => transformType(transformHelpers(doc)); - } - return collection; - }, -}; diff --git a/EJSONType.js b/EJSONType.js deleted file mode 100644 index c0397f0..0000000 --- a/EJSONType.js +++ /dev/null @@ -1,12 +0,0 @@ -/* eslint-disable class-methods-use-this */ -export class EJSONType { - typeName() { - return this.constructor.name; - } - - toJSONValue() { - throw new Error( - `toJSONValue() needs to be implemented in ${this.typeName()}` - ); - } -} diff --git a/README.md b/README.md index 8dc1132..b74c0be 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ Features - Schemas -- Types - Helpers - Hooks - Composers @@ -17,7 +16,6 @@ Every application that connects to databases usually need the following features - A way to access object instances when they come from the database: helpers - Provide new methods to collections: collection - Add a few hooks to react to changes in different collections: hooks -- Map some types to avoid manual conversion all the time: types - Valid the data before persisting: schemas - Centralize behaviors: composers @@ -37,16 +35,15 @@ meteor add quave:collections ### Optional installations -To use Type or Hooks options you need to install [meteor-collection-hooks](https://github.com/Meteor-Community-Packages/meteor-collection-hooks) +To use Hooks options you need to install [meteor-collection-hooks](https://github.com/Meteor-Community-Packages/meteor-collection-hooks) ```sh meteor add matb33:collection-hooks ``` -To use Schema options you need to install [meteor-collection2](https://github.com/Meteor-Community-Packages/meteor-collection2) +To use Schema options you need to install [simpl-schema](https://www.npmjs.com/package/simpl-schema) from npmjs ```sh -meteor add aldeed:collection2 meteor npm install simpl-schema ``` @@ -295,11 +292,6 @@ export const UsersCollection = createCollection({ }); ``` -## Limitations - -- You can't apply `type` and `typeFields` when you inform an instance of a MongoDB collection, usually you only use an instance for `Meteor.users`. In this case I would recommend you to don't add fields with custom types to the users documents. - -- If you want to use your objects from the database also in the client but you don't use your whole collection in client (you are not using Mini Mongo) you need to instantiate your type also in the client, you can do this importing your type and calling `register`. This is important to register it as an EJSON type. ### License diff --git a/collections.js b/collections.js index 5882152..b507d41 100644 --- a/collections.js +++ b/collections.js @@ -3,8 +3,6 @@ import { Mongo } from 'meteor/mongo'; import { getSettings } from 'meteor/quave:settings'; -import { CustomTypeCollection } from './CustomTypeCollection'; - // to load attachSchema import './schema'; @@ -24,16 +22,7 @@ const compose = (...funcs) => arg => arg ); -const getDbCollection = ({ name, definition, helpers, instance, options }) => { - if (definition) { - if (instance) { - throw new Error("dbCollection is already defined, type can't be applied"); - } - - return CustomTypeCollection.createTypedCollection(name, definition, { - helpers, - }); - } +const getDbCollection = ({ name, helpers, instance, options }) => { let dbCollection = instance; if (!dbCollection) { dbCollection = new Mongo.Collection(name, options); @@ -50,9 +39,8 @@ const getDbCollection = ({ name, definition, helpers, instance, options }) => { }; export const createCollection = ({ - definition, - name: nameParam, - schema: schemaParam, + name, + schema, collection = {}, helpers = {}, apply = null, @@ -61,9 +49,6 @@ export const createCollection = ({ options = {}, }) => { try { - - const schema = definition ? definition.toSimpleSchema() : schemaParam; - const name = definition ? definition.pluralNameCamelCase : nameParam; if (isVerbose) { console.log(`${PACKAGE_NAME} ${name} settings`, settings); } @@ -80,7 +65,6 @@ export const createCollection = ({ } const dbCollection = getDbCollection({ name, - definition, helpers, instance, options, @@ -95,12 +79,11 @@ export const createCollection = ({ if (schema) { dbCollection.attachSchema(schema); } - dbCollection.definition = definition; return dbCollection; } catch (e) { console.error( `An error has happened when your collection${ - nameParam ? ` "${nameParam}"` : '' + name ? ` "${name}"` : '' } was being created.`, e ); diff --git a/package.js b/package.js index bc3015d..38c9a96 100644 --- a/package.js +++ b/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'quave:collections', - version: '1.1.0', + version: '2.0.0', summary: 'Utility package to create Meteor collections in a standard way', git: 'https://github.com/quavedev/collections', }); @@ -12,18 +12,20 @@ Npm.depends({ }); Package.onUse(function(api) { - api.versionsFrom('2.13.3'); + api.versionsFrom('METEOR@3.0-alpha.18'); - api.use('mongo'); + api.use([ + 'ecmascript@0.16.7||0.16.8-alpha300.18', + 'mongo@1.0.0||2.0.0||2.0.0-alpha300.17', + 'minimongo@1.9.3||2.0.0-alpha300.18', + 'ejson@1.1.3||1.1.4-alpha300.18' + ]); api.imply('mongo'); - api.use('minimongo'); - api.use('ejson'); + api.use('raix:eventemitter@1.0.0'); - api.use('ecmascript'); api.use('tmeasday:check-npm-versions@1.0.2'); + api.use('quave:settings@1.0.0'); api.mainModule('collections.js'); - - api.export('Collection2'); }); From 34685629a4892114095f9be3753207339fada116 Mon Sep 17 00:00:00 2001 From: filipenevola Date: Thu, 7 Dec 2023 16:52:03 -0400 Subject: [PATCH 04/10] Implements helpers and helpers test, also apply prettier to changed files --- collections.js | 33 +++++++++---------- helpers-test.js | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ helpers.js | 20 ++++++++++++ package.js | 11 +++++++ 4 files changed, 134 insertions(+), 17 deletions(-) create mode 100644 helpers-test.js create mode 100644 helpers.js diff --git a/collections.js b/collections.js index b507d41..929ccd5 100644 --- a/collections.js +++ b/collections.js @@ -1,12 +1,14 @@ -import { Meteor } from 'meteor/meteor'; -import { Mongo } from 'meteor/mongo'; +import { Meteor } from "meteor/meteor"; +import { Mongo } from "meteor/mongo"; -import { getSettings } from 'meteor/quave:settings'; +import { getSettings } from "meteor/quave:settings"; +// to load helpers +import "./helpers"; // to load attachSchema -import './schema'; +import "./schema"; -const PACKAGE_NAME = 'quave:collections'; +const PACKAGE_NAME = "quave:collections"; const settings = getSettings({ packageName: PACKAGE_NAME }); const { isServerOnly, isVerbose } = settings; @@ -18,8 +20,10 @@ const { isServerOnly, isVerbose } = settings; */ const compose = (...funcs) => funcs.reduce( - (a, b) => (...args) => a(b(...args)), - arg => arg + (a, b) => + (...args) => + a(b(...args)), + (arg) => arg, ); const getDbCollection = ({ name, helpers, instance, options }) => { @@ -27,12 +31,7 @@ const getDbCollection = ({ name, helpers, instance, options }) => { if (!dbCollection) { dbCollection = new Mongo.Collection(name, options); } - if (helpers && Object.keys(helpers).length) { - if (!dbCollection.helpers) { - throw new Error( - "You need to add this package https://github.com/dburles/meteor-collection-helpers to use 'helpers'" - ); - } + if (helpers) { dbCollection.helpers(helpers); } return dbCollection; @@ -55,12 +54,12 @@ export const createCollection = ({ if (!name && !instance) { throw new Error( - "The option 'name' is required, unless you are using the option 'instance' that is not your case :)." + "The option 'name' is required, unless you are using the option 'instance' that is not your case :).", ); } if (Meteor.isClient && isServerOnly) { throw new Error( - 'Collections are not allowed in the client, you can disable this changing the setting `isServerOnly`' + "Collections are not allowed in the client, you can disable this changing the setting `isServerOnly`", ); } const dbCollection = getDbCollection({ @@ -83,9 +82,9 @@ export const createCollection = ({ } catch (e) { console.error( `An error has happened when your collection${ - name ? ` "${name}"` : '' + name ? ` "${name}"` : "" } was being created.`, - e + e, ); throw e; } diff --git a/helpers-test.js b/helpers-test.js new file mode 100644 index 0000000..761fa8f --- /dev/null +++ b/helpers-test.js @@ -0,0 +1,87 @@ +import { Mongo } from "meteor/mongo"; + +const options = { _suppressSameNameError: true }; +Tinytest.addAsync("works", async function (test) { + const Books = new Mongo.Collection(`books`, options); + const Authors = new Mongo.Collection(`authors`, options); + + const author1 = await Authors.insertAsync({ + firstName: "Charles", + lastName: "Darwin", + }); + + const author2 = await Authors.insertAsync({ + firstName: "Carl", + lastName: "Sagan", + }); + + const book1 = await Books.insertAsync({ + authorId: author1, + name: "On the Origin of Species", + }); + + const book2 = await Books.insertAsync({ + authorId: author2, + name: "Contact", + }); + + Books.helpers({ + author: async function () { + return Authors.findOneAsync(this.authorId); + }, + }); + + // We should be able to apply more if we wish + Books.helpers({ + foo: "bar", + }); + + Authors.helpers({ + fullName: function () { + return `${this.firstName} ${this.lastName}`; + }, + books: function () { + return Books.find({ authorId: this._id }); + }, + }); + + const bookFirst = await Books.findOneAsync(book1); + const authorFirst = await bookFirst?.author(); + + test.equal(authorFirst?.firstName, "Charles"); + test.equal(bookFirst?.foo, "bar"); + + const bookSecond = await Books.findOneAsync(book2); + const authorSecond = await bookSecond?.author(); + test.equal(authorSecond?.fullName(), "Carl Sagan"); + + const authorThird = await Authors.findOneAsync(author1); + const booksThird = await authorThird?.books(); + test.equal(await booksThird?.countAsync(), 1); +}); + +Tinytest.addAsync( + "throw error if transform function already exists", + async function (test) { + const Author = function (doc) { + return Object.assign(this, doc); + }; + + Author.prototype.fullName = "Charles Darwin"; + + const Authors = new Mongo.Collection(`authors`, { + ...options, + transform: function (doc) { + return new Author(doc); + }, + }); + + test.throws(function () { + Authors.helpers({ + fullName: function () { + return `${this.firstName} ${this.lastName}`; + }, + }); + }); + }, +); diff --git a/helpers.js b/helpers.js new file mode 100644 index 0000000..4360a0a --- /dev/null +++ b/helpers.js @@ -0,0 +1,20 @@ +Mongo.Collection.prototype.helpers = function (helpers) { + const self = this; + + if (self._transform && !self._helpers) { + throw new Meteor.Error( + `Can't apply helpers to '${self._name}' a transform function already exists!`, + ); + } + + if (!self._helpers) { + self._helpers = function Document(doc) { + return Object.assign(this, doc); + }; + self._transform = (doc) => new self._helpers(doc); + } + + Object.keys(helpers).forEach((key) => { + self._helpers.prototype[key] = helpers[key]; + }); +}; diff --git a/package.js b/package.js index 38c9a96..408a94e 100644 --- a/package.js +++ b/package.js @@ -29,3 +29,14 @@ Package.onUse(function(api) { api.mainModule('collections.js'); }); + +Package.onTest(function(api) { + api.use([ + 'ecmascript', + 'tinytest', + 'insecure', + 'autopublish', + 'mongo']); + + api.addFiles(['helpers.js', 'helpers-test.js']); +}); From 6247463f8faedc6ae3344b060801e75edf0983fc Mon Sep 17 00:00:00 2001 From: filipenevola Date: Thu, 7 Dec 2023 16:52:57 -0400 Subject: [PATCH 05/10] Apply prettier --- collections.js | 22 +++++++++++----------- helpers-test.js | 30 +++++++++++++++--------------- helpers.js | 2 +- package.js | 13 ++++--------- 4 files changed, 31 insertions(+), 36 deletions(-) diff --git a/collections.js b/collections.js index 929ccd5..28ce4eb 100644 --- a/collections.js +++ b/collections.js @@ -1,14 +1,14 @@ -import { Meteor } from "meteor/meteor"; -import { Mongo } from "meteor/mongo"; +import { Meteor } from 'meteor/meteor'; +import { Mongo } from 'meteor/mongo'; -import { getSettings } from "meteor/quave:settings"; +import { getSettings } from 'meteor/quave:settings'; // to load helpers -import "./helpers"; +import './helpers'; // to load attachSchema -import "./schema"; +import './schema'; -const PACKAGE_NAME = "quave:collections"; +const PACKAGE_NAME = 'quave:collections'; const settings = getSettings({ packageName: PACKAGE_NAME }); const { isServerOnly, isVerbose } = settings; @@ -23,7 +23,7 @@ const compose = (...funcs) => (a, b) => (...args) => a(b(...args)), - (arg) => arg, + (arg) => arg ); const getDbCollection = ({ name, helpers, instance, options }) => { @@ -54,12 +54,12 @@ export const createCollection = ({ if (!name && !instance) { throw new Error( - "The option 'name' is required, unless you are using the option 'instance' that is not your case :).", + "The option 'name' is required, unless you are using the option 'instance' that is not your case :)." ); } if (Meteor.isClient && isServerOnly) { throw new Error( - "Collections are not allowed in the client, you can disable this changing the setting `isServerOnly`", + 'Collections are not allowed in the client, you can disable this changing the setting `isServerOnly`' ); } const dbCollection = getDbCollection({ @@ -82,9 +82,9 @@ export const createCollection = ({ } catch (e) { console.error( `An error has happened when your collection${ - name ? ` "${name}"` : "" + name ? ` "${name}"` : '' } was being created.`, - e, + e ); throw e; } diff --git a/helpers-test.js b/helpers-test.js index 761fa8f..682df33 100644 --- a/helpers-test.js +++ b/helpers-test.js @@ -1,28 +1,28 @@ -import { Mongo } from "meteor/mongo"; +import { Mongo } from 'meteor/mongo'; const options = { _suppressSameNameError: true }; -Tinytest.addAsync("works", async function (test) { +Tinytest.addAsync('works', async function (test) { const Books = new Mongo.Collection(`books`, options); const Authors = new Mongo.Collection(`authors`, options); const author1 = await Authors.insertAsync({ - firstName: "Charles", - lastName: "Darwin", + firstName: 'Charles', + lastName: 'Darwin', }); const author2 = await Authors.insertAsync({ - firstName: "Carl", - lastName: "Sagan", + firstName: 'Carl', + lastName: 'Sagan', }); const book1 = await Books.insertAsync({ authorId: author1, - name: "On the Origin of Species", + name: 'On the Origin of Species', }); const book2 = await Books.insertAsync({ authorId: author2, - name: "Contact", + name: 'Contact', }); Books.helpers({ @@ -33,7 +33,7 @@ Tinytest.addAsync("works", async function (test) { // We should be able to apply more if we wish Books.helpers({ - foo: "bar", + foo: 'bar', }); Authors.helpers({ @@ -48,12 +48,12 @@ Tinytest.addAsync("works", async function (test) { const bookFirst = await Books.findOneAsync(book1); const authorFirst = await bookFirst?.author(); - test.equal(authorFirst?.firstName, "Charles"); - test.equal(bookFirst?.foo, "bar"); + test.equal(authorFirst?.firstName, 'Charles'); + test.equal(bookFirst?.foo, 'bar'); const bookSecond = await Books.findOneAsync(book2); const authorSecond = await bookSecond?.author(); - test.equal(authorSecond?.fullName(), "Carl Sagan"); + test.equal(authorSecond?.fullName(), 'Carl Sagan'); const authorThird = await Authors.findOneAsync(author1); const booksThird = await authorThird?.books(); @@ -61,13 +61,13 @@ Tinytest.addAsync("works", async function (test) { }); Tinytest.addAsync( - "throw error if transform function already exists", + 'throw error if transform function already exists', async function (test) { const Author = function (doc) { return Object.assign(this, doc); }; - Author.prototype.fullName = "Charles Darwin"; + Author.prototype.fullName = 'Charles Darwin'; const Authors = new Mongo.Collection(`authors`, { ...options, @@ -83,5 +83,5 @@ Tinytest.addAsync( }, }); }); - }, + } ); diff --git a/helpers.js b/helpers.js index 4360a0a..a2e1d6f 100644 --- a/helpers.js +++ b/helpers.js @@ -3,7 +3,7 @@ Mongo.Collection.prototype.helpers = function (helpers) { if (self._transform && !self._helpers) { throw new Meteor.Error( - `Can't apply helpers to '${self._name}' a transform function already exists!`, + `Can't apply helpers to '${self._name}' a transform function already exists!` ); } diff --git a/package.js b/package.js index 408a94e..941514d 100644 --- a/package.js +++ b/package.js @@ -11,14 +11,14 @@ Npm.depends({ 'lodash.isobject': '3.0.2', }); -Package.onUse(function(api) { +Package.onUse(function (api) { api.versionsFrom('METEOR@3.0-alpha.18'); api.use([ 'ecmascript@0.16.7||0.16.8-alpha300.18', 'mongo@1.0.0||2.0.0||2.0.0-alpha300.17', 'minimongo@1.9.3||2.0.0-alpha300.18', - 'ejson@1.1.3||1.1.4-alpha300.18' + 'ejson@1.1.3||1.1.4-alpha300.18', ]); api.imply('mongo'); @@ -30,13 +30,8 @@ Package.onUse(function(api) { api.mainModule('collections.js'); }); -Package.onTest(function(api) { - api.use([ - 'ecmascript', - 'tinytest', - 'insecure', - 'autopublish', - 'mongo']); +Package.onTest(function (api) { + api.use(['ecmascript', 'tinytest', 'insecure', 'autopublish', 'mongo']); api.addFiles(['helpers.js', 'helpers-test.js']); }); From 1ad1cdce171214b53b30c16f971f7e5d00a7deb6 Mon Sep 17 00:00:00 2001 From: filipenevola Date: Thu, 7 Dec 2023 17:18:45 -0400 Subject: [PATCH 06/10] Test zodern mtest --- .github/workflows/test.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..aaee7ad --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,31 @@ +# the test suite runs the tests (headless, server+client) for multiple Meteor releases +name: Test suite +on: + push: + branches: + - meteor-3 + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + meteorRelease: + - '--release 3.0-alpha.19' + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: '12.x' + + - name: Install Dependencies + run: | + curl https://install.meteor.com | /bin/sh + npm i -g @zodern/mtest + - name: Run Tests + run: | + mtest --package ./ --once ${{ matrix.meteorRelease }} From 9701779f904750fe086de9e61eac6c5dc83c6f92 Mon Sep 17 00:00:00 2001 From: filipenevola Date: Thu, 7 Dec 2023 17:18:54 -0400 Subject: [PATCH 07/10] Test zodern mtest --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index aaee7ad..52a3f44 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,7 +20,7 @@ jobs: - name: Install Node.js uses: actions/setup-node@v4 with: - node-version: '12.x' + node-version: '20.x' - name: Install Dependencies run: | From 5a2aeffff3a36404b6ac5e9c55773d307991e67f Mon Sep 17 00:00:00 2001 From: filipenevola Date: Fri, 8 Dec 2023 11:40:05 -0400 Subject: [PATCH 08/10] Prettier and eslint --- .nvmrc | 1 + .prettierignore | 1 + package-lock.json | 5631 ++++++++++++++++++++++++++++++++++++++++++++ package.json | 30 + prettier.config.js | 1 + 5 files changed, 5664 insertions(+) create mode 100644 .nvmrc create mode 100644 .prettierignore create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 prettier.config.js diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..9a2a0e2 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v20 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..a210498 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +.meteor diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..fa19f40 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5631 @@ +{ + "name": "quave-collections", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "quave-collections", + "version": "1.0.0", + "devDependencies": { + "@quave/eslint-config-quave": "^2.0.0" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.5.tgz", + "integrity": "sha512-Cwc2XjUrG4ilcfOw4wBAK+enbdgwAcAJCfGUItPBKR7Mjw4aEfAFYrLxeRp4jWgtNIKn3n2AlBOfwwafl+42/g==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.5", + "@babel/parser": "^7.23.5", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.23.3.tgz", + "integrity": "sha512-9bTuNlyx7oSstodm1cR1bECj4fkiknsDa1YniISkJemMY3DGhJNYBECbe6QD/q54mp2J8VO66jW3/7uP//iFCw==", + "dev": true, + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.5.tgz", + "integrity": "sha512-BPssCHrBD+0YrxviOa3QzpqwhNIXKEtOa2jQrm4FlmkC2apYgRnQcmPWiGZDlGxiNtltnUFolMe8497Esry+jA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "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.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "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.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "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-simple-access": { + "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.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "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.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.5.tgz", + "integrity": "sha512-oO7us8FzTEsG3U6ag9MfdF1iA/7Z6dz+MtFhifZk8C8o453rGJFFWUP1t+ULM9TUIAzC9uxXEiXjOiVMyd7QPg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.5", + "@babel/types": "^7.23.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.5.tgz", + "integrity": "sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "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-react-display-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.23.3.tgz", + "integrity": "sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw==", + "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-react-jsx": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz", + "integrity": "sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/types": "^7.23.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz", + "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==", + "dev": true, + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.23.3.tgz", + "integrity": "sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^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/preset-react": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.23.3.tgz", + "integrity": "sha512-tbkHOS9axH6Ysf2OUEqoSZ6T3Fa2SrNH6WTWSPBboxKzdxNc9qOICeLXkNG0ZEwbQ1HY8liwOce4aN/Ceyuq6w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-transform-react-display-name": "^7.23.3", + "@babel/plugin-transform-react-jsx": "^7.22.15", + "@babel/plugin-transform-react-jsx-development": "^7.22.5", + "@babel/plugin-transform-react-pure-annotations": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz", + "integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.5.tgz", + "integrity": "sha512-czx7Xy5a6sapWWRx61m1Ke1Ra4vczu1mCTtJam5zRTBOonfdJ+S/B6HYmGYu3fJtr8GGET3si6IhgWVBhJ/m8w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.5", + "@babel/types": "^7.23.5", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz", + "integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", + "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "dev": true + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@meteorjs/eslint-config-meteor": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@meteorjs/eslint-config-meteor/-/eslint-config-meteor-1.0.5.tgz", + "integrity": "sha512-iJBdOtsaiYuswDSGctK95ZYaYIPxwnIlxGF07jDxeM5sxuuFwKTXoopahmDBFdBt48rwmSIFUcu/zTMB5yzd5w==", + "dev": true, + "peerDependencies": { + "babel-eslint": ">= 7", + "eslint": ">= 3", + "eslint-config-airbnb": ">= 13", + "eslint-import-resolver-meteor": ">= 0.3.0", + "eslint-plugin-import": ">= 2", + "eslint-plugin-jsx-a11y": ">= 2", + "eslint-plugin-meteor": ">= 4", + "eslint-plugin-react": ">= 6" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@quave/eslint-config-quave": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@quave/eslint-config-quave/-/eslint-config-quave-2.0.0.tgz", + "integrity": "sha512-G16I540GqAERq2zAV751Yp6F4VxpLYgwriQm61odIEWsOsWWDEyy6dwsBYrHsO0OCbyRZzCVOwKLwvL0XdyOWw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.5", + "@babel/eslint-parser": "^7.23.3", + "@babel/preset-react": "^7.23.3", + "@meteorjs/eslint-config-meteor": "^1.0.5", + "eslint": "^8.55.0", + "eslint-config-airbnb": "^19.0.4", + "eslint-config-prettier": "^9.1.0", + "eslint-import-resolver-meteor": "^0.4.0", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-jest": "^27.6.0", + "eslint-plugin-jsx-a11y": "^6.8.0", + "eslint-plugin-meteor": "^7.3.0", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "husky": "^4.3.8", + "lint-staged": "^15.2.0", + "prettier": "^3.1.0", + "prettier-eslint": "^16.1.2", + "prettier-plugin-tailwindcss": "^0.4.1" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.2.tgz", + "integrity": "sha512-MUkcC+7Wt/QOGeVlM8aGGJZy1XV5YKjTpq9jK6r6/iLsGXhBVaGP5N0UYvFsu9BFlSpwY9kMretzdBH01rkRXg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.13.2", + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/typescript-estree": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz", + "integrity": "sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.2.tgz", + "integrity": "sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.2.tgz", + "integrity": "sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/visitor-keys": "6.13.2", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.2.tgz", + "integrity": "sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.13.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@typescript-eslint/parser/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/@typescript-eslint/parser/node_modules/semver": { + "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" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/parser/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/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/typescript-estree/node_modules/semver": { + "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" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/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/@typescript-eslint/utils/node_modules/semver": { + "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" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/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/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "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", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", + "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", + "dev": true, + "dependencies": { + "type-fest": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "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-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", + "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz", + "integrity": "sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "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/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true + }, + "node_modules/asynciterator.prototype": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", + "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + } + }, + "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.7.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", + "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", + "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "eslint": ">= 4.12.1" + } + }, + "node_modules/babel-eslint/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001566", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001566.tgz", + "integrity": "sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/compare-versions": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/confusing-browser-globals": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.608", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.608.tgz", + "integrity": "sha512-J2f/3iIIm3Mo0npneITZ2UPe4B1bg8fTNrFjD8715F/k1BvbviRuqYGkET1PgprrczXYTHFvotbBOmUp6KE0uA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "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.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "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.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz", + "integrity": "sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==", + "dev": true, + "dependencies": { + "asynciterator.prototype": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.1", + "es-set-tostringtag": "^2.0.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.0.1" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", + "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.55.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "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.2.2", + "eslint-visitor-keys": "^3.4.3", + "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.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "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.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-airbnb": { + "version": "19.0.4", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", + "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", + "dev": true, + "dependencies": { + "eslint-config-airbnb-base": "^15.0.0", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5" + }, + "engines": { + "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.28.0", + "eslint-plugin-react-hooks": "^4.3.0" + } + }, + "node_modules/eslint-config-airbnb-base": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", + "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "dev": true, + "dependencies": { + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", + "object.entries": "^1.1.5", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "peerDependencies": { + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.2" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-meteor": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-meteor/-/eslint-import-resolver-meteor-0.4.0.tgz", + "integrity": "sha512-BSqvgt6QZvk9EGhDGnM4azgbxyBD8b0y6FYA52WFzpWpHcZV9ys8PxM33bx8dlCy3HyopRLLsMUnlhTpZzsZmQ==", + "dev": true, + "dependencies": { + "object-assign": "^4.0.1", + "resolve": "^1.1.6" + }, + "peerDependencies": { + "eslint-plugin-import": ">=1.4.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/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-module-utils": { + "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" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/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": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz", + "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.14.2" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "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", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-jest": { + "version": "27.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.6.0.tgz", + "integrity": "sha512-MTlusnnDMChbElsszJvrwD1dN3x6nZl//s4JD23BxB6MgR66TZlL064su24xEIS3VACfAoHV1vgyMgPw8nkdng==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^5.10.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0", + "eslint": "^7.0.0 || ^8.0.0", + "jest": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", + "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.23.2", + "aria-query": "^5.3.0", + "array-includes": "^3.1.7", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "=4.7.0", + "axobject-query": "^3.2.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.15", + "hasown": "^2.0.0", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-meteor": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-meteor/-/eslint-plugin-meteor-7.3.0.tgz", + "integrity": "sha512-z+O+tZQDo9tMw4drgcDSFLpMglJCtMYA1BGX5DA2uUldQw+FPewHerZFLIQVJvSgWpQ2RC+SKaI033RhmU0d1g==", + "dev": true, + "dependencies": { + "invariant": "2.2.4" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": ">= 3.7.0" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.33.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", + "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.12", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.8" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "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" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "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", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "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.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "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" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "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/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 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", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "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" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-versions": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz", + "integrity": "sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==", + "dev": true, + "dependencies": { + "semver-regex": "^3.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "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/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "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/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": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "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" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "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==", + "dev": true, + "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", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/husky": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.8.tgz", + "integrity": "sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "compare-versions": "^3.6.0", + "cosmiconfig": "^7.0.0", + "find-versions": "^4.0.0", + "opencollective-postinstall": "^2.0.2", + "pkg-dir": "^5.0.0", + "please-upgrade-node": "^3.2.0", + "slash": "^3.0.0", + "which-pm-runs": "^1.0.0" + }, + "bin": { + "husky-run": "bin/run.js", + "husky-upgrade": "lib/upgrader/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/husky" + } + }, + "node_modules/husky/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/husky/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/husky/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/husky/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/husky/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/husky/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "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-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "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", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "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-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "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-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "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", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "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.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/lint-staged": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.0.tgz", + "integrity": "sha512-TFZzUEV00f+2YLaVPWBWGAMq7So6yQx+GG8YRMDeOEIf95Zn5RyiLMsEiX4KTNl9vq/w+NqRJkLA1kPIo15ufQ==", + "dev": true, + "dependencies": { + "chalk": "5.3.0", + "commander": "11.1.0", + "debug": "4.3.4", + "execa": "8.0.1", + "lilconfig": "3.0.0", + "listr2": "8.0.0", + "micromatch": "4.0.5", + "pidtree": "0.6.0", + "string-argv": "0.3.2", + "yaml": "2.3.4" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/listr2": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.0.tgz", + "integrity": "sha512-u8cusxAcyqAiQ2RhYvV7kRKNLgUvtObIbhOX2NCXqvp1UU32xIg5CT22ykS2TPKJXZWJwtK3IKLiqAGlGNE+Zg==", + "dev": true, + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.0.0", + "rfdc": "^1.3.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-update": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", + "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", + "dev": true, + "dependencies": { + "ansi-escapes": "^6.2.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^7.0.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/loglevel": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.1.tgz", + "integrity": "sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, + "node_modules/loglevel-colored-level-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/loglevel-colored-level-prefix/-/loglevel-colored-level-prefix-1.0.0.tgz", + "integrity": "sha512-u45Wcxxc+SdAlh4yeF/uKlC1SPUPCy0gullSNKXod5I4bmifzk+Q4lSLExNEVn19tGaJipbZ4V4jbFn79/6mVA==", + "dev": true, + "dependencies": { + "chalk": "^1.1.3", + "loglevel": "^1.4.1" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "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": { + "yallist": "^3.0.2" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": 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/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/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", + "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", + "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1" + } + }, + "node_modules/object.hasown": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", + "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opencollective-postinstall": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", + "dev": true, + "bin": { + "opencollective-postinstall": "index.js" + } + }, + "node_modules/optionator": { + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "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", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pkg-dir": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "dev": true, + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "dev": true, + "dependencies": { + "semver-compare": "^1.0.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", + "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-eslint": { + "version": "16.1.2", + "resolved": "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-16.1.2.tgz", + "integrity": "sha512-mGFGZQbAh11FSnwW3H1zngzQYR2QMmHO8vdfgnAuzOFhnDeUZHYtwpqQvOMOMT0k818Dr1X+J4a/sVE0r34RKQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/parser": "^6.7.5", + "common-tags": "^1.4.0", + "dlv": "^1.1.0", + "eslint": "^8.7.0", + "indent-string": "^4.0.0", + "lodash.merge": "^4.6.0", + "loglevel-colored-level-prefix": "^1.0.0", + "prettier": "^3.0.1", + "pretty-format": "^29.7.0", + "require-relative": "^0.8.7", + "typescript": "^5.2.2", + "vue-eslint-parser": "^9.1.0" + }, + "engines": { + "node": ">=16.10.0" + } + }, + "node_modules/prettier-plugin-tailwindcss": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.4.1.tgz", + "integrity": "sha512-hwn2EiJmv8M+AW4YDkbjJ6HlZCTzLyz1QlySn9sMuKV/Px0fjwldlB7tol8GzdgqtkdPtzT3iJ4UzdnYXP25Ag==", + "dev": true, + "engines": { + "node": ">=12.17.0" + }, + "peerDependencies": { + "@ianvs/prettier-plugin-sort-imports": "*", + "@prettier/plugin-pug": "*", + "@shopify/prettier-plugin-liquid": "*", + "@shufo/prettier-plugin-blade": "*", + "@trivago/prettier-plugin-sort-imports": "*", + "prettier": "^2.2 || ^3.0", + "prettier-plugin-astro": "*", + "prettier-plugin-css-order": "*", + "prettier-plugin-import-sort": "*", + "prettier-plugin-jsdoc": "*", + "prettier-plugin-marko": "*", + "prettier-plugin-organize-attributes": "*", + "prettier-plugin-organize-imports": "*", + "prettier-plugin-style-order": "*", + "prettier-plugin-svelte": "*", + "prettier-plugin-twig-melody": "*" + }, + "peerDependenciesMeta": { + "@ianvs/prettier-plugin-sort-imports": { + "optional": true + }, + "@prettier/plugin-pug": { + "optional": true + }, + "@shopify/prettier-plugin-liquid": { + "optional": true + }, + "@shufo/prettier-plugin-blade": { + "optional": true + }, + "@trivago/prettier-plugin-sort-imports": { + "optional": true + }, + "prettier-plugin-astro": { + "optional": true + }, + "prettier-plugin-css-order": { + "optional": true + }, + "prettier-plugin-import-sort": { + "optional": true + }, + "prettier-plugin-jsdoc": { + "optional": true + }, + "prettier-plugin-marko": { + "optional": true + }, + "prettier-plugin-organize-attributes": { + "optional": true + }, + "prettier-plugin-organize-imports": { + "optional": true + }, + "prettier-plugin-style-order": { + "optional": true + }, + "prettier-plugin-svelte": { + "optional": true + }, + "prettier-plugin-twig-melody": { + "optional": true + } + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "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/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", + "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "dev": true + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha512-AKGr4qvHiryxRb19m3PsLRGuKVAbJLUD7E6eOaHkfKhwc+vSgVOCY5xNvm9EkolBKTOf0GrQAZKLimOCz81Khg==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "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": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true + }, + "node_modules/semver-regex": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.4.tgz", + "integrity": "sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.0.0.tgz", + "integrity": "sha512-GPQHj7row82Hjo9hKZieKcHIhaAIKOJvFSIZXuCU9OASVZrMNUaZuz++SPVrBjnLsnk4k+z9f2EIypgxf2vNFw==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", + "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "regexp.prototype.flags": "^1.5.0", + "set-function-name": "^2.0.0", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tsconfig-paths": { + "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.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "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" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vue-eslint-parser": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.2.tgz", + "integrity": "sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-scope": { + "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", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/vue-eslint-parser/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/vue-eslint-parser/node_modules/semver": { + "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" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vue-eslint-parser/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/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-pm-runs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", + "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..7249f16 --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "quave-collections", + "version": "1.0.0", + "scripts": { + "quave-eslint": "eslint . --fix", + "quave-prettier": "prettier --write \"**/*.js\"", + "quave-check": "npm run quave-eslint && npm run quave-prettier" + }, + "eslintConfig": { + "extends": [ + "@quave/quave" + ] + }, + "husky": { + "hooks": { + "pre-commit": "meteor npm test && lint-staged", + "post-commit": "git update-index --again" + } + }, + "lint-staged": { + "*.js": [ + "eslint --fix", + "prettier --write", + "git add" + ] + }, + "devDependencies": { + "@quave/eslint-config-quave": "^2.0.0" + } +} diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 0000000..3a15538 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1 @@ +module.exports = require('@quave/eslint-config-quave/prettier.config'); From f10dc307b5070251770179009776b24bf5a4ed88 Mon Sep 17 00:00:00 2001 From: filipenevola Date: Fri, 8 Dec 2023 11:42:45 -0400 Subject: [PATCH 09/10] Bringing tests from here https://github.com/Meteor-Community-Packages/meteor-collection2/tree/master/tests - Skipped eslint checks - We still need to run the client tests but server is running fine (we removed a few as they were trying to test dummy stuff (like default options) but modifying the collection2 class object (our goal is to run this test in our repo https://github.com/Meteor-Community-Packages/meteor-collection2/actions/runs/6398509589/job/17368820251) --- schema-tests/.meteor/.finished-upgraders | 19 + schema-tests/.meteor/.gitignore | 1 + schema-tests/.meteor/.id | 7 + schema-tests/.meteor/packages | 22 + schema-tests/.meteor/platforms | 2 + schema-tests/.meteor/release | 1 + schema-tests/.meteor/versions | 87 + schema-tests/.nvmrc | 1 + schema-tests/_main.tests.js | 1 + schema-tests/autoValue.tests.js | 91 + schema-tests/books.tests.js | 429 +++++ schema-tests/clean.tests.js | 206 +++ schema-tests/collection2.tests.js | 693 ++++++++ schema-tests/context.tests.js | 105 ++ schema-tests/default.tests.js | 43 + schema-tests/multi.tests.js | 418 +++++ schema-tests/package-lock.json | 1934 ++++++++++++++++++++++ schema-tests/package.json | 20 + 18 files changed, 4080 insertions(+) create mode 100644 schema-tests/.meteor/.finished-upgraders create mode 100644 schema-tests/.meteor/.gitignore create mode 100644 schema-tests/.meteor/.id create mode 100644 schema-tests/.meteor/packages create mode 100644 schema-tests/.meteor/platforms create mode 100644 schema-tests/.meteor/release create mode 100644 schema-tests/.meteor/versions create mode 100644 schema-tests/.nvmrc create mode 100644 schema-tests/_main.tests.js create mode 100644 schema-tests/autoValue.tests.js create mode 100644 schema-tests/books.tests.js create mode 100644 schema-tests/clean.tests.js create mode 100644 schema-tests/collection2.tests.js create mode 100644 schema-tests/context.tests.js create mode 100644 schema-tests/default.tests.js create mode 100644 schema-tests/multi.tests.js create mode 100644 schema-tests/package-lock.json create mode 100644 schema-tests/package.json diff --git a/schema-tests/.meteor/.finished-upgraders b/schema-tests/.meteor/.finished-upgraders new file mode 100644 index 0000000..c07b6ff --- /dev/null +++ b/schema-tests/.meteor/.finished-upgraders @@ -0,0 +1,19 @@ +# This file contains information which helps Meteor properly upgrade your +# app when you run 'meteor update'. You should check it into version control +# with your project. + +notices-for-0.9.0 +notices-for-0.9.1 +0.9.4-platform-file +notices-for-facebook-graph-api-2 +1.2.0-standard-minifiers-package +1.2.0-meteor-platform-split +1.2.0-cordova-changes +1.2.0-breaking-changes +1.3.0-split-minifiers-package +1.4.0-remove-old-dev-bundle-link +1.4.1-add-shell-server-package +1.4.3-split-account-service-packages +1.5-add-dynamic-import-package +1.7-split-underscore-from-meteor-base +1.8.3-split-jquery-from-blaze diff --git a/schema-tests/.meteor/.gitignore b/schema-tests/.meteor/.gitignore new file mode 100644 index 0000000..4083037 --- /dev/null +++ b/schema-tests/.meteor/.gitignore @@ -0,0 +1 @@ +local diff --git a/schema-tests/.meteor/.id b/schema-tests/.meteor/.id new file mode 100644 index 0000000..d4ab15b --- /dev/null +++ b/schema-tests/.meteor/.id @@ -0,0 +1,7 @@ +# This file contains a token that is unique to your project. +# Check it into your repository along with the rest of this directory. +# It can be used for purposes such as: +# - ensuring you don't accidentally deploy one app on top of another +# - providing package authors with aggregated statistics + +1nydo23oqnttp22v79u diff --git a/schema-tests/.meteor/packages b/schema-tests/.meteor/packages new file mode 100644 index 0000000..3f0b125 --- /dev/null +++ b/schema-tests/.meteor/packages @@ -0,0 +1,22 @@ +meteor-base +mobile-experience +mongo +blaze-html-templates +reactive-var +jquery +tracker + +standard-minifier-css +standard-minifier-js +es5-shim +ecmascript +shell-server + +autopublish +insecure + +dynamic-import +# Specific sub dep version to get this version of puppeteer https://github.com/Meteor-Community-Packages/meteor-browser-tests/commit/00ced01ead0e8037a8b95f69f7c83086176d3716 +meteortesting:browser-tests@=1.5.3 +meteortesting:mocha +quave:collections diff --git a/schema-tests/.meteor/platforms b/schema-tests/.meteor/platforms new file mode 100644 index 0000000..efeba1b --- /dev/null +++ b/schema-tests/.meteor/platforms @@ -0,0 +1,2 @@ +server +browser diff --git a/schema-tests/.meteor/release b/schema-tests/.meteor/release new file mode 100644 index 0000000..6641d04 --- /dev/null +++ b/schema-tests/.meteor/release @@ -0,0 +1 @@ +METEOR@2.13.3 diff --git a/schema-tests/.meteor/versions b/schema-tests/.meteor/versions new file mode 100644 index 0000000..8700fa3 --- /dev/null +++ b/schema-tests/.meteor/versions @@ -0,0 +1,87 @@ +allow-deny@1.1.1 +autopublish@1.0.7 +autoupdate@1.8.0 +babel-compiler@7.10.4 +babel-runtime@1.5.1 +base64@1.0.12 +binary-heap@1.0.11 +blaze@2.5.0 +blaze-html-templates@1.2.0 +blaze-tools@1.1.1 +boilerplate-generator@1.7.1 +caching-compiler@1.2.2 +caching-html-compiler@1.2.0 +callback-hook@1.5.1 +check@1.3.2 +ddp@1.4.1 +ddp-client@2.6.1 +ddp-common@1.4.0 +ddp-server@2.6.2 +diff-sequence@1.1.2 +dynamic-import@0.7.3 +ecmascript@0.16.7 +ecmascript-runtime@0.8.1 +ecmascript-runtime-client@0.12.1 +ecmascript-runtime-server@0.11.0 +ejson@1.1.3 +es5-shim@4.8.0 +fetch@0.1.3 +geojson-utils@1.0.11 +hot-code-push@1.0.4 +html-tools@1.1.1 +htmljs@1.1.0 +http@1.4.4 +id-map@1.1.1 +insecure@1.0.7 +inter-process-messaging@0.1.1 +jquery@3.0.0 +launch-screen@1.3.0 +logging@1.3.2 +meteor@1.11.3 +meteor-base@1.5.1 +meteortesting:browser-tests@1.5.3 +meteortesting:mocha@2.0.1 +meteortesting:mocha-core@8.1.2 +minifier-css@1.6.4 +minifier-js@2.7.5 +minimongo@1.9.3 +mobile-experience@1.1.0 +mobile-status-bar@1.1.0 +modern-browsers@0.1.9 +modules@0.19.0 +modules-runtime@0.13.1 +mongo@1.16.7 +mongo-decimal@0.1.3 +mongo-dev-server@1.1.0 +mongo-id@1.0.8 +npm-mongo@4.16.0 +observe-sequence@1.0.16 +ordered-dict@1.1.0 +promise@0.12.2 +quave:collections@2.0.0 +quave:settings@1.0.0 +raix:eventemitter@1.0.0 +random@1.2.1 +react-fast-refresh@0.2.7 +reactive-var@1.0.12 +reload@1.3.1 +retry@1.1.0 +routepolicy@1.1.1 +shell-server@0.5.0 +socket-stream-client@0.5.1 +spacebars@1.2.0 +spacebars-compiler@1.2.1 +standard-minifier-css@1.9.2 +standard-minifier-js@2.8.1 +templating@1.4.1 +templating-compiler@1.4.1 +templating-runtime@1.5.0 +templating-tools@1.2.0 +tmeasday:check-npm-versions@1.0.2 +tracker@1.3.2 +typescript@4.9.4 +ui@1.0.13 +underscore@1.0.13 +url@1.3.2 +webapp@1.13.5 +webapp-hashing@1.1.1 diff --git a/schema-tests/.nvmrc b/schema-tests/.nvmrc new file mode 100644 index 0000000..9a2a0e2 --- /dev/null +++ b/schema-tests/.nvmrc @@ -0,0 +1 @@ +v20 diff --git a/schema-tests/_main.tests.js b/schema-tests/_main.tests.js new file mode 100644 index 0000000..b012711 --- /dev/null +++ b/schema-tests/_main.tests.js @@ -0,0 +1 @@ +import 'babel-polyfill'; diff --git a/schema-tests/autoValue.tests.js b/schema-tests/autoValue.tests.js new file mode 100644 index 0000000..ca8ff95 --- /dev/null +++ b/schema-tests/autoValue.tests.js @@ -0,0 +1,91 @@ +import { Meteor } from 'meteor/meteor'; +import expect from 'expect'; +import { Mongo } from 'meteor/mongo'; +import SimpleSchema from 'simpl-schema'; + +const collection = new Mongo.Collection('autoValueTestCollection'); +const localCollection = new Mongo.Collection('autoValueTestLocalCollection', { connection: null }); + +[collection, localCollection].forEach((c) => { + c.attachSchema(new SimpleSchema({ + clientAV: { + type: SimpleSchema.Integer, + optional: true, + autoValue() { + if (Meteor.isServer) return; + return (this.value || 0) + 1; + } + }, + serverAV: { + type: SimpleSchema.Integer, + optional: true, + autoValue() { + if (Meteor.isClient) return; + return (this.value || 0) + 1; + } + } + })); +}); + +if (Meteor.isClient) { + describe('autoValue on client', function () { + it('for client insert, autoValues should be added on the server only (added to only a validated clone of the doc on client)', function (done) { + collection.insert({}, (error, id) => { + const doc = collection.findOne(id); + expect(doc.clientAV).toBe(undefined); + expect(doc.serverAV).toBe(1); + done(); + }); + }); + + it('runs function once for LocalCollection', function (done) { + localCollection.insert({}, (error, id) => { + const doc = localCollection.findOne(id); + expect(doc.clientAV).toBe(1); + expect(doc.serverAV).toBe(undefined); + done(); + }); + }); + + it('with getAutoValues false, does not run function for LocalCollection', function (done) { + localCollection.insert({}, { getAutoValues: false }, (error, id) => { + const doc = localCollection.findOne(id); + expect(doc.clientAV).toBe(undefined); + expect(doc.serverAV).toBe(undefined); + done(); + }); + }); + }); +} + +if (Meteor.isServer) { + describe('autoValue on server', function () { + it('runs function once', function () { + const id = collection.insert({}); + const doc = collection.findOne(id); + expect(doc.clientAV).toBe(undefined); + expect(doc.serverAV).toBe(1); + }); + + it('with getAutoValues false, does not run function', function () { + const id = collection.insert({}, { getAutoValues: false }); + const doc = collection.findOne(id); + expect(doc.clientAV).toBe(undefined); + expect(doc.serverAV).toBe(undefined); + }); + + it('runs function once for LocalCollection', function () { + const id = localCollection.insert({}); + const doc = localCollection.findOne(id); + expect(doc.clientAV).toBe(undefined); + expect(doc.serverAV).toBe(1); + }); + + it('with getAutoValues false, does not run function for LocalCollection', function () { + const id = localCollection.insert({}, { getAutoValues: false }); + const doc = localCollection.findOne(id); + expect(doc.clientAV).toBe(undefined); + expect(doc.serverAV).toBe(undefined); + }); + }); +} diff --git a/schema-tests/books.tests.js b/schema-tests/books.tests.js new file mode 100644 index 0000000..2a9cf5e --- /dev/null +++ b/schema-tests/books.tests.js @@ -0,0 +1,429 @@ +import expect from 'expect'; +import { Mongo } from 'meteor/mongo'; +import SimpleSchema from 'simpl-schema'; + +const booksSchema = new SimpleSchema({ + title: { + type: String, + label: "Title", + max: 200, + }, + author: { + type: String, + label: "Author" + }, + copies: { + type: SimpleSchema.Integer, + label: "Number of copies", + min: 0 + }, + lastCheckedOut: { + type: Date, + label: "Last date this book was checked out", + optional: true + }, + summary: { + type: String, + label: "Brief summary", + optional: true, + max: 1000 + }, + isbn: { + type: String, + label: "ISBN", + optional: true, + }, + field1: { + type: String, + optional: true + }, + field2: { + type: String, + optional: true + }, + createdAt: { + type: Date, + optional: true, + }, + updatedAt: { + type: Date, + optional: true, + } +}); + +const books = new Mongo.Collection('books'); +books.attachSchema(booksSchema); + +const upsertTest = new Mongo.Collection('upsertTest'); +upsertTest.attachSchema(new SimpleSchema({ + _id: {type: String}, + foo: {type: Number} +})); + +export default function addBooksTests() { + describe('insert', function () { + beforeEach(function () { + books.find({}).forEach(book => { + books.remove(book._id); + }); + }); + + it('required', function (done) { + let callCount = 0; + const maybeNext = function() { + callCount++; + if (callCount >= 2) { + done(); + } + }; + + const id = books.insert({ + title: "Ulysses", + author: "James Joyce" + }, (error, result) => { + //The insert will fail, error will be set, + expect(!!error).toBe(true); + //and result will be false because "copies" is required. + expect(result).toBe(false); + //The list of errors is available by calling books.simpleSchema().namedContext().validationErrors() + const validationErrors = books.simpleSchema().namedContext().validationErrors(); + expect(validationErrors.length).toBe(1); + + const key = validationErrors[0] || {}; + expect(key.name).toBe('copies'); + expect(key.type).toBe('required'); + maybeNext(); + }); + + expect(typeof id).toBe('string'); + maybeNext(); + }); + + if (Meteor.isServer) { + it('no validation when calling underlying _collection on the server', function (done) { + books._collection.insert({ + title: "Ulysses", + author: "James Joyce", + copies: 1, + updatedAt: new Date() + }, (error) => { + expect(error).toBe(null); + done(); + }); + }); + } + }); + + if (Meteor.isServer) { + describe('upsert', function () { + function getCallback(done) { + return (error, result) => { + expect(!!error).toBe(false); + expect(result.numberAffected).toBe(1); + + const validationErrors = books.simpleSchema().namedContext().validationErrors(); + expect(validationErrors.length).toBe(0); + + done(); + }; + } + + function getUpdateCallback(done) { + return (error, result) => { + if (error) console.error(error); + expect(!!error).toBe(false); + expect(result).toBe(1); + + const validationErrors = books.simpleSchema().namedContext().validationErrors(); + expect(validationErrors.length).toBe(0); + + done(); + }; + } + + function getErrorCallback(done) { + return (error, result) => { + expect(!!error).toBe(true); + expect(!!result).toBe(false); + + const validationErrors = books.simpleSchema().namedContext().validationErrors(); + expect(validationErrors.length).toBe(1); + + done(); + }; + } + + it('valid', function (done) { + books.upsert({ + title: "Ulysses", + author: "James Joyce" + }, { + $set: { + title: "Ulysses", + author: "James Joyce", + copies: 1 + } + }, getCallback(done)); + }); + + it('upsert as update should update entity by _id - valid', function (done) { + const id = books.insert({title: 'new', author: 'author new', copies: 2}); + + books.upsert({ + _id: id + }, { + $set: { + title: "Ulysses", + author: "James Joyce", + copies: 1 + } + }, getCallback(done)); + }); + + it('upsert as update - valid', function (done) { + books.update({ + title: "Ulysses", + author: "James Joyce" + }, { + $set: { + title: "Ulysses", + author: "James Joyce", + copies: 1 + } + }, { + upsert: true + }, getUpdateCallback(done)); + }); + + it('upsert as update with $and', function (done) { + books.update({ + $and: [ + { title: "Ulysses" }, + { author: "James Joyce" }, + ], + }, { + $set: { + title: "Ulysses", + author: "James Joyce", + copies: 1 + } + }, { + upsert: true + }, getUpdateCallback(done)); + }); + + it('upsert - invalid', function (done) { + books.upsert({ + title: "Ulysses", + author: "James Joyce" + }, { + $set: { + copies: -1 + } + }, getErrorCallback(done)); + }); + + it('upsert as update - invalid', function (done) { + books.update({ + title: "Ulysses", + author: "James Joyce" + }, { + $set: { + copies: -1 + } + }, { + upsert: true + }, getErrorCallback(done)); + }); + + it('upsert - valid with selector', function (done) { + books.upsert({ + title: "Ulysses", + author: "James Joyce" + }, { + $set: { + copies: 1 + } + }, getCallback(done)); + }); + + it('upsert as update - valid with selector', function (done) { + books.update({ + title: "Ulysses", + author: "James Joyce" + }, { + $set: { + copies: 1 + } + }, { + upsert: true + }, getUpdateCallback(done)); + }); + }); + } + + it('validate false', function (done) { + let title; + if (Meteor.isClient) { + title = "Validate False Client"; + } else { + title = "Validate False Server"; + } + + books.insert({ + title: title, + author: "James Joyce" + }, { + validate: false, + validationContext: "validateFalse" + }, (error, result) => { + let insertedBook; + const validationErrors = books.simpleSchema().namedContext("validateFalse").validationErrors(); + + if (Meteor.isClient) { + // When validate: false on the client, we should still get a validation error and validationErrors back from the server + expect(!!error).toBe(true); + // There should be an `invalidKeys` property on the error, too + expect(error.invalidKeys.length).toBe(1); + expect(!!result).toBe(false); + expect(validationErrors.length).toBe(1); + + insertedBook = books.findOne({ title: title }); + expect(!!insertedBook).toBe(false); + } else { + // When validate: false on the server, validation should be skipped + expect(!!error).toBe(false); + expect(!!result).toBe(true); + expect(validationErrors.length).toBe(0); + + insertedBook = books.findOne({ title: title }); + expect(!!insertedBook).toBe(true); + } + + // do a good one to set up update test + books.insert({ + title: title + " 2", + author: "James Joyce", + copies: 1 + }, { + validate: false, + validationContext: "validateFalse2" + }, (error, newId) => { + const validationErrors = books.simpleSchema().namedContext("validateFalse2").validationErrors(); + + expect(!!error).toBe(false); + expect(!!newId).toBe(true); + expect(validationErrors.length).toBe(0); + + const insertedBook = books.findOne({ title: title + " 2" }); + expect(!!insertedBook).toBe(true); + + books.update({ + _id: newId + }, { + $set: { + copies: "Yes Please" + } + }, { + validate: false, + validationContext: "validateFalse3" + }, (error, result) => { + let updatedBook; + const validationErrors = books.simpleSchema().namedContext("validateFalse3").validationErrors(); + + if (Meteor.isClient) { + // When validate: false on the client, we should still get a validation error and invalidKeys from the server + expect(!!error).toBe(true); + // There should be an `invalidKeys` property on the error, too + expect(error.invalidKeys.length).toBe(1); + expect(!!result).toBe(false); + expect(validationErrors.length).toBe(1); + + updatedBook = books.findOne(newId); + expect(!!updatedBook).toBe(true); + // copies should still be 1 because our new value failed validation on the server + expect(updatedBook.copies).toBe(1); + } else { + // When validate: false on the server, validation should be skipped + expect(!!error).toBe(false); + expect(!!result).toBe(true); + expect(validationErrors.length).toBe(0); + + updatedBook = books.findOne(newId); + expect(!!updatedBook).toBe(true); + // copies should be changed despite being invalid because we skipped validation on the server + expect(updatedBook.copies).toBe('Yes Please'); + } + + // now try a good one + books.update({ + _id: newId + }, { + $set: { + copies: 3 + } + }, { + validate: false, + validationContext: "validateFalse4" + }, (error, result) => { + const validationErrors = books.simpleSchema().namedContext("validateFalse4").validationErrors(); + expect(!!error).toBe(false); + expect(result).toBe(1); + expect(validationErrors.length).toBe(0); + + const updatedBook = books.findOne(newId); + expect(!!updatedBook).toBe(true); + // copies should be changed because we used a valid value + expect(updatedBook.copies).toBe(3); + done(); + }); + }); + }); + }); + }); + + if (Meteor.isServer) { + it('bypassCollection2', function (done) { + let id; + + try { + id = books.insert({}, {bypassCollection2: true}) + } catch (error) { + done(error); + } + + try { + books.update(id, {$set: {copies: 2}}, {bypassCollection2: true}) + done(); + } catch (error) { + done(error); + } + }); + + it('everything filtered out', function () { + expect(function () { + upsertTest.update({_id: '123'}, { + $set: { + boo: 1 + } + }); + }).toThrow('After filtering out keys not in the schema, your modifier is now empty'); + }); + + it('upsert works with schema that allows _id', function () { + upsertTest.remove({}); + + const upsertTestId = upsertTest.insert({foo: 1}); + + upsertTest.update({_id: upsertTestId}, { + $set: { + foo: 2 + } + }, { + upsert: true + }); + const doc = upsertTest.findOne(upsertTestId); + expect(doc.foo).toBe(2); + }); + } +} diff --git a/schema-tests/clean.tests.js b/schema-tests/clean.tests.js new file mode 100644 index 0000000..de98665 --- /dev/null +++ b/schema-tests/clean.tests.js @@ -0,0 +1,206 @@ +import expect from 'expect'; +import { Mongo } from 'meteor/mongo'; +import SimpleSchema from 'simpl-schema'; + +let collection; + +if (Meteor.isClient) { + collection = new Mongo.Collection('cleanTests', { connection: null }); +} else { + collection = new Mongo.Collection('cleanTests'); +} + +describe('clean options', function () { + describe('filter', function () { + it('keeps default schema clean options', function (done) { + const schema = new SimpleSchema({ + name: String, + }, { + clean: { + filter: false, + }, + }); + + collection.attachSchema(schema, { replace: true }); + + collection.insert({ name: 'name', bad: 'prop' }, (error) => { + expect(error instanceof Error).toBe(true); + done(); + }); + }); + + it('keeps operation clean options', function (done) { + const schema = new SimpleSchema({ + name: String, + }, { + clean: { + filter: true, + }, + }); + + collection.attachSchema(schema, { replace: true }); + + collection.insert({ name: 'name', bad: 'prop' }, { filter: false }, (error) => { + expect(error instanceof Error).toBe(true); + done(); + }); + }); + + it('has clean option on by default', function (done) { + const schema = new SimpleSchema({ name: String }); + + collection.attachSchema(schema, { replace: true }); + + collection.insert({ name: 'name', bad: 'prop' }, (error) => { + expect(error).toBe(null); + done(); + }); + }); + }); + + describe('autoConvert', function () { + it('keeps default schema clean options', function (done) { + const schema = new SimpleSchema({ + name: String, + }, { + clean: { + autoConvert: false, + }, + }); + + collection.attachSchema(schema, { replace: true }); + + collection.insert({ name: 1 }, (error) => { + expect(error instanceof Error).toBe(true); + done(); + }); + }); + + it('keeps operation clean options', function (done) { + const schema = new SimpleSchema({ + name: String, + }, { + clean: { + autoConvert: true, + }, + }); + + collection.attachSchema(schema, { replace: true }); + + collection.insert({ name: 1 }, { autoConvert: false }, (error) => { + expect(error instanceof Error).toBe(true); + done(); + }); + }); + + it('has clean option on by default', function (done) { + const schema = new SimpleSchema({ name: String }); + + collection.attachSchema(schema, { replace: true }); + + collection.insert({ name: 1 }, (error) => { + expect(error).toBe(null); + done(); + }); + }); + }); + + describe('removeEmptyStrings', function () { + it('keeps default schema clean options', function (done) { + const schema = new SimpleSchema({ + name: String, + other: Number + }, { + clean: { + removeEmptyStrings: false, + }, + }); + + collection.attachSchema(schema, { replace: true }); + + collection.insert({ name: '', other: 1 }, (error) => { + expect(error).toBe(null); + done(); + }); + }); + + it('keeps operation clean options', function (done) { + const schema = new SimpleSchema({ + name: String, + other: Number, + }, { + clean: { + removeEmptyStrings: true, + }, + }); + + collection.attachSchema(schema, { replace: true }); + + collection.insert({ name: '', other: 1 }, { removeEmptyStrings: false }, (error) => { + expect(error).toBe(null); + done(); + }); + }); + + it('has clean option on by default', function (done) { + const schema = new SimpleSchema({ name: String, other: Number }); + + collection.attachSchema(schema, { replace: true }); + + collection.insert({ name: '', other: 1 }, (error) => { + expect(error instanceof Error).toBe(true); + done(); + }); + }); + }); + + describe('trimStrings', function () { + it('keeps default schema clean options', function (done) { + const schema = new SimpleSchema({ + name: String, + }, { + clean: { + trimStrings: false, + }, + }); + + collection.attachSchema(schema, { replace: true }); + + collection.insert({ name: ' foo ' }, (error, _id) => { + expect(error).toBe(null); + expect(collection.findOne(_id)).toEqual({ _id, name: ' foo ' }); + done(); + }); + }); + + it('keeps operation clean options', function (done) { + const schema = new SimpleSchema({ + name: String, + }, { + clean: { + trimStrings: true, + }, + }); + + collection.attachSchema(schema, { replace: true }); + + collection.insert({ name: ' foo ' }, { trimStrings: false }, (error, _id) => { + expect(error).toBe(null); + expect(collection.findOne(_id)).toEqual({ _id, name: ' foo ' }); + done(); + }); + }); + + it('has clean option on by default', function (done) { + const schema = new SimpleSchema({ name: String }); + + collection.attachSchema(schema, { replace: true }); + + collection.insert({ name: ' foo ' }, (error, _id) => { + expect(error).toBe(null); + expect(collection.findOne(_id)).toEqual({ _id, name: 'foo' }); + done(); + }); + }); + }); +}); diff --git a/schema-tests/collection2.tests.js b/schema-tests/collection2.tests.js new file mode 100644 index 0000000..3e81fb5 --- /dev/null +++ b/schema-tests/collection2.tests.js @@ -0,0 +1,693 @@ +import expect from 'expect'; +import { Mongo } from 'meteor/mongo'; +import SimpleSchema from 'simpl-schema'; + +import addMultiTests from './multi.tests.js'; +import addBooksTests from './books.tests.js'; +import addContextTests from './context.tests.js'; +import addDefaultValuesTests from './default.tests.js'; + +describe('collection2', function () { + it('attach and get simpleSchema for normal collection', function () { + var mc = new Mongo.Collection('mc'); + + mc.attachSchema( + new SimpleSchema({ + foo: { type: String }, + }) + ); + + expect(mc.simpleSchema() instanceof SimpleSchema).toBe(true); + }); + + it('attach and get simpleSchema for local collection', function () { + var mc = new Mongo.Collection(null); + + mc.attachSchema( + new SimpleSchema({ + foo: { type: String }, + }) + ); + + expect(mc.simpleSchema() instanceof SimpleSchema).toBe(true); + }); + + it('handles prototype-less objects', function (done) { + const prototypelessTest = new Mongo.Collection('prototypelessTest'); + + prototypelessTest.attachSchema( + new SimpleSchema({ + foo: { + type: String, + }, + }) + ); + + const prototypelessObject = Object.create(null); + prototypelessObject.foo = 'bar'; + + prototypelessTest.insert(prototypelessObject, (error, newId) => { + expect(!!error).toBe(false); + done(); + }); + }); + + if (Meteor.isServer) { + // https://github.com/aldeed/meteor-collection2/issues/243 + it('upsert runs autoValue only once', function (done) { + const upsertAutoValueTest = new Mongo.Collection('upsertAutoValueTest'); + let times = 0; + + upsertAutoValueTest.attachSchema( + new SimpleSchema({ + foo: { + type: String, + }, + av: { + type: String, + autoValue() { + times++; + return 'test'; + }, + }, + }) + ); + + upsertAutoValueTest.remove({}); + + upsertAutoValueTest.upsert( + { + foo: 'bar', + }, + { + $set: { + av: 'abc', + }, + }, + (error, result) => { + expect(times).toBe(1); + done(); + } + ); + }); + + // https://forums.meteor.com/t/simpl-schema-update-error-while-using-lte-operator-when-calling-update-by-the-field-of-type-date/50414/3 + it('upsert can handle query operators in the selector', function () { + const upsertQueryOperatorsTest = new Mongo.Collection( + 'upsertQueryOperatorsTest' + ); + + upsertQueryOperatorsTest.attachSchema( + new SimpleSchema({ + foo: { + type: Date, + optional: true, + }, + bar: Number, + baz: Number, + }) + ); + + upsertQueryOperatorsTest.remove({}); + const oneDayInMs = 1000 * 60 * 60 * 24; + const yesterday = new Date(Date.now() - oneDayInMs); + const tomorrow = new Date(Date.now() + oneDayInMs); + + const { numberAffected, insertedId } = upsertQueryOperatorsTest.upsert( + { + foo: { $gte: yesterday, $lte: tomorrow }, + }, + { + $set: { + bar: 2, + }, + $inc: { + baz: 4, + }, + } + ); + + expect(numberAffected).toBe(1); + const doc = upsertQueryOperatorsTest.findOne(); + expect(insertedId).toBe(doc._id); + expect(doc.bar).toBe(2); + expect(doc.baz).toBe(4); + }); + + it('upsert with schema can handle query operator which contains undefined or null', function (done) { + const upsertQueryOperatorUndefinedTest = new Mongo.Collection( + 'upsertQueryOperatorUndefinedTest' + ); + + upsertQueryOperatorUndefinedTest.attachSchema( + new SimpleSchema({ + foo: { + type: String, + optional: true, + }, + bar: Number, + baz: Number, + }) + ); + + // Let's try for undefined. + upsertQueryOperatorUndefinedTest.remove({}); + + upsertQueryOperatorUndefinedTest.upsert( + { + foo: undefined, + }, + { + $set: { + bar: 2, + }, + $inc: { + baz: 4, + }, + }, + (error, result) => { + expect(error).toBe(null); + + expect(result.numberAffected).toBe(1); + const doc = upsertQueryOperatorUndefinedTest.findOne(); + expect(result.insertedId).toBe(doc._id); + expect(doc.foo).toBe(undefined); + expect(doc.bar).toBe(2); + expect(doc.baz).toBe(4); + + // Let's try for null. + upsertQueryOperatorUndefinedTest.remove({}); + + upsertQueryOperatorUndefinedTest.upsert( + { + foo: null, + }, + { + $set: { + bar: 2, + }, + $inc: { + baz: 4, + }, + }, + (error2, result2) => { + expect(error2).toBe(null); + + expect(result2.numberAffected).toBe(1); + const doc = upsertQueryOperatorUndefinedTest.findOne(); + expect(result2.insertedId).toBe(doc._id); + expect(doc.foo).toBe(null); + expect(doc.bar).toBe(2); + expect(doc.baz).toBe(4); + + done(); + } + ); + } + ); + }); + + it('upsert with schema can handle query operator "eq" correctly in the selector when property is left out in $set or $setOnInsert', function (done) { + const upsertQueryOperatorEqTest = new Mongo.Collection( + 'upsertQueryOperatorEqTest' + ); + + upsertQueryOperatorEqTest.attachSchema( + new SimpleSchema({ + foo: String, + bar: Number, + baz: Number, + }) + ); + + upsertQueryOperatorEqTest.remove({}); + + upsertQueryOperatorEqTest.upsert( + { + foo: { $eq: 'test' }, + }, + { + $set: { + bar: 2, + }, + $inc: { + baz: 4, + }, + }, + (error, result) => { + expect(error).toBe(null); + + expect(result.numberAffected).toBe(1); + const doc = upsertQueryOperatorEqTest.findOne(); + expect(result.insertedId).toBe(doc._id); + expect(doc.foo).toBe('test'); + expect(doc.bar).toBe(2); + expect(doc.baz).toBe(4); + + done(); + } + ); + }); + + it('upsert with schema can handle query operator "in" with one element correctly in the selector when property is left out in $set or $setOnInsert', function (done) { + const upsertQueryOperatorInSingleTest = new Mongo.Collection( + 'upsertQueryOperatorInSingleTest' + ); + + upsertQueryOperatorInSingleTest.attachSchema( + new SimpleSchema({ + foo: String, + bar: Number, + baz: Number, + }) + ); + + upsertQueryOperatorInSingleTest.remove({}); + + upsertQueryOperatorInSingleTest.upsert( + { + foo: { $in: ['test'] }, + }, + { + $set: { + bar: 2, + }, + $inc: { + baz: 4, + }, + }, + (error, result) => { + expect(error).toBe(null); + + expect(result.numberAffected).toBe(1); + const doc = upsertQueryOperatorInSingleTest.findOne(); + expect(result.insertedId).toBe(doc._id); + expect(doc.foo).toBe('test'); + expect(doc.bar).toBe(2); + expect(doc.baz).toBe(4); + + done(); + } + ); + }); + + it('upsert with schema can handle query operator "in" with multiple elements correctly in the selector when property is left out in $set or $setOnInsert', function (done) { + const upsertQueryOperatorInMultiTest = new Mongo.Collection( + 'upsertQueryOperatorInMultiTest' + ); + + upsertQueryOperatorInMultiTest.attachSchema( + new SimpleSchema({ + foo: { + type: String, + optional: true, + }, + bar: Number, + baz: Number, + }) + ); + + upsertQueryOperatorInMultiTest.remove({}); + + upsertQueryOperatorInMultiTest.upsert( + { + foo: { $in: ['test', 'test2'] }, + }, + { + $set: { + bar: 2, + }, + $inc: { + baz: 4, + }, + }, + (error, result) => { + expect(error).toBe(null); + + expect(result.numberAffected).toBe(1); + const doc = upsertQueryOperatorInMultiTest.findOne(); + expect(result.insertedId).toBe(doc._id); + expect(doc.foo).toBe(undefined); + expect(doc.bar).toBe(2); + expect(doc.baz).toBe(4); + + done(); + } + ); + }); + + // https://github.com/Meteor-Community-Packages/meteor-collection2/issues/408 + it('upsert with schema can handle nested objects correctly', function (done) { + const upsertQueryOperatorNestedObject = new Mongo.Collection( + 'upsertQueryOperatorNestedObject' + ); + + upsertQueryOperatorNestedObject.attachSchema( + new SimpleSchema({ + foo: { + type: new SimpleSchema({ + bar: { + type: String, + }, + baz: { + type: String, + }, + }), + }, + test: { + type: Date, + }, + }) + ); + + upsertQueryOperatorNestedObject.remove({}); + + const testDateValue = new Date(); + upsertQueryOperatorNestedObject.upsert( + { + test: '1', + }, + { + $set: { + foo: { + bar: '1', + baz: '2', + }, + test: testDateValue, + }, + }, + (error, result) => { + expect(error).toBe(null); + expect(result.numberAffected).toBe(1); + + const doc = upsertQueryOperatorNestedObject.findOne({ + _id: result.insertedId, + }); + + expect(result.insertedId).toBe(doc._id); + expect(doc.foo.bar).toBe('1'); + expect(doc.foo.baz).toBe('2'); + expect(doc.test).toEqual(testDateValue); + + done(); + } + ); + }); + + it('upsert with schema can handle query operator "$and" including inner nested selectors correctly when properties is left out in $set or $setOnInsert', function (done) { + const upsertQueryOperatorAndTest = new Mongo.Collection( + 'upsertQueryOperatorAndTest' + ); + + upsertQueryOperatorAndTest.attachSchema( + new SimpleSchema({ + foo: String, + test1: String, + test2: String, + bar: Number, + baz: Number, + }) + ); + + upsertQueryOperatorAndTest.remove({}); + + upsertQueryOperatorAndTest.upsert( + { + foo: 'test', + $and: [{ test1: 'abc' }, { $and: [{ test2: { $in: ['abc'] } }] }], + }, + { + $set: { + bar: 2, + }, + $inc: { + baz: 4, + }, + }, + (error, result) => { + expect(error).toBe(null); + + expect(result.numberAffected).toBe(1); + const doc = upsertQueryOperatorAndTest.findOne(); + expect(result.insertedId).toBe(doc._id); + expect(doc.foo).toBe('test'); + expect(doc.test1).toBe('abc'); + expect(doc.test2).toBe('abc'); + expect(doc.bar).toBe(2); + expect(doc.baz).toBe(4); + + done(); + } + ); + }); + } + + it('no errors when using a schemaless collection', function (done) { + const noSchemaCollection = new Mongo.Collection('noSchema', { + transform(doc) { + doc.userFoo = 'userBar'; + return doc; + }, + }); + + noSchemaCollection.insert( + { + a: 1, + b: 2, + }, + (error, newId) => { + expect(!!error).toBe(false); + expect(!!newId).toBe(true); + + const doc = noSchemaCollection.findOne(newId); + expect(doc instanceof Object).toBe(true); + expect(doc.userFoo).toBe('userBar'); + + noSchemaCollection.update( + { + _id: newId, + }, + { + $set: { + a: 3, + b: 4, + }, + }, + (error) => { + expect(!!error).toBe(false); + done(); + } + ); + } + ); + }); + + it('empty strings are removed but we can override', function (done) { + const RESSchema = new SimpleSchema({ + foo: { type: String }, + bar: { type: String, optional: true }, + }); + + const RES = new Mongo.Collection('RES'); + RES.attachSchema(RESSchema); + + // Remove empty strings (default) + RES.insert( + { + foo: 'foo', + bar: '', + }, + (error, newId1) => { + expect(!!error).toBe(false); + expect(typeof newId1).toBe('string'); + + const doc = RES.findOne(newId1); + expect(doc instanceof Object).toBe(true); + expect(doc.bar).toBe(undefined); + + // Don't remove empty strings + RES.insert( + { + foo: 'foo', + bar: '', + }, + { + removeEmptyStrings: false, + }, + (error, newId2) => { + expect(!!error).toBe(false); + expect(typeof newId2).toBe('string'); + + const doc = RES.findOne(newId2); + expect(doc instanceof Object).toBe(true); + expect(doc.bar).toBe(''); + + // Don't remove empty strings for an update either + RES.update( + { + _id: newId1, + }, + { + $set: { + bar: '', + }, + }, + { + removeEmptyStrings: false, + }, + (error, result) => { + expect(!!error).toBe(false); + expect(result).toBe(1); + + const doc = RES.findOne(newId1); + expect(doc instanceof Object).toBe(true); + expect(doc.bar).toBe(''); + done(); + } + ); + } + ); + } + ); + }); + + it('extending a schema after attaching it, collection2 validation respects the extension', (done) => { + const schema = new SimpleSchema({ + foo: String, + }); + + const collection = new Mongo.Collection('ExtendAfterAttach'); + collection.attachSchema(schema); + + collection.insert( + { + foo: 'foo', + bar: 'bar', + }, + { + filter: false, + }, + (error) => { + expect(error.invalidKeys[0].name).toBe('bar'); + schema.extend({ + bar: String, + }); + + collection.insert( + { + foo: 'foo', + bar: 'bar', + }, + { + filter: false, + }, + (error2) => { + expect(!!error2).toBe(false); + + done(); + } + ); + } + ); + }); + + it('extending a schema with a selector after attaching it, collection2 validation respects the extension', (done) => { + const schema = new SimpleSchema({ + foo: String, + }); + + const collection = new Mongo.Collection('ExtendAfterAttach2'); + collection.attachSchema(schema, { selector: { foo: 'foo' } }); + + collection.insert( + { + foo: 'foo', + bar: 'bar', + }, + { + filter: false, + }, + (error) => { + expect(error.invalidKeys[0].name).toBe('bar'); + + schema.extend({ + bar: String, + }); + + collection.insert( + { + foo: 'foo', + bar: 'bar', + }, + { + filter: false, + }, + (error2) => { + expect(!!error2).toBe(false); + + done(); + } + ); + } + ); + }); + + it('pick or omit schema fields when options are provided', function () { + const collectionSchema = new SimpleSchema({ + foo: { type: String }, + bar: { type: String, optional: true }, + }); + + const collection = new Mongo.Collection('pickOrOmit'); + collection.attachSchema(collectionSchema); + + // Test error from including both pick and omit + let errorThrown = false; + + try { + collection.insert( + { foo: 'foo', bar: '' }, + { pick: ['foo'], omit: ['foo'] } + ); + } catch (error) { + expect(error.message).toBe( + 'pick and omit options are mutually exclusive' + ); + errorThrown = true; + } + + expect(errorThrown).toBe(true); + + // Omit required field 'foo' + collection.insert({ bar: 'test' }, { omit: ['foo'] }, (error, newId2) => { + expect(!!error).toBe(false); + expect(typeof newId2).toBe('string'); + + const doc = collection.findOne(newId2); + expect(doc instanceof Object).toBe(true); + expect(doc.foo).toBe(undefined); + expect(doc.bar).toBe('test'); + + // Pick only 'foo' + collection.update( + { _id: newId2 }, + { $set: { foo: 'test', bar: 'changed' } }, + { pick: ['foo'] }, + (error, result) => { + expect(!!error).toBe(false); + expect(result).toBe(1); + + const doc = collection.findOne(newId2); + expect(doc instanceof Object).toBe(true); + expect(doc.foo).toBe('test'); + expect(doc.bar).toBe('test'); + } + ); + }); + }); + + addBooksTests(); + addContextTests(); + addDefaultValuesTests(); + addMultiTests(); +}); diff --git a/schema-tests/context.tests.js b/schema-tests/context.tests.js new file mode 100644 index 0000000..24d6e04 --- /dev/null +++ b/schema-tests/context.tests.js @@ -0,0 +1,105 @@ +import expect from 'expect'; +import { Mongo } from 'meteor/mongo'; +import SimpleSchema from 'simpl-schema'; + +const contextCheckSchema = new SimpleSchema({ + foo: { + type: String, + optional: true + }, + context: { + type: Object, + optional: true, + defaultValue: {}, + }, + 'context.userId': { + type: String, + optional: true, + autoValue() { + return this.userId; + } + }, + 'context.isFromTrustedCode': { + type: Boolean, + optional: true, + autoValue() { + return this.isFromTrustedCode; + } + }, + 'context.isInsert': { + type: Boolean, + optional: true, + autoValue() { + return this.isInsert; + } + }, + 'context.isUpdate': { + type: Boolean, + optional: true, + autoValue() { + return this.isUpdate; + } + }, + 'context.docId': { + type: String, + optional: true, + autoValue() { + return this.docId; + } + } +}); + +const contextCheck = new Mongo.Collection('contextCheck'); +contextCheck.attachSchema(contextCheckSchema); + +export default function addContextTests() { + it('AutoValue Context', function (done) { + let testId; + + const callback1 = () => { + const ctx = contextCheck.findOne(testId); + expect(ctx.context.docId).toBe(testId); + done(); + }; + + const callback2 = () => { + const ctx = contextCheck.findOne(testId); + expect(ctx.foo).toBe('bar'); + expect(ctx.context.isUpdate).toBe(true); + expect(ctx.context.isInsert).toBe(false); + expect(ctx.context.userId).toBe(null); + expect(ctx.context.docId).toBe(testId); + expect(ctx.context.isFromTrustedCode).toBe(!Meteor.isClient); + + // make sure docId works with `_id` direct, too + contextCheck.update(testId, { + $set: { + context: {}, + foo: "bar" + } + }, callback1); + }; + + const callback3 = (error, result) => { + testId = result; + expect(!!error).toBe(false); + const ctx = contextCheck.findOne(testId); + expect(ctx.context.isInsert).toBe(true); + expect(ctx.context.isUpdate).toBe(false); + expect(ctx.context.userId).toBe(null); + expect(ctx.context.docId).toBe(undefined); + expect(ctx.context.isFromTrustedCode).toBe(!Meteor.isClient); + + contextCheck.update({ + _id: testId + }, { + $set: { + context: {}, + foo: "bar" + } + }, callback2); + }; + + contextCheck.insert({}, callback3); + }); +} diff --git a/schema-tests/default.tests.js b/schema-tests/default.tests.js new file mode 100644 index 0000000..8d4e0ae --- /dev/null +++ b/schema-tests/default.tests.js @@ -0,0 +1,43 @@ +import expect from 'expect'; +import { Mongo } from 'meteor/mongo'; +import SimpleSchema from 'simpl-schema'; + +const defaultValuesSchema = new SimpleSchema({ + bool1: { + type: Boolean, + defaultValue: false + } +}); + +const defaultValues = new Mongo.Collection('dv'); +defaultValues.attachSchema(defaultValuesSchema); + +export default function addDefaultValuesTests() { + it('defaultValues', function (done) { + let p; + + // Base case + defaultValues.insert({}, (error, testId1) => { + p = defaultValues.findOne(testId1); + expect(p.bool1).toBe(false); + + // Ensure that default values do not mess with inserts and updates of the field + defaultValues.insert({ + bool1: true + }, (err, testId2) => { + p = defaultValues.findOne(testId2); + expect(p.bool1).toBe(true); + + defaultValues.update(testId1, { + $set: { + bool1: true + } + }, () => { + p = defaultValues.findOne(testId1); + expect(p.bool1).toBe(true); + done(); + }); + }); + }); + }); +}; diff --git a/schema-tests/multi.tests.js b/schema-tests/multi.tests.js new file mode 100644 index 0000000..29e0032 --- /dev/null +++ b/schema-tests/multi.tests.js @@ -0,0 +1,418 @@ +import expect from 'expect'; +import { Mongo } from 'meteor/mongo'; +import SimpleSchema from 'simpl-schema'; + +const productSchema = new SimpleSchema({ + _id: { + type: String, + optional: true + }, + title: { + type: String, + defaultValue: "" + }, + type: { + label: "Product Type", + type: String, + defaultValue: "simple" + }, + description: { + type: String, + defaultValue: "This is a simple product." + } +}); + +const productVariantSchema = new SimpleSchema({ + _id: { + type: String, + optional: true + }, + title: { + type: String, + defaultValue: "" + }, + optionTitle: { + label: "Option", + type: String, + optional: true + }, + type: { + label: "Product Variant Type", + type: String, + defaultValue: "variant" + }, + price: { + label: "Price", + type: Number, + min: 0, + optional: true, + defaultValue: 5 + }, + createdAt: { + type: Date, + } +}); + +const extendedProductSchema = new SimpleSchema(productSchema); +extendedProductSchema.extend({ + barcode: { + type: String, + defaultValue: "ABC123" + } +}); + +/* Products */ + +// Need to define the client one on both client and server +let products = new Mongo.Collection('TestProductsClient'); +products.attachSchema(productSchema, { selector: { type: 'simple' } }); +products.attachSchema(productVariantSchema, { selector: { type: 'variant' } }); +if (Meteor.isServer) { + products = new Mongo.Collection('TestProductsServer'); + products.attachSchema(productSchema, { selector: { type: 'simple' } }); + products.attachSchema(productVariantSchema, { selector: { type: 'variant' } }); +} + +/* Extended Products */ +// Need to define the client one on both client and server +let extendedProducts = new Mongo.Collection('ExtendedProductsClient'); +extendedProducts.attachSchema(productSchema, {selector: {type: 'simple'}}); +extendedProducts.attachSchema(productVariantSchema, {selector: {type: 'variant'}}); +extendedProducts.attachSchema(extendedProductSchema, {selector: {type: 'simple'}}); +if (Meteor.isServer) { + extendedProducts = new Mongo.Collection('ExtendedProductsServer'); + extendedProducts.attachSchema(productSchema, {selector: {type: 'simple'}}); + extendedProducts.attachSchema(productVariantSchema, {selector: {type: 'variant'}}); + extendedProducts.attachSchema(extendedProductSchema, {selector: {type: 'simple'}}); +} + +export default function addMultiTests() { + describe('multiple top-level schemas', function () { + beforeEach(function () { + products.find({}).forEach(doc => { + products.remove(doc._id); + }); + extendedProducts.find({}).forEach(doc => { + products.remove(doc._id); + }); + }); + + it('works', function () { + const c = new Mongo.Collection('multiSchema'); + + // Attach two different schemas + c.attachSchema(new SimpleSchema({ + one: { type: String } + })); + c.attachSchema(new SimpleSchema({ + two: { type: String } + })); + + // Check the combined schema + let combinedSchema = c.simpleSchema(); + expect(combinedSchema._schemaKeys.includes('one')).toBe(true); + expect(combinedSchema._schemaKeys.includes('two')).toBe(true); + expect(combinedSchema.schema('two').type).toEqual(SimpleSchema.oneOf(String)); + + // Attach a third schema and make sure that it extends/overwrites the others + c.attachSchema(new SimpleSchema({ + two: { type: SimpleSchema.Integer } + })); + combinedSchema = c.simpleSchema(); + expect(combinedSchema._schemaKeys.includes('one')).toBe(true); + expect(combinedSchema._schemaKeys.includes('two')).toBe(true); + expect(combinedSchema.schema('two').type).toEqual(SimpleSchema.oneOf(SimpleSchema.Integer)); + + // Ensure that we've only attached two deny functions + expect(c._validators.insert.deny.length).toBe(2); + expect(c._validators.update.deny.length).toBe(2); + }); + + it('inserts doc correctly with selector passed via doc', function (done) { + const productId = products.insert({ + title: 'Product one', + type: 'simple' // selector in doc + }, () => { + const product = products.findOne(productId); + expect(product.description).toBe('This is a simple product.'); + expect(product.price).toBe(undefined); + + const productId3 = products.insert({ + title: 'Product three', + createdAt: new Date(), + type: 'variant' // other selector in doc + }, () => { + const product3 = products.findOne(productId3); + expect(product3.description).toBe(undefined); + expect(product3.price).toBe(5); + done(); + }); + }); + }); + + if (Meteor.isServer) { + // Passing selector in options works only on the server because + // client options are not sent to the server and made availabe in + // the deny functions, where we call .simpleSchema() + // + // Also synchronous only works on server + it('insert selects the correct schema', function () { + const productId = products.insert({ + title: 'Product one' + }, { selector: { type: 'simple' } }); + + const productVariantId = products.insert({ + title: 'Product variant one', + createdAt: new Date() + }, { selector: { type: 'variant' } }); + + const product = products.findOne(productId); + const productVariant = products.findOne(productVariantId); + + // we should receive new docs with correct property set for each type of doc + expect(product.description).toBe('This is a simple product.'); + expect(product.price).toBe(undefined); + expect(productVariant.description).toBe(undefined); + expect(productVariant.price).toBe(5) + }); + + it('inserts doc correctly with selector passed via doc and via