├── .editorconfig ├── .github └── workflows │ └── release.yml ├── .gitignore ├── .npmignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── changes.md ├── docs ├── changes.md ├── index.md ├── pt │ ├── changes.md │ └── index.md └── public │ ├── brazil.png │ └── logo.png ├── lib ├── core │ ├── Collection.js │ └── MycroDatabase.js ├── index.js ├── storage │ ├── json.js │ ├── memory.js │ └── typedJson.js ├── types.js └── utils │ ├── createDirectoriesRecursively.js │ ├── removeFileNameAndExtension.js │ └── validateSchema.js ├── package-lock.json ├── package.json └── test ├── class.test.js ├── count.test.js ├── get.test.js ├── insert.test.js ├── query.test.js ├── remove.test.js ├── storage.test.js ├── typedJson.storage.test.js └── update.test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | end_of_line = crlf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | workflow_dispatch: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | release: 10 | name: release 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions/setup-node@v1 15 | with: 16 | node-version: "20.x" 17 | - run: npx semantic-release --ci=false --dry-run=false 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.REPO_TOKEN }} 20 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Enable my LOG 11 | !changes.log 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | node_modules/ 46 | jspm_packages/ 47 | 48 | # Snowpack dependency directory (https://snowpack.dev/) 49 | web_modules/ 50 | 51 | # TypeScript cache 52 | *.tsbuildinfo 53 | 54 | # Optional npm cache directory 55 | .npm 56 | 57 | # Optional eslint cache 58 | .eslintcache 59 | 60 | # Optional stylelint cache 61 | .stylelintcache 62 | 63 | # Microbundle cache 64 | .rpt2_cache/ 65 | .rts2_cache_cjs/ 66 | .rts2_cache_es/ 67 | .rts2_cache_umd/ 68 | 69 | # Optional REPL history 70 | .node_repl_history 71 | 72 | # Output of 'npm pack' 73 | *.tgz 74 | 75 | # Yarn Integrity file 76 | .yarn-integrity 77 | 78 | # dotenv environment variable files 79 | .env 80 | .env.development.local 81 | .env.test.local 82 | .env.production.local 83 | .env.local 84 | 85 | # parcel-bundler cache (https://parceljs.org/) 86 | .cache 87 | .parcel-cache 88 | 89 | # Next.js build output 90 | .next 91 | out 92 | 93 | # Nuxt.js build / generate output 94 | .nuxt 95 | dist 96 | 97 | # Gatsby files 98 | .cache/ 99 | # Comment in the public line in if your project uses Gatsby and not Next.js 100 | # https://nextjs.org/blog/next-9-1#public-directory-support 101 | # public 102 | 103 | # vuepress build output 104 | .vuepress/dist 105 | 106 | # vuepress v2.x temp and cache directory 107 | .temp 108 | .cache 109 | 110 | # Docusaurus cache and generated files 111 | .docusaurus 112 | 113 | # Serverless directories 114 | .serverless/ 115 | 116 | # FuseBox cache 117 | .fusebox/ 118 | 119 | # DynamoDB Local files 120 | .dynamodb/ 121 | 122 | # TernJS port file 123 | .tern-port 124 | 125 | # Stores VSCode versions used for testing VSCode extensions 126 | .vscode-test 127 | 128 | # yarn v2 129 | .yarn/cache 130 | .yarn/unplugged 131 | .yarn/build-state.yml 132 | .yarn/install-state.gz 133 | .pnp.* 134 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | 3 | !lib/index.js 4 | !lib/types.js 5 | 6 | !lib/core/Collection.js 7 | !lib/core/MycroDatabase.js 8 | 9 | !lib/storage/json.js 10 | !lib/storage/memory.js 11 | !lib/storage/typedJson.js 12 | 13 | !lib/utils/createDirectoriesRecursively.js 14 | !lib/utils/removeFileNameAndExtension.js 15 | !lib/utils/validateSchema.js 16 | 17 | !package.json 18 | !README.md 19 | !docs/public/* 20 | !LICENSE 21 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": ["mycro"], 3 | "editor.formatOnSave": true, 4 | "editor.codeActionsOnSave": { 5 | "source.fixAll": true, 6 | "source.organizeImports": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Diego Queiroz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MycroDB 📦 2 | 3 | [![Logo](/docs/public/logo.png)](https://www.npmjs.com/package/mycro-db) 4 | 5 | [![Brazil Flag](/docs/public/brazil.png) Documentation in Portuguese](https://diegiwg.github.io/mycro-db/pt) 6 | 7 | ## Project Overview 🚀 8 | 9 | MycroDB is a JavaScript library designed for managing Document Databases stored in a single JSON file or in memory. 10 | 11 | MycroDB is available as an NPM library, and you can find it at [https://www.npmjs.com/package/mycro-db](https://www.npmjs.com/package/mycro-db). 12 | 13 | ## Example Project 14 | 15 | To showcase how MycroDB works, we've developed a sample project that implements a Command Line Interface (CLI) for task management. For more information about this project, please visit its dedicated repository at [Todz](https://github.com/Diegiwg/todz). 16 | 17 | ## Installation 18 | 19 | To integrate MycroDB into your project, you can install it via npm (or other package managers): 20 | 21 | ```shell 22 | npm install mycro-db 23 | ``` 24 | 25 | ## MycroDB API 26 | 27 | To get started, import the 'MycroDatabase' class along with a 'Storage' class, and initialize both objects: 28 | 29 | ```javascript 30 | import { JsonStorage, MemoryStorage, MycroDatabase } from 'mycro-db'; 31 | 32 | // In-memory mode 33 | const inMemoryStorage = new MemoryStorage(); 34 | const db = new MycroDatabase(inMemoryStorage); 35 | 36 | // JSON file mode 37 | const jsonStorage = new JsonStorage('my_database.json'); 38 | const db = new MycroDatabase(jsonStorage); 39 | ``` 40 | 41 | ### Collections API 42 | 43 | To maintain organized data, the library employs a collection structure. Utilize collections to logically categorize your data. 44 | 45 | #### Define a Collection 46 | 47 | To create a collection, you need to provide a name, and optionally, you can include a model (an object with properties and their corresponding data types) to enhance IDE intellisense. 48 | 49 | ```javascript 50 | const User = db.collection('users', { name: String(), age: Number() }); 51 | ``` 52 | 53 | #### Insert a Document into a Collection 54 | 55 | To insert a document into a collection, you should supply a plain JavaScript object with values compatible with JSON. You can insert one or more documents in a single operation by passing an array of document objects. 56 | 57 | ```javascript 58 | User.insert([ 59 | { name: 'Alice', age: 28 }, 60 | { name: 'Bob', age: 30 } 61 | ]); 62 | ``` 63 | 64 | #### Update a Document in a Collection 65 | 66 | To update a document, provide an object containing the 'id' key with the document's ID to be updated, and the 'data' key containing an object with 'key: value' pairs to be updated in the document. The update is atomic, meaning that only the values provided in the object will be updated, while other values in the document remain unchanged. You can update one or more documents in a single operation by passing an array of document objects. 67 | 68 | ```javascript 69 | User.update([ 70 | { id: 1, data: { age: 45 } } 71 | ]); 72 | ``` 73 | 74 | #### Get a Document in a Collection 75 | 76 | To retrieve a document from a collection, provide an ID of the document. You can get one or more documents in a single operation by passing an array of IDs. 77 | 78 | ```javascript 79 | User.get([ 80 | 1, 5 81 | ]); 82 | ``` 83 | 84 | #### Query Documents in a Collection 85 | 86 | To query documents in a collection, provide a strategy (filter) function. If no filtering function is provided, all documents will be returned. The number of documents returned depends on the 'limit' parameter, and the offset parameter is used for 'pagination'. All parameters are optional. By default, the limit is 25, and the offset is 0. 87 | 88 | ```javascript 89 | const strategy = (user) => user.age > 21; 90 | const limit = 10; 91 | const offset = 0; 92 | 93 | User.query(strategy, limit, offset); 94 | ``` 95 | 96 | #### Remove a Document from a Collection 97 | 98 | To remove a document, provide an ID of the document. You can remove one or more documents in a single operation by passing an array of IDs. 99 | 100 | ```javascript 101 | User.remove([ 102 | 1, 5 103 | ]); 104 | ``` 105 | 106 | ## Built-in Storage Strategies 107 | 108 | The library supports the following storage strategies: 109 | 110 | ### In-Memory 111 | 112 | This is the simplest strategy, saving data in memory until the application reloads and all data is erased. 113 | 114 | ```javascript 115 | import { MemoryStorage } from 'mycro-db'; 116 | 117 | const storage = new MemoryStorage(); 118 | const db = new MycroDatabase(storage); 119 | ``` 120 | 121 | ### JSON 122 | 123 | This is the most commonly used strategy and is ideal for those requiring flexibility and persistence. You can provide a schema, but it is primarily used as a reference for IDE intellisense. 124 | 125 | ```javascript 126 | import { JsonStorage } from 'mycro-db'; 127 | 128 | const storage = new JsonStorage('my_database.json'); 129 | const db = new MycroDatabase(storage); 130 | ``` 131 | 132 | ### Typed JSON 133 | 134 | This strategy offers the same functionality as JSON, but it incorporates a 'Schema' for 'insert' and 'update' functions, ensuring that documents added to the database conform to the expected structure (no extra fields and correct data types). If an extra field or incorrect value is provided, an error is raised. 135 | 136 | ```javascript 137 | import { TypedJsonStorage } from 'mycro-db'; 138 | 139 | const storage = new TypedJsonStorage('my_database.json'); 140 | const db = new MycroDatabase(storage); 141 | 142 | const user = db.collection('users', { name: String(), age: Number() }); 143 | // Here, it is defined that a user has Name and Age fields, respectively a String and a Number. 144 | ``` 145 | 146 | ## Changes Log 147 | 148 | For a detailed history of changes to this project, please refer to the [changes.md](changes.md) file in the root directory. 149 | 150 | ## License 📜 151 | 152 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. 153 | -------------------------------------------------------------------------------- /changes.md: -------------------------------------------------------------------------------- 1 | # Version Tracking File 2 | 3 | ## v1.2.5 4 | 5 | - Fixed bug related to synchronization between disk and memory. 6 | 7 | ## v1.2.4 8 | 9 | - Fixed the logo link in the Portuguese documentation. 10 | - Released the version with the fix on npm. 11 | 12 | ## v1.2.3 13 | 14 | - Added a category for Portuguese documentation to the GitHub page. 15 | - A link to this documentation has been added to the README. 16 | 17 | ## v1.2.2 18 | 19 | - Fixed a bug in the generics system that ensures intellisense in collections. 20 | - Modified the file structure of changes. 21 | 22 | ## v1.2.1 23 | 24 | - Updated the README for add a reference to the new Storage Strategy (TypedJson). 25 | 26 | ## v1.2.0 27 | 28 | - Added new Storage model: TypedJson. 29 | - Characteristics: 30 | Now, when a schema exists, all inserted/updated data is checked. 31 | If the type of a data or a key that does not exist in the schema is provided in the Document, an error will be raised. 32 | Complex cases were tested, such as: { value: [ { key: String(), xxx: [ Number() ] } ], required: Boolean() }. 33 | - Given this example, at run time, each document will be tested, looking for the following requirements: 34 | - required: if it exists in the past Document, it must be a boolean. 35 | - value: if it exists in the document, it must be an array. 36 | Each value within this array must be an object: 37 | - key: if it exists in the object, it must be a string. 38 | - xxx: if it exists in the object, it must be an array of Numbers. 39 | Several cases were tested, and 'apparently' the validation function '(utils/validateSchema.js)' is working correctly. 40 | 41 | ## v1.1.1 42 | 43 | - Fixed the npmignore file. 44 | 45 | ## v1.1.0 46 | 47 | - The Storage API has been enhanced with the option to override the functions available in the Collection API. 48 | - This primarily aims to enable more complex methods in more intricate Storages. 49 | 50 | ## v1.0.1 51 | 52 | - Fixed the npmignore file. 53 | 54 | ## v1.0.0 55 | 56 | - Rework of the entire API. 57 | - The library has been divided into several modules. 58 | - Core 59 | - MycroDatabase: The main class of the library, used to build the database access wrapper. 60 | - Collection: A class that represents a collection and provides access to its manipulation methods. 61 | - Storage: 62 | - Memory: A class that represents an in-memory database. 63 | - JSON: A class that represents a disk-based database in JSON format. 64 | 65 | ## v0.4.1 66 | 67 | - Added a 'static site' using the Github Pages. 68 | 69 | ## v0.4.0 70 | 71 | - Removed the old build script. 72 | - 'insert' now accepts multiple documents, making it simpler to insert multiple documents at once. 73 | - Example: `db.collection('users', {id: 0, name: "", age: 0}).insert([{name: "John Doe", age: 20}, {name: "Jane Doe, age: 30}])` 74 | - 'insert', 'update', and 'remove' now return the list of IDs related to the affected documents (created, modified, and removed). 75 | - General improvements in argument validations for functions. 76 | - Updated tests to reflect the changes. 77 | - README documentation updated. 78 | 79 | ## v0.3.2 80 | 81 | - Re-added the 'project overview' label in the README. 82 | 83 | ## v0.3.1 84 | 85 | - Added a Logo in the README. 86 | 87 | ## v0.3.0 88 | 89 | - Added Remove and Update methods to the Collections API. 90 | - Complete rewrite of the library's tests. 91 | - Each function is in its own file. 92 | - README has been updated to reflect the new changes. 93 | 94 | ## v0.2.2 95 | 96 | - Removed all Rollup build tooling. 97 | - The library is 'self-contained' and does not require a separate build process (for now). 98 | - Updated the package.json to reflect the changes. 99 | 100 | ## v0.2.1 101 | 102 | - Fixed a minor 'import' example error in the README. 103 | - Old: import MycroDatabase from 'mycro-db' 104 | - New: import { MycroDatabase } from 'mycro-db 105 | 106 | ## v0.2.0 107 | 108 | - The collections system is now stable. 109 | - When you create a collection, it has its own in-memory space to save its objects. 110 | - Objects are still indexed using auto-generated IDs. 111 | - All collection-related information is also saved to disk. 112 | - No changes were made to the APIs, which still include Insert and Query for each collection, and Sync for the database. 113 | - Tests have been updated to reflect the changes. 114 | 115 | ## v0.1.3 116 | 117 | - Modified the type of the 'filter' parameter in db.collection.query. 118 | - Now, the IDE can provide 'intellisense' for the 'doc' that exists inside the collection. 119 | - Example: db.collection('users', {id: 0, name: "", age: 0}).query((doc) => doc.name === "John Doe") 120 | - The IDE knows that 'doc' is of type {id: number, name: string, age: number}. 121 | 122 | ## v0.1.2 123 | 124 | - When defining a collection, it now checks if the required arguments are being passed for collection creation. 125 | - There is no type checking on these arguments. 126 | - The implementation of 'saving collection schemas' to the on-disk database has begun. 127 | 128 | ## v0.1.1 129 | 130 | - Update README to reflect API changes. 131 | 132 | ## v0.1.0 133 | 134 | - Implemented the initial version of the Collections API. 135 | - Removed direct access to Insert and Query. 136 | - When defining a Collection, you should now pass (with a plain JavaScript object) what you want to be the Schema for that collection. 137 | - Example: db.collection('users', {id: 0, name: "", age: 0}) 138 | - This will ensure that when users access the Insert and Query methods using the collection, the IDE will know that the 'Document' in this collection has the type: {id: number, name: string, age: number}, and provide auto-completion (intellisense) for the user. 139 | - To use Insert and Query, you should first create a collection. 140 | - Example: const User = db.collection('users', {id: 0, name: "", age: 0}) 141 | - User.insert({name: "John Doe", age: 20}) 142 | - User.query((doc) => doc.name === "John Doe") 143 | - Sync remains at the database level. 144 | - Example: db.sync() 145 | - Tests have been modified in accordance with the above changes. 146 | 147 | ## v0.0.5 148 | 149 | - Added the Rollup package with some plugins for the project compilation process. 150 | - Modified the package.json to fix the library import issue in other projects. 151 | 152 | ## v0.0.4 153 | 154 | - Revamped the project README to include the current MycroDB API information. 155 | - Added the LICENSE file. 156 | 157 | ## v0.0.3 158 | 159 | - Added the .npmignore file to prevent unnecessary files from being included with the library during packaging. 160 | 161 | ## v0.0.2 162 | 163 | - Added the 'ava' package as a development dependency for testing. 164 | - Implemented the initial approach for the Database. 165 | - The library exports the 'MycroDatabase' class. 166 | - When constructing this class, it takes a path to the JSON file. 167 | - An object with 'Insert,' 'Query,' and 'Sync' functions is returned: 168 | - Insert: Receives a document (object) and inserts it (in memory) into the database. 169 | - Query: Receives an expression to be used as a filter (in a filter) on the database values. 170 | - Sync: Synchronizes the in-memory data with the on-disk file. 171 | - There are other private functions and properties that are not part of the MycroDatabase object's API: 172 | - __load 173 | -__save 174 | - __nextId 175 | -__filePath 176 | - __memory 177 | -__id 178 | 179 | ## v0.0.1 180 | 181 | - GitHub repository created with some configuration files and initial project structure. 182 | 183 | ## v0.0.0 184 | 185 | - Package published on npm. 186 | -------------------------------------------------------------------------------- /docs/changes.md: -------------------------------------------------------------------------------- 1 | # Version Tracking File 2 | 3 | ## v1.2.5 4 | 5 | - Fixed bug related to synchronization between disk and memory. 6 | 7 | ## v1.2.4 8 | 9 | - Fixed the logo link in the Portuguese documentation. 10 | - Released the version with the fix on npm. 11 | 12 | ## v1.2.3 13 | 14 | - Added a category for Portuguese documentation to the GitHub page. 15 | - A link to this documentation has been added to the README. 16 | 17 | ## v1.2.2 18 | 19 | - Fixed a bug in the generics system that ensures intellisense in collections. 20 | - Modified the file structure of changes. 21 | 22 | ## v1.2.1 23 | 24 | - Updated the README for add a reference to the new Storage Strategy (TypedJson). 25 | 26 | ## v1.2.0 27 | 28 | - Added new Storage model: TypedJson. 29 | - Characteristics: 30 | Now, when a schema exists, all inserted/updated data is checked. 31 | If the type of a data or a key that does not exist in the schema is provided in the Document, an error will be raised. 32 | Complex cases were tested, such as: { value: [ { key: String(), xxx: [ Number() ] } ], required: Boolean() }. 33 | - Given this example, at run time, each document will be tested, looking for the following requirements: 34 | - required: if it exists in the past Document, it must be a boolean. 35 | - value: if it exists in the document, it must be an array. 36 | Each value within this array must be an object: 37 | - key: if it exists in the object, it must be a string. 38 | - xxx: if it exists in the object, it must be an array of Numbers. 39 | Several cases were tested, and 'apparently' the validation function '(utils/validateSchema.js)' is working correctly. 40 | 41 | ## v1.1.1 42 | 43 | - Fixed the npmignore file. 44 | 45 | ## v1.1.0 46 | 47 | - The Storage API has been enhanced with the option to override the functions available in the Collection API. 48 | - This primarily aims to enable more complex methods in more intricate Storages. 49 | 50 | ## v1.0.1 51 | 52 | - Fixed the npmignore file. 53 | 54 | ## v1.0.0 55 | 56 | - Rework of the entire API. 57 | - The library has been divided into several modules. 58 | - Core 59 | - MycroDatabase: The main class of the library, used to build the database access wrapper. 60 | - Collection: A class that represents a collection and provides access to its manipulation methods. 61 | - Storage: 62 | - Memory: A class that represents an in-memory database. 63 | - JSON: A class that represents a disk-based database in JSON format. 64 | 65 | ## v0.4.1 66 | 67 | - Added a 'static site' using the Github Pages. 68 | 69 | ## v0.4.0 70 | 71 | - Removed the old build script. 72 | - 'insert' now accepts multiple documents, making it simpler to insert multiple documents at once. 73 | - Example: `db.collection('users', {id: 0, name: "", age: 0}).insert([{name: "John Doe", age: 20}, {name: "Jane Doe, age: 30}])` 74 | - 'insert', 'update', and 'remove' now return the list of IDs related to the affected documents (created, modified, and removed). 75 | - General improvements in argument validations for functions. 76 | - Updated tests to reflect the changes. 77 | - README documentation updated. 78 | 79 | ## v0.3.2 80 | 81 | - Re-added the 'project overview' label in the README. 82 | 83 | ## v0.3.1 84 | 85 | - Added a Logo in the README. 86 | 87 | ## v0.3.0 88 | 89 | - Added Remove and Update methods to the Collections API. 90 | - Complete rewrite of the library's tests. 91 | - Each function is in its own file. 92 | - README has been updated to reflect the new changes. 93 | 94 | ## v0.2.2 95 | 96 | - Removed all Rollup build tooling. 97 | - The library is 'self-contained' and does not require a separate build process (for now). 98 | - Updated the package.json to reflect the changes. 99 | 100 | ## v0.2.1 101 | 102 | - Fixed a minor 'import' example error in the README. 103 | - Old: import MycroDatabase from 'mycro-db' 104 | - New: import { MycroDatabase } from 'mycro-db 105 | 106 | ## v0.2.0 107 | 108 | - The collections system is now stable. 109 | - When you create a collection, it has its own in-memory space to save its objects. 110 | - Objects are still indexed using auto-generated IDs. 111 | - All collection-related information is also saved to disk. 112 | - No changes were made to the APIs, which still include Insert and Query for each collection, and Sync for the database. 113 | - Tests have been updated to reflect the changes. 114 | 115 | ## v0.1.3 116 | 117 | - Modified the type of the 'filter' parameter in db.collection.query. 118 | - Now, the IDE can provide 'intellisense' for the 'doc' that exists inside the collection. 119 | - Example: db.collection('users', {id: 0, name: "", age: 0}).query((doc) => doc.name === "John Doe") 120 | - The IDE knows that 'doc' is of type {id: number, name: string, age: number}. 121 | 122 | ## v0.1.2 123 | 124 | - When defining a collection, it now checks if the required arguments are being passed for collection creation. 125 | - There is no type checking on these arguments. 126 | - The implementation of 'saving collection schemas' to the on-disk database has begun. 127 | 128 | ## v0.1.1 129 | 130 | - Update README to reflect API changes. 131 | 132 | ## v0.1.0 133 | 134 | - Implemented the initial version of the Collections API. 135 | - Removed direct access to Insert and Query. 136 | - When defining a Collection, you should now pass (with a plain JavaScript object) what you want to be the Schema for that collection. 137 | - Example: db.collection('users', {id: 0, name: "", age: 0}) 138 | - This will ensure that when users access the Insert and Query methods using the collection, the IDE will know that the 'Document' in this collection has the type: {id: number, name: string, age: number}, and provide auto-completion (intellisense) for the user. 139 | - To use Insert and Query, you should first create a collection. 140 | - Example: const User = db.collection('users', {id: 0, name: "", age: 0}) 141 | - User.insert({name: "John Doe", age: 20}) 142 | - User.query((doc) => doc.name === "John Doe") 143 | - Sync remains at the database level. 144 | - Example: db.sync() 145 | - Tests have been modified in accordance with the above changes. 146 | 147 | ## v0.0.5 148 | 149 | - Added the Rollup package with some plugins for the project compilation process. 150 | - Modified the package.json to fix the library import issue in other projects. 151 | 152 | ## v0.0.4 153 | 154 | - Revamped the project README to include the current MycroDB API information. 155 | - Added the LICENSE file. 156 | 157 | ## v0.0.3 158 | 159 | - Added the .npmignore file to prevent unnecessary files from being included with the library during packaging. 160 | 161 | ## v0.0.2 162 | 163 | - Added the 'ava' package as a development dependency for testing. 164 | - Implemented the initial approach for the Database. 165 | - The library exports the 'MycroDatabase' class. 166 | - When constructing this class, it takes a path to the JSON file. 167 | - An object with 'Insert,' 'Query,' and 'Sync' functions is returned: 168 | - Insert: Receives a document (object) and inserts it (in memory) into the database. 169 | - Query: Receives an expression to be used as a filter (in a filter) on the database values. 170 | - Sync: Synchronizes the in-memory data with the on-disk file. 171 | - There are other private functions and properties that are not part of the MycroDatabase object's API: 172 | - __load 173 | -__save 174 | - __nextId 175 | -__filePath 176 | - __memory 177 | -__id 178 | 179 | ## v0.0.1 180 | 181 | - GitHub repository created with some configuration files and initial project structure. 182 | 183 | ## v0.0.0 184 | 185 | - Package published on npm. 186 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # MycroDB 📦 2 | 3 | [![Logo](/public/logo.png)](https://www.npmjs.com/package/mycro-db) 4 | 5 | [![Brazil Flag](/public/brazil.png) Documentation in Portuguese](https://diegiwg.github.io/mycro-db/pt) 6 | 7 | ## Project Overview 🚀 8 | 9 | MycroDB is a JavaScript library designed for managing Document Databases stored in a single JSON file or in memory. 10 | 11 | MycroDB is available as an NPM library, and you can find it at [https://www.npmjs.com/package/mycro-db](https://www.npmjs.com/package/mycro-db). 12 | 13 | ## Example Project 14 | 15 | To showcase how MycroDB works, we've developed a sample project that implements a Command Line Interface (CLI) for task management. For more information about this project, please visit its dedicated repository at [Todz](https://github.com/Diegiwg/todz). 16 | 17 | ## Installation 18 | 19 | To integrate MycroDB into your project, you can install it via npm (or other package managers): 20 | 21 | ```shell 22 | npm install mycro-db 23 | ``` 24 | 25 | ## MycroDB API 26 | 27 | To get started, import the 'MycroDatabase' class along with a 'Storage' class, and initialize both objects: 28 | 29 | ```javascript 30 | import { JsonStorage, MemoryStorage, MycroDatabase } from 'mycro-db'; 31 | 32 | // In-memory mode 33 | const inMemoryStorage = new MemoryStorage(); 34 | const db = new MycroDatabase(inMemoryStorage); 35 | 36 | // JSON file mode 37 | const jsonStorage = new JsonStorage('my_database.json'); 38 | const db = new MycroDatabase(jsonStorage); 39 | ``` 40 | 41 | ### Collections API 42 | 43 | To maintain organized data, the library employs a collection structure. Utilize collections to logically categorize your data. 44 | 45 | #### Define a Collection 46 | 47 | To create a collection, you need to provide a name, and optionally, you can include a model (an object with properties and their corresponding data types) to enhance IDE intellisense. 48 | 49 | ```javascript 50 | const User = db.collection('users', { name: String(), age: Number() }); 51 | ``` 52 | 53 | #### Insert a Document into a Collection 54 | 55 | To insert a document into a collection, you should supply a plain JavaScript object with values compatible with JSON. You can insert one or more documents in a single operation by passing an array of document objects. 56 | 57 | ```javascript 58 | User.insert([ 59 | { name: 'Alice', age: 28 }, 60 | { name: 'Bob', age: 30 } 61 | ]); 62 | ``` 63 | 64 | #### Update a Document in a Collection 65 | 66 | To update a document, provide an object containing the 'id' key with the document's ID to be updated, and the 'data' key containing an object with 'key: value' pairs to be updated in the document. The update is atomic, meaning that only the values provided in the object will be updated, while other values in the document remain unchanged. You can update one or more documents in a single operation by passing an array of document objects. 67 | 68 | ```javascript 69 | User.update([ 70 | { id: 1, data: { age: 45 } } 71 | ]); 72 | ``` 73 | 74 | #### Get a Document in a Collection 75 | 76 | To retrieve a document from a collection, provide an ID of the document. You can get one or more documents in a single operation by passing an array of IDs. 77 | 78 | ```javascript 79 | User.get([ 80 | 1, 5 81 | ]); 82 | ``` 83 | 84 | #### Query Documents in a Collection 85 | 86 | To query documents in a collection, provide a strategy (filter) function. If no filtering function is provided, all documents will be returned. The number of documents returned depends on the 'limit' parameter, and the offset parameter is used for 'pagination'. All parameters are optional. By default, the limit is 25, and the offset is 0. 87 | 88 | ```javascript 89 | const strategy = (user) => user.age > 21; 90 | const limit = 10; 91 | const offset = 0; 92 | 93 | User.query(strategy, limit, offset); 94 | ``` 95 | 96 | #### Remove a Document from a Collection 97 | 98 | To remove a document, provide an ID of the document. You can remove one or more documents in a single operation by passing an array of IDs. 99 | 100 | ```javascript 101 | User.remove([ 102 | 1, 5 103 | ]); 104 | ``` 105 | 106 | ## Built-in Storage Strategies 107 | 108 | The library supports the following storage strategies: 109 | 110 | ### In-Memory 111 | 112 | This is the simplest strategy, saving data in memory until the application reloads and all data is erased. 113 | 114 | ```javascript 115 | import { MemoryStorage } from 'mycro-db'; 116 | 117 | const storage = new MemoryStorage(); 118 | const db = new MycroDatabase(storage); 119 | ``` 120 | 121 | ### JSON 122 | 123 | This is the most commonly used strategy and is ideal for those requiring flexibility and persistence. You can provide a schema, but it is primarily used as a reference for IDE intellisense. 124 | 125 | ```javascript 126 | import { JsonStorage } from 'mycro-db'; 127 | 128 | const storage = new JsonStorage('my_database.json'); 129 | const db = new MycroDatabase(storage); 130 | ``` 131 | 132 | ### Typed JSON 133 | 134 | This strategy offers the same functionality as JSON, but it incorporates a 'Schema' for 'insert' and 'update' functions, ensuring that documents added to the database conform to the expected structure (no extra fields and correct data types). If an extra field or incorrect value is provided, an error is raised. 135 | 136 | ```javascript 137 | import { TypedJsonStorage } from 'mycro-db'; 138 | 139 | const storage = new TypedJsonStorage('my_database.json'); 140 | const db = new MycroDatabase(storage); 141 | 142 | const user = db.collection('users', { name: String(), age: Number() }); 143 | // Here, it is defined that a user has Name and Age fields, respectively a String and a Number. 144 | ``` 145 | 146 | ## Changes Log 147 | 148 | For a detailed history of changes to this project, please refer to the [changes.md](changes.md) file in the root directory. 149 | 150 | ## License 📜 151 | 152 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. 153 | -------------------------------------------------------------------------------- /docs/pt/changes.md: -------------------------------------------------------------------------------- 1 | # Arquivo de Rastreamento de Versão 2 | 3 | ## v1.2.5 4 | 5 | - Corrigido bug relacionado à sincronização entre disco e memória. 6 | 7 | ## v1.2.4 8 | 9 | - Corrigido o link do logotipo na documentação em português. 10 | - Lançada a versão com a correção no npm. 11 | 12 | ## v1.2.3 13 | 14 | - Adicionada uma categoria de documentação em português à página do GitHub. 15 | - Um link para esta documentação foi adicionado ao README. 16 | 17 | ## v1.2.2 18 | 19 | - Corrigido um bug no sistema de genéricos que garante a intellisense nas coleções. 20 | - Modificada a estrutura de arquivo de alterações. 21 | 22 | ## v1.2.1 23 | 24 | - Atualizado o README para adicionar uma referência à nova Estratégia de Armazenamento (TypedJson). 25 | 26 | ## v1.2.0 27 | 28 | - Adicionado um novo modelo de armazenamento: TypedJson. 29 | - Características: 30 | Agora, quando um esquema existe, todos os dados inseridos/atualizados são verificados. 31 | Se o tipo de um dado ou uma chave que não existe no esquema é fornecido no Documento, um erro será gerado. 32 | Casos complexos foram testados, como: { value: [ { key: String(), xxx: [ Number() ] } ], required: Boolean() }. 33 | - Dado este exemplo, em tempo de execução, cada documento será testado em busca dos seguintes requisitos: 34 | - required: se existir no Documento anterior, deve ser um booleano. 35 | - value: se existir no documento, deve ser um array. 36 | Cada valor dentro deste array deve ser um objeto: 37 | - key: se existir no objeto, deve ser uma string. 38 | - xxx: se existir no objeto, deve ser um array de números. 39 | Vários casos foram testados e, aparentemente, a função de validação '(utils/validateSchema.js)' está funcionando corretamente. 40 | 41 | ## v1.1.1 42 | 43 | - Corrigido o arquivo .npmignore. 44 | 45 | ## v1.1.0 46 | 47 | - A API de Armazenamento foi aprimorada com a opção de substituir as funções disponíveis na API de Coleções. 48 | - Isso visa principalmente permitir métodos mais complexos em Armazenamentos mais intricados. 49 | 50 | ## v1.0.1 51 | 52 | - Corrigido o arquivo .npmignore. 53 | 54 | ## v1.0.0 55 | 56 | - Reformulação de toda a API. 57 | - A biblioteca foi dividida em vários módulos. 58 | - Core 59 | - MycroDatabase: A classe principal da biblioteca, usada para construir o wrapper de acesso ao banco de dados. 60 | - Collection: Uma classe que representa uma coleção e fornece acesso aos seus métodos de manipulação. 61 | - Storage: 62 | - Memory: Uma classe que representa um banco de dados em memória. 63 | - JSON: Uma classe que representa um banco de dados baseado em disco no formato JSON. 64 | 65 | ## v0.4.1 66 | 67 | - Adicionado um 'site estático' usando as Páginas do Github. 68 | 69 | ## v0.4.0 70 | 71 | - Removido o antigo script de compilação. 72 | - 'insert' agora aceita vários documentos, tornando mais simples a inserção de vários documentos de uma vez. 73 | - Exemplo: `db.collection('users', {id: 0, name: "", age: 0}).insert([{name: "John Doe", age: 20}, {name: "Jane Doe, age: 30}])` 74 | - 'insert', 'update' e 'remove' agora retornam a lista de IDs relacionados aos documentos afetados (criados, modificados e removidos). 75 | - Melhorias gerais na validação de argumentos para funções. 76 | - Testes atualizados para refletir as mudanças. 77 | - Documentação do README atualizada. 78 | 79 | ## v0.3.2 80 | 81 | - Re-added the 'project overview' label in the README. 82 | 83 | ## v0.3.1 84 | 85 | - Added a Logo in the README. 86 | 87 | ## v0.3.0 88 | 89 | - Added Remove and Update methods to the Collections API. 90 | - Complete rewrite of the library's tests. 91 | - Each function is in its own file. 92 | - README has been updated to reflect the new changes. 93 | 94 | ## v0.2.2 95 | 96 | - Removed all Rollup build tooling. 97 | - The library is 'self-contained' and does not require a separate build process (for now). 98 | - Updated the package.json to reflect the changes. 99 | 100 | ## v0.2.1 101 | 102 | - Fixed a minor 'import' example error in the README. 103 | - Old: import MycroDatabase from 'mycro-db' 104 | - New: import { MycroDatabase } from 'mycro-db 105 | 106 | ## v0.2.0 107 | 108 | - The collections system is now stable. 109 | - When you create a collection, it has its own in-memory space to save its objects. 110 | - Objects are still indexed using auto-generated IDs. 111 | - All collection-related information is also saved to disk. 112 | - No changes were made to the APIs, which still include Insert and Query for each collection, and Sync for the database. 113 | - Tests have been updated to reflect the changes. 114 | 115 | ## v0.1.3 116 | 117 | - Modified the type of the 'filter' parameter in db.collection.query. 118 | - Now, the IDE can provide 'intellisense' for the 'doc' that exists inside the collection. 119 | - Example: db.collection('users', {id: 0, name: "", age: 0}).query((doc) => doc.name === "John Doe") 120 | - The IDE knows that 'doc' is of type {id: number, name: string, age: number}. 121 | 122 | ## v0.1.2 123 | 124 | - When defining a collection, it now checks if the required arguments are being passed for collection creation. 125 | - There is no type checking on these arguments. 126 | - The implementation of 'saving collection schemas' to the on-disk database has begun. 127 | 128 | ## v0.1.1 129 | 130 | - Update README to reflect API changes. 131 | 132 | ## v0.1.0 133 | 134 | - Implemented the initial version of the Collections API. 135 | - Removed direct access to Insert and Query. 136 | - When defining a Collection, you should now pass (with a plain JavaScript object) what you want to be the Schema for that collection. 137 | - Example: db.collection('users', {id: 0, name: "", age: 0}) 138 | - This will ensure that when users access the Insert and Query methods using the collection, the IDE will know that the 'Document' in this collection has the type: {id: number, name: string, age: number}, and provide auto-completion (intellisense) for the user. 139 | - To use Insert and Query, you should first create a collection. 140 | - Example: const User = db.collection('users', {id: 0, name: "", age: 0}) 141 | - User.insert({name: "John Doe", age: 20}) 142 | - User.query((doc) => doc.name === "John Doe") 143 | - Sync remains at the database level. 144 | - Example: db.sync() 145 | - Tests have been modified in accordance with the above changes. 146 | 147 | ## v0.0.5 148 | 149 | - Added the Rollup package with some plugins for the project compilation process. 150 | - Modified the package.json to fix the library import issue in other projects. 151 | 152 | ## v0.0.4 153 | 154 | - Revamped the project README to include the current MycroDB API information. 155 | - Added the LICENSE file. 156 | 157 | ## v0.0.3 158 | 159 | - Added the .npmignore file to prevent unnecessary files from being included with the library during packaging. 160 | 161 | ## v0.0.2 162 | 163 | - Added the 'ava' package as a development dependency for testing. 164 | - Implemented the initial approach for the Database. 165 | - The library exports the 'MycroDatabase' class. 166 | - When constructing this class, it takes a path to the JSON file. 167 | - An object with 'Insert,' 'Query,' and 'Sync' functions is returned: 168 | - Insert: Receives a document (object) and inserts it (in memory) into the database. 169 | - Query: Receives an expression to be used as a filter (in a filter) on the database values. 170 | - Sync: Synchronizes the in-memory data with the on-disk file. 171 | - There are other private functions and properties that are not part of the MycroDatabase object's API: 172 | - __load 173 | -__save 174 | - __nextId 175 | -__filePath 176 | - __memory 177 | -__id 178 | 179 | ## v0.0.1 180 | 181 | - GitHub repository created with some configuration files and initial project structure. 182 | 183 | ## v0.0.0 184 | 185 | - Package published on npm. 186 | -------------------------------------------------------------------------------- /docs/pt/index.md: -------------------------------------------------------------------------------- 1 | # MycroDB 📦 2 | 3 | [![Logo](../public/logo.png)](https://www.npmjs.com/package/mycro-db) 4 | 5 | [Documentação em Inglês](https://diegiwg.github.io/mycro-db) 6 | 7 | ## Visão Geral do Projeto 🚀 8 | 9 | MycroDB é uma biblioteca JavaScript projetada para gerenciar Bancos de Dados de Documentos armazenados em um único arquivo JSON ou na memória. 10 | 11 | MycroDB é publicado como uma biblioteca no NPM, que você pode encontrar em [https://www.npmjs.com/package/mycro-db](https://www.npmjs.com/package/mycro-db). 12 | 13 | ## Projeto de Exemplo 14 | 15 | Para demonstrar como o MycroDB funciona, desenvolvemos um projeto de exemplo que implementa uma Interface de Linha de Comando (CLI) para o gerenciamento de tarefas. Para obter mais informações sobre esse projeto, visite seu repositório dedicado em [Todz](https://github.com/Diegiwg/todz). 16 | 17 | ## Instalação 18 | 19 | Para integrar o MycroDB em seu projeto, você pode instalá-lo via npm (ou outros gerenciadores de pacotes): 20 | 21 | ```shell 22 | npm install mycro-db 23 | ``` 24 | 25 | ## API do MycroDB 26 | 27 | Para começar, importe a classe 'MycroDatabase' juntamente com uma classe 'Storage' e inicialize ambos os objetos: 28 | 29 | ```javascript 30 | import { JsonStorage, MemoryStorage, MycroDatabase } from 'mycro-db'; 31 | 32 | // Modo de memória 33 | const inMemoryStorage = new MemoryStorage(); 34 | const db = new MycroDatabase(inMemoryStorage); 35 | 36 | // Modo de arquivo JSON 37 | const jsonStorage = new JsonStorage('my_database.json'); 38 | const db = new MycroDatabase(jsonStorage); 39 | ``` 40 | 41 | ### API de Coleções 42 | 43 | Para manter os dados organizados, a biblioteca utiliza uma estrutura de coleções. Use coleções para categorizar logicamente seus dados. 44 | 45 | #### Definir uma Coleção 46 | 47 | Para criar uma coleção, você deve fornecer um nome e, opcionalmente, pode incluir um modelo (um objeto com propriedades e seus tipos de dados correspondentes) para melhorar a intellisense do IDE. 48 | 49 | ```javascript 50 | const User = db.collection('users', { name: String(), age: Number() }); 51 | ``` 52 | 53 | #### Inserir um Documento em uma Coleção 54 | 55 | Para inserir um documento em uma coleção, você deve fornecer um objeto JavaScript simples com valores compatíveis com JSON. Você pode inserir um ou mais documentos em uma única operação passando uma matriz de objetos de documentos. 56 | 57 | ```javascript 58 | User.insert([ 59 | { name: 'Alice', age: 28 }, 60 | { name: 'Bob', age: 30 } 61 | ]); 62 | ``` 63 | 64 | #### Atualizar um Documento em uma Coleção 65 | 66 | Para atualizar um documento, forneça um objeto contendo a chave 'id' com o ID do documento a ser atualizado e a chave 'data' contendo um objeto com os pares 'chave: valor' a serem atualizados no documento. A atualização é atômica, o que significa que apenas os valores fornecidos no objeto serão atualizados, enquanto os outros valores no documento permanecem inalterados. Você pode atualizar um ou mais documentos em uma única operação passando uma matriz de objetos de documentos. 67 | 68 | ```javascript 69 | User.update([ 70 | { id: 1, data: { age: 45 } } 71 | ]); 72 | ``` 73 | 74 | #### Obter um Documento em uma Coleção 75 | 76 | Para recuperar um documento de uma coleção, forneça um ID do documento. Você pode obter um ou mais documentos em uma única operação passando uma matriz de IDs. 77 | 78 | ```javascript 79 | User.get([ 80 | 1, 5 81 | ]); 82 | ``` 83 | 84 | #### Consultar Documentos em uma Coleção 85 | 86 | Para consultar documentos em uma coleção, forneça uma função de estratégia (filtro). Se nenhuma função de filtro for fornecida, todos os documentos serão retornados. A quantidade de documentos retornados depende do parâmetro 'limite', e o parâmetro de deslocamento é usado para 'paginação'. Todos os parâmetros são opcionais. Por padrão, o limite é 25 e o deslocamento é 0. 87 | 88 | ```javascript 89 | const estrategia = (usuário) => usuário.age > 21; 90 | const limite = 10; 91 | const deslocamento = 0; 92 | 93 | User.query(estrategia, limite, deslocamento); 94 | ``` 95 | 96 | #### Remover um Documento de uma Coleção 97 | 98 | Para remover um documento, forneça um ID do documento. Você pode remover um ou mais documentos em uma única operação passando uma matriz de IDs. 99 | 100 | ```javascript 101 | User.remove([ 102 | 1, 5 103 | ]); 104 | ``` 105 | 106 | ## Estratégias de Armazenamento Incorporadas 107 | 108 | A biblioteca suporta as seguintes estratégias de armazenamento: 109 | 110 | ### Na Memória 111 | 112 | Esta é a estratégia mais simples, salvando os dados na memória até que a aplicação seja recarregada e todos os dados sejam apagados. 113 | 114 | ```javascript 115 | import { MemoryStorage } from 'mycro-db'; 116 | 117 | const armazenamento = new MemoryStorage(); 118 | const db = new MycroDatabase(armazenamento); 119 | ``` 120 | 121 | ### JSON 122 | 123 | Esta é a estratégia mais comum e é ideal para aqueles que precisam de flexibilidade e persistência. Você pode fornecer um esquema, mas ele é principalmente usado como referência para a intellisense do IDE. 124 | 125 | ```javascript 126 | import { JsonStorage } from 'mycro-db'; 127 | 128 | const armazenamento = new JsonStorage('my_database.json'); 129 | const db = new MycroDatabase(armazenamento); 130 | ``` 131 | 132 | ### JSON Tipado 133 | 134 | Esta estratégia oferece a mesma funcionalidade do JSON, mas incorpora um 'Esquema' para as funções de 'inserção' e 'atualização', garantindo que os documentos adicionados ao banco de dados estejam de acordo com a estrutura esperada (sem campos extras e tipos de dados corretos). Se um campo extra ou um valor incorreto for fornecido, um erro será gerado. 135 | 136 | ```javascript 137 | import { TypedJsonStorage } from 'mycro-db'; 138 | 139 | const armazenamento = new TypedJsonStorage('my_database.json'); 140 | const db = new MycroDatabase(armazenamento); 141 | 142 | const usuário = db.collection('usuários', { nome: String(), idade: Number() }); 143 | // Aqui, é definido que um usuário possui campos Nome e Idade, respectivamente uma String e um Número. 144 | ``` 145 | 146 | ## Registro de Alterações 147 | 148 | Para obter um histórico detalhado das alterações neste projeto, consulte o arquivo [changes.md](changes.md) no diretório raiz. 149 | 150 | ## Licença 📜 151 | 152 | Este projeto está licenciado sob a Licença MIT. Consulte o arquivo [LICENSE](LICENSE) para obter mais detalhes. 153 | -------------------------------------------------------------------------------- /docs/public/brazil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Diegiwg/mycro-db/0d8b1b7141639478f810c8964ac7d649565e80b2/docs/public/brazil.png -------------------------------------------------------------------------------- /docs/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Diegiwg/mycro-db/0d8b1b7141639478f810c8964ac7d649565e80b2/docs/public/logo.png -------------------------------------------------------------------------------- /lib/core/Collection.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Checks the validity of a parameter and returns it. 3 | * 4 | * @param {any} param The parameter to be checked. 5 | * @return {Array} The valid parameter. 6 | */ 7 | function checkParam(param) { 8 | if (param == null || param === undefined) { 9 | throw new Error("The parameter is required."); 10 | } 11 | 12 | if (!Array.isArray(param)) { 13 | param = [param]; 14 | } 15 | 16 | return param; 17 | } 18 | 19 | /** 20 | * Inserts documents into the collection. 21 | * 22 | * @template Model 23 | * @param {import('../types.js').CollectionRef} ref The reference to the collection. 24 | * @param {Model} schema The schema for the collection. 25 | */ 26 | function insert(ref, schema) { 27 | /** 28 | * Inserts documents into the collection. 29 | * 30 | * @param {Model[]} docs The documents to be inserted. 31 | */ 32 | return (docs) => { 33 | docs = checkParam(docs); 34 | 35 | const operations = []; 36 | 37 | for (const doc of docs) { 38 | operations.push(() => { 39 | const docId = ref.memory.id++; 40 | 41 | doc.id = docId; 42 | 43 | ref.memory.documents[docId] = doc; 44 | }); 45 | } 46 | 47 | ref.sync(operations); 48 | }; 49 | } 50 | 51 | /** 52 | * Retrieves documents from the collection. 53 | * 54 | * @template Model 55 | * @param {import('../types.js').CollectionRef} ref The reference to the collection. 56 | * @param {Model} schema The schema for the collection. 57 | */ 58 | function get(ref, schema) { 59 | /** 60 | * Retrieves documents from the collection. 61 | * 62 | * @param {number[]} ids The ids of the documents to be retrieved. 63 | */ 64 | return (ids) => { 65 | ids = checkParam(ids); 66 | 67 | const file = ref.storage.read(); 68 | ref.memory = file["collections"][ref.identifier]; 69 | 70 | const docs = []; 71 | for (const id of ids) { 72 | if (!ref.memory.documents[id]) continue; 73 | 74 | docs.push(file["collections"][ref.identifier].documents[id]); 75 | } 76 | 77 | return docs; 78 | }; 79 | } 80 | 81 | /** 82 | * Removes documents from the collection. 83 | * 84 | * @template Model 85 | * @param {import('../types.js').CollectionRef} ref The reference to the collection. 86 | * @param {Model} schema The schema for the collection. 87 | */ 88 | function remove(ref, schema) { 89 | /** 90 | * Removes documents from the collection. 91 | * 92 | * @param {number[]} ids The ids of the documents to be removed. 93 | */ 94 | return (ids) => { 95 | ids = checkParam(ids); 96 | 97 | const file = ref.storage.read(); 98 | ref.memory = file["collections"][ref.identifier]; 99 | 100 | const operations = []; 101 | for (const id of ids) { 102 | if (!ref.memory.documents[id]) continue; 103 | 104 | operations.push(() => { 105 | delete ref.memory.documents[id]; 106 | }); 107 | } 108 | 109 | ref.sync(operations); 110 | }; 111 | } 112 | 113 | /** 114 | * Updates documents in the collection. 115 | * 116 | * @template Model 117 | * @param {import('../types.js').CollectionRef} ref The reference to the collection. 118 | * @param {Model} schema The schema for the collection. 119 | */ 120 | function update(ref, schema) { 121 | /** 122 | * Updates documents in the collection. 123 | * 124 | * @param {{id: number, data: Model}[]} orders The update orders to be applied. 125 | */ 126 | return (orders) => { 127 | orders = checkParam(orders); 128 | 129 | const file = ref.storage.read(); 130 | ref.memory = file["collections"][ref.identifier]; 131 | 132 | const operations = []; 133 | 134 | for (const order of orders) { 135 | if (!order.id || !order.data) { 136 | continue; 137 | } 138 | 139 | if (!ref.memory.documents[order.id]) { 140 | continue; 141 | } 142 | 143 | operations.push(() => { 144 | for (const key of Object.keys(order.data)) { 145 | ref.memory.documents[order.id][key] = order.data[key]; 146 | } 147 | }); 148 | } 149 | 150 | ref.sync(operations); 151 | }; 152 | } 153 | 154 | /** 155 | * Retrieves documents from the collection using a strategy (filter). 156 | * 157 | * @template Model 158 | * @param {import('../types.js').CollectionRef} ref The reference to the collection. 159 | * @param {Model} schema The schema for the collection. 160 | */ 161 | function query(ref, schema) { 162 | /** 163 | * Retrieves documents from the collection using a strategy (filter). 164 | * 165 | * @param {(doc: Model) => boolean} strategy The strategy to be used (optional). 166 | * @param {number} limit The number of documents to be retrieved (default: 25). 167 | * @param {number} offset The number of documents to be skipped (for pagination). 168 | */ 169 | return (strategy = null, limit = 25, offset = 0) => { 170 | const file = ref.storage.read(); 171 | const docs = file["collections"][ref.identifier].documents; 172 | const values = Object.values(docs); 173 | 174 | const result = strategy ? values.filter(strategy) : values; 175 | const limitResult = result.slice(offset, offset + limit); 176 | 177 | return { 178 | /** @type {Model[]} */ 179 | docs: limitResult, 180 | offset, 181 | limit, 182 | }; 183 | }; 184 | } 185 | 186 | /** 187 | * Retrieves the number of documents in the collection. 188 | * 189 | * @template Model 190 | * @param {import('../types.js').CollectionRef} ref The reference to the collection. 191 | * @param {Model} schema The schema for the collection. 192 | */ 193 | function count(ref, schema) { 194 | /** 195 | * Retrieves the number of documents in the collection. 196 | */ 197 | return () => { 198 | const file = ref.storage.read(); 199 | return Object.keys(file["collections"][ref.identifier].documents) 200 | .length; 201 | }; 202 | } 203 | 204 | /** 205 | * Crate a new collection if the identifier does not exist in the storage. 206 | * 207 | * @param {CollectionRef} ref The reference to the collection. 208 | */ 209 | function create(ref) { 210 | const file = ref.storage.read(); 211 | 212 | if (!Object.keys(file["collections"]).includes(ref.identifier)) { 213 | file["collections"][ref.identifier] = ref.memory; 214 | ref.storage.write(file); 215 | } 216 | } 217 | 218 | /** 219 | * Synchronizes the collection with the storage. 220 | * 221 | * @param {Function[]} operations The operations to be executed. 222 | */ 223 | function sync(ref) { 224 | /** 225 | * Synchronizes the collection with the storage. 226 | * 227 | * @param {Function[]} operations The operations to be executed. 228 | */ 229 | return (operations) => { 230 | operations = checkParam(operations); 231 | 232 | const file = ref.storage.read(); 233 | ref.memory = file["collections"][ref.identifier]; 234 | 235 | for (const operation of operations) { 236 | operation.call(this); 237 | } 238 | 239 | file["collections"][ref.identifier] = ref.memory; 240 | ref.storage.write(file); 241 | }; 242 | } 243 | 244 | export const DEFAULT_FUNCTIONS = { 245 | insert, 246 | get, 247 | remove, 248 | update, 249 | query, 250 | count, 251 | create, 252 | sync, 253 | 254 | // Utils 255 | checkParam, 256 | }; 257 | 258 | /** 259 | * Represents a collection of documents. 260 | * 261 | * @template Model The type of the documents in the collection. 262 | * @param {string} identifier The identifier for the collection. 263 | * @param {import('../types.js').StoragePlugin} storage The storage object for the collection. 264 | * @param {Model} schema The schema for the collection. 265 | */ 266 | export function Collection(identifier, storage, schema) { 267 | /** 268 | * @private 269 | * @type {object} 270 | * @property {number} id - The current ID for new documents. 271 | * @property {Model[]} documents - The collection of documents. 272 | */ 273 | this.memory = { 274 | id: 1, 275 | documents: {}, 276 | }; 277 | 278 | /** 279 | * @private 280 | * @type {string} 281 | * @description The identifier for the collection. 282 | */ 283 | this.identifier = identifier; 284 | 285 | /** 286 | * @private 287 | * @type {import('../types.js').StoragePlugin} 288 | */ 289 | this.storage = storage; 290 | 291 | /** 292 | * @private 293 | */ 294 | this.sync = storage.sync ? storage.sync(this, schema) : sync(this); 295 | 296 | /** 297 | * @public 298 | * Inserts documents into the collection. 299 | * @type {(docs: Model[]) => void} 300 | * @param {Model[]} docs The documents to be inserted. 301 | */ 302 | this.insert = storage.insert 303 | ? storage.insert(this, schema) 304 | : insert(this, schema); 305 | 306 | /** 307 | * @public 308 | * Retrieves documents from the collection. 309 | * @type {(number[]) => Model[]} 310 | * @param {number[]} ids The ids of the documents to be retrieved. 311 | */ 312 | this.get = storage.get ? storage.get(this, schema) : get(this, schema); 313 | 314 | /** 315 | * @public 316 | * Removes documents from the collection. 317 | * @type {(number[]) => void} 318 | * @param {number[]} ids The ids of the documents to be removed. 319 | */ 320 | this.remove = storage.remove 321 | ? storage.remove(this, schema) 322 | : remove(this, schema); 323 | 324 | /** 325 | * @public 326 | * Updates documents in the collection. 327 | * @param {number[]} ids The ids of the documents to be updated. 328 | * @param {{id: number, data: Model}[]} orders The update orders to be applied. 329 | */ 330 | this.update = storage.update 331 | ? storage.update(this, schema) 332 | : update(this, schema); 333 | 334 | /** 335 | * @public 336 | * Retrieves documents from the collection using a strategy (filter). 337 | * @type {(strategy?: (doc: Model) => boolean, limit?: number, offset?: number) => {docs: Model[]; offset: number; limit: number;}} 338 | * @param {(doc: Model) => boolean} strategy The strategy to be used (optional). 339 | * @param {number} limit The number of documents to be retrieved (default: 25). 340 | * @param {number} offset The number of documents to be skipped (for pagination). 341 | */ 342 | this.query = storage.query 343 | ? storage.query(this, schema) 344 | : query(this, schema); 345 | 346 | /** 347 | * @public 348 | * Retrieves the number of documents in the collection. 349 | * @type {() => number} 350 | */ 351 | this.count = storage.count 352 | ? storage.count(this, schema) 353 | : count(this, schema); 354 | 355 | /** 356 | * @private 357 | */ 358 | storage.create ? storage.create(this, schema) : create(this, schema); 359 | } 360 | -------------------------------------------------------------------------------- /lib/core/MycroDatabase.js: -------------------------------------------------------------------------------- 1 | import { Collection } from "./Collection.js"; 2 | 3 | /** 4 | * @typedef {Object} StoragePlugin 5 | * @property {Function} read The read function. 6 | * @property {Function} write The write function. 7 | */ 8 | 9 | /** 10 | * Represents a database. 11 | */ 12 | export class MycroDatabase { 13 | /** @private */ 14 | storage; 15 | 16 | /** 17 | * Initializes a new instance of the MycroDatabase class. 18 | * 19 | * @param {StoragePlugin} storage The storage plugin to be used. Must include 'read' and 'write' as functions. 20 | */ 21 | constructor(storage) { 22 | this.storage = storage; 23 | } 24 | 25 | /** 26 | * Creates a new collection with the given identifier and schema. 27 | * 28 | * @template Model 29 | * @param {string} identifier The identifier for the collection. 30 | * @param {Model} schema The schema for the collection. 31 | */ 32 | collection(identifier, schema = {}) { 33 | const col = new Collection(identifier, this.storage, schema); 34 | return col; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | import { MycroDatabase } from "./core/MycroDatabase.js"; 2 | 3 | import { JsonStorage } from "./storage/json.js"; 4 | import { MemoryStorage } from "./storage/memory.js"; 5 | import { TypedJsonStorage } from "./storage/typedJson.js"; 6 | 7 | export { JsonStorage, MemoryStorage, MycroDatabase, TypedJsonStorage }; 8 | -------------------------------------------------------------------------------- /lib/storage/json.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | 3 | import { createDirectoriesRecursively } from "../utils/createDirectoriesRecursively.js"; 4 | import { removeFileNameAndExtension } from "../utils/removeFileNameAndExtension.js"; 5 | 6 | export class JsonStorage { 7 | filePath; 8 | 9 | /** 10 | * A storage for operations that require data persistence and maintain a JSON file structure. 11 | * 12 | * @param {string} filePath Path to the file where the data will be stored. 13 | */ 14 | constructor(filePath) { 15 | this.filePath = filePath; 16 | 17 | this.bootstrap(); 18 | } 19 | 20 | /** @private */ 21 | bootstrap() { 22 | const dirPath = removeFileNameAndExtension(this.filePath); 23 | createDirectoriesRecursively(dirPath); 24 | 25 | if (!fs.existsSync(this.filePath)) { 26 | fs.writeFileSync(this.filePath, '{"collections": {}}'); 27 | } 28 | } 29 | 30 | /** @public */ 31 | read() { 32 | return JSON.parse(fs.readFileSync(this.filePath, "utf-8")); 33 | } 34 | 35 | /** @public */ 36 | write(data) { 37 | fs.writeFileSync(this.filePath, JSON.stringify(data)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/storage/memory.js: -------------------------------------------------------------------------------- 1 | export class MemoryStorage { 2 | /** @private */ 3 | memory; 4 | 5 | /** 6 | * A Storage utility for operations that do not require data persistence. 7 | */ 8 | constructor() { 9 | this.memory = { collections: {} }; 10 | } 11 | 12 | read() { 13 | return this.memory; 14 | } 15 | 16 | write(data) { 17 | this.memory = data; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/storage/typedJson.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | 3 | import { DEFAULT_FUNCTIONS } from "../core/Collection.js"; 4 | import { createDirectoriesRecursively } from "../utils/createDirectoriesRecursively.js"; 5 | import { removeFileNameAndExtension } from "../utils/removeFileNameAndExtension.js"; 6 | import { validateSchema } from "../utils/validateSchema.js"; 7 | 8 | export class TypedJsonStorage { 9 | filePath; 10 | 11 | /** 12 | * A storage for operations that require data persistence and maintain a JSON file structure. 13 | * Also has a built-in type checker, for the schema of the collections. 14 | * 15 | * @param {string} filePath Path to the file where the data will be stored. 16 | */ 17 | constructor(filePath) { 18 | this.filePath = filePath; 19 | 20 | this.bootstrap(); 21 | } 22 | 23 | /** @private */ 24 | bootstrap() { 25 | const dirPath = removeFileNameAndExtension(this.filePath); 26 | createDirectoriesRecursively(dirPath); 27 | 28 | if (!fs.existsSync(this.filePath)) { 29 | fs.writeFileSync(this.filePath, '{"collections": {}}'); 30 | } 31 | } 32 | 33 | /** @public */ 34 | read() { 35 | return JSON.parse(fs.readFileSync(this.filePath, "utf-8")); 36 | } 37 | 38 | /** @public */ 39 | write(data) { 40 | fs.writeFileSync(this.filePath, JSON.stringify(data)); 41 | } 42 | 43 | // Using the Extended Storage API for type checking 44 | 45 | /** 46 | * Inserts documents into the collection. 47 | * 48 | * @template Model 49 | * @param {import('../types.js').CollectionRef} ref The reference to the collection. 50 | * @param {Model} schema The schema for the collection. 51 | */ 52 | insert(ref, schema) { 53 | /** 54 | * Inserts documents into the collection. 55 | * 56 | * @param {Model[]} docs The documents to be inserted. 57 | */ 58 | return (docs) => { 59 | docs = DEFAULT_FUNCTIONS.checkParam(docs); 60 | 61 | for (let i = 0; i < docs.length; i++) { 62 | docs[i] = validateSchema(schema, docs[i]); 63 | } 64 | 65 | // Call the default function after checking the schema 66 | DEFAULT_FUNCTIONS.insert(ref, schema)(docs); 67 | }; 68 | } 69 | 70 | /** 71 | * Updates documents in the collection. 72 | * 73 | * @template Model 74 | * @param {import('../types.js').CollectionRef} ref The reference to the collection. 75 | * @param {Model} schema The schema for the collection. 76 | */ 77 | update(ref, schema) { 78 | /** 79 | * Updates documents in the collection. 80 | * 81 | * @param {{id: number, data: Model}[]} orders The update orders to be applied. 82 | */ 83 | return (orders) => { 84 | orders = DEFAULT_FUNCTIONS.checkParam(orders); 85 | 86 | for (let i = 0; i < orders.length; i++) { 87 | orders[i].data = validateSchema(schema, orders[i].data); 88 | } 89 | 90 | // Call the default function after checking the schema 91 | DEFAULT_FUNCTIONS.update(ref, schema)(orders); 92 | }; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /lib/types.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef StoragePlugin 3 | * @property {Function?} count - The count function. 4 | * @property {Function?} create - The create function. 5 | * @property {Function?} get - The get function. 6 | * @property {Function?} insert - The insert function. 7 | * @property {Function?} query - The query function. 8 | * @property {Function} read - The read function. 9 | * @property {Function?} remove - The remove function. 10 | * @property {Function?} sync - The sync function. 11 | * @property {Function?} update - The update function. 12 | * @property {Function} write - The write function. 13 | */ 14 | 15 | /** 16 | * @template Model The type of the documents in the collection 17 | * 18 | * Represents a collection of documents 19 | * @typedef CollectionRef 20 | * @property {string} identifier The identifier for the collection. 21 | * @property {StoragePlugin} storage The storage object for the collection. 22 | * @property {{id: number, documents: Object}} memory The memory object for the collection. 23 | */ 24 | 25 | export const _ = ""; 26 | -------------------------------------------------------------------------------- /lib/utils/createDirectoriesRecursively.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | 4 | /** 5 | * Creates directories recursively based on the provided full path. 6 | * 7 | * @param {string} fullPath The full path of the directory to be created. 8 | */ 9 | export function createDirectoriesRecursively(fullPath) { 10 | // Split the full path into individual directory names 11 | const dirs = fullPath.split(/\\|\//); 12 | 13 | let currentDir = ""; 14 | // Loop through each directory name and create the corresponding directory 15 | for (const dir of dirs) { 16 | // Append the current directory name to the current directory path 17 | currentDir = path.join(currentDir, dir); 18 | // Check if the current directory already exists 19 | if (!fs.existsSync(currentDir)) { 20 | // Create the current directory if it doesn't exist 21 | fs.mkdirSync(currentDir); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/utils/removeFileNameAndExtension.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | 3 | /** 4 | * Removes the file name and extension from the given file path. 5 | * 6 | * @param {string} filePath The file path. 7 | * @returns {string} The directory path. 8 | */ 9 | export function removeFileNameAndExtension(filePath) { 10 | // Parse the file path using the path module 11 | const parsedPath = path.parse(filePath); 12 | 13 | // Return the directory path 14 | return parsedPath.dir; 15 | } 16 | -------------------------------------------------------------------------------- /lib/utils/validateSchema.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Validates a document against a given schema. 3 | * 4 | * @param {Object} schema - The schema to validate against. 5 | * @param {Object} doc - The document to validate. 6 | * @throws {Error} Throws an error if the document is invalid. 7 | * @return {Object} Returns the validated document. 8 | */ 9 | export function validateSchema(schema, doc) { 10 | const keysInSchema = Object.keys(schema); 11 | 12 | for (const key of Object.keys(doc)) { 13 | if (Array.isArray(doc[key])) { 14 | const strictType = typeof schema[key][0]; 15 | 16 | for (let i = 0; i < doc[key].length; i++) { 17 | const docType = typeof doc[key][i]; 18 | 19 | if (docType !== strictType) { 20 | throw new Error( 21 | `Invalid type in [${key}] array: ${docType} is not a ${strictType}` 22 | ); 23 | } 24 | 25 | if (typeof doc[key][i] === "object" && doc[key][i] !== null) { 26 | validateSchema(schema[key][0], doc[key][i]); 27 | } 28 | } 29 | return; 30 | } 31 | 32 | if (typeof doc[key] === "object" && doc[key] !== null) { 33 | validateSchema(schema[key], doc[key]); 34 | continue; 35 | } 36 | 37 | if (typeof schema[key] !== typeof doc[key]) { 38 | throw new Error( 39 | `Invalid type for [${key}]: ${typeof doc[ 40 | key 41 | ]} is not a ${typeof schema[key]}` 42 | ); 43 | } 44 | 45 | if (!keysInSchema.includes(key)) { 46 | throw new Error(`Invalid key present in document: ${key}`); 47 | } 48 | } 49 | 50 | return doc; 51 | } 52 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mycro-db", 3 | "version": "1.2.5", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "mycro-db", 9 | "version": "1.2.5", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "ava": "^5.3.1" 13 | } 14 | }, 15 | "node_modules/@nodelib/fs.scandir": { 16 | "version": "2.1.5", 17 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 18 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 19 | "dev": true, 20 | "dependencies": { 21 | "@nodelib/fs.stat": "2.0.5", 22 | "run-parallel": "^1.1.9" 23 | }, 24 | "engines": { 25 | "node": ">= 8" 26 | } 27 | }, 28 | "node_modules/@nodelib/fs.stat": { 29 | "version": "2.0.5", 30 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 31 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 32 | "dev": true, 33 | "engines": { 34 | "node": ">= 8" 35 | } 36 | }, 37 | "node_modules/@nodelib/fs.walk": { 38 | "version": "1.2.8", 39 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 40 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 41 | "dev": true, 42 | "dependencies": { 43 | "@nodelib/fs.scandir": "2.1.5", 44 | "fastq": "^1.6.0" 45 | }, 46 | "engines": { 47 | "node": ">= 8" 48 | } 49 | }, 50 | "node_modules/acorn": { 51 | "version": "8.10.0", 52 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", 53 | "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", 54 | "dev": true, 55 | "bin": { 56 | "acorn": "bin/acorn" 57 | }, 58 | "engines": { 59 | "node": ">=0.4.0" 60 | } 61 | }, 62 | "node_modules/acorn-walk": { 63 | "version": "8.2.0", 64 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 65 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", 66 | "dev": true, 67 | "engines": { 68 | "node": ">=0.4.0" 69 | } 70 | }, 71 | "node_modules/aggregate-error": { 72 | "version": "4.0.1", 73 | "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", 74 | "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", 75 | "dev": true, 76 | "dependencies": { 77 | "clean-stack": "^4.0.0", 78 | "indent-string": "^5.0.0" 79 | }, 80 | "engines": { 81 | "node": ">=12" 82 | }, 83 | "funding": { 84 | "url": "https://github.com/sponsors/sindresorhus" 85 | } 86 | }, 87 | "node_modules/ansi-regex": { 88 | "version": "6.0.1", 89 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", 90 | "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", 91 | "dev": true, 92 | "engines": { 93 | "node": ">=12" 94 | }, 95 | "funding": { 96 | "url": "https://github.com/chalk/ansi-regex?sponsor=1" 97 | } 98 | }, 99 | "node_modules/ansi-styles": { 100 | "version": "6.2.1", 101 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", 102 | "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", 103 | "dev": true, 104 | "engines": { 105 | "node": ">=12" 106 | }, 107 | "funding": { 108 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 109 | } 110 | }, 111 | "node_modules/anymatch": { 112 | "version": "3.1.3", 113 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 114 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 115 | "dev": true, 116 | "dependencies": { 117 | "normalize-path": "^3.0.0", 118 | "picomatch": "^2.0.4" 119 | }, 120 | "engines": { 121 | "node": ">= 8" 122 | } 123 | }, 124 | "node_modules/argparse": { 125 | "version": "1.0.10", 126 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 127 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 128 | "dev": true, 129 | "dependencies": { 130 | "sprintf-js": "~1.0.2" 131 | } 132 | }, 133 | "node_modules/array-find-index": { 134 | "version": "1.0.2", 135 | "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", 136 | "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", 137 | "dev": true, 138 | "engines": { 139 | "node": ">=0.10.0" 140 | } 141 | }, 142 | "node_modules/arrgv": { 143 | "version": "1.0.2", 144 | "resolved": "https://registry.npmjs.org/arrgv/-/arrgv-1.0.2.tgz", 145 | "integrity": "sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==", 146 | "dev": true, 147 | "engines": { 148 | "node": ">=8.0.0" 149 | } 150 | }, 151 | "node_modules/arrify": { 152 | "version": "3.0.0", 153 | "resolved": "https://registry.npmjs.org/arrify/-/arrify-3.0.0.tgz", 154 | "integrity": "sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==", 155 | "dev": true, 156 | "engines": { 157 | "node": ">=12" 158 | }, 159 | "funding": { 160 | "url": "https://github.com/sponsors/sindresorhus" 161 | } 162 | }, 163 | "node_modules/ava": { 164 | "version": "5.3.1", 165 | "resolved": "https://registry.npmjs.org/ava/-/ava-5.3.1.tgz", 166 | "integrity": "sha512-Scv9a4gMOXB6+ni4toLuhAm9KYWEjsgBglJl+kMGI5+IVDt120CCDZyB5HNU9DjmLI2t4I0GbnxGLmmRfGTJGg==", 167 | "dev": true, 168 | "dependencies": { 169 | "acorn": "^8.8.2", 170 | "acorn-walk": "^8.2.0", 171 | "ansi-styles": "^6.2.1", 172 | "arrgv": "^1.0.2", 173 | "arrify": "^3.0.0", 174 | "callsites": "^4.0.0", 175 | "cbor": "^8.1.0", 176 | "chalk": "^5.2.0", 177 | "chokidar": "^3.5.3", 178 | "chunkd": "^2.0.1", 179 | "ci-info": "^3.8.0", 180 | "ci-parallel-vars": "^1.0.1", 181 | "clean-yaml-object": "^0.1.0", 182 | "cli-truncate": "^3.1.0", 183 | "code-excerpt": "^4.0.0", 184 | "common-path-prefix": "^3.0.0", 185 | "concordance": "^5.0.4", 186 | "currently-unhandled": "^0.4.1", 187 | "debug": "^4.3.4", 188 | "emittery": "^1.0.1", 189 | "figures": "^5.0.0", 190 | "globby": "^13.1.4", 191 | "ignore-by-default": "^2.1.0", 192 | "indent-string": "^5.0.0", 193 | "is-error": "^2.2.2", 194 | "is-plain-object": "^5.0.0", 195 | "is-promise": "^4.0.0", 196 | "matcher": "^5.0.0", 197 | "mem": "^9.0.2", 198 | "ms": "^2.1.3", 199 | "p-event": "^5.0.1", 200 | "p-map": "^5.5.0", 201 | "picomatch": "^2.3.1", 202 | "pkg-conf": "^4.0.0", 203 | "plur": "^5.1.0", 204 | "pretty-ms": "^8.0.0", 205 | "resolve-cwd": "^3.0.0", 206 | "stack-utils": "^2.0.6", 207 | "strip-ansi": "^7.0.1", 208 | "supertap": "^3.0.1", 209 | "temp-dir": "^3.0.0", 210 | "write-file-atomic": "^5.0.1", 211 | "yargs": "^17.7.2" 212 | }, 213 | "bin": { 214 | "ava": "entrypoints/cli.mjs" 215 | }, 216 | "engines": { 217 | "node": ">=14.19 <15 || >=16.15 <17 || >=18" 218 | }, 219 | "peerDependencies": { 220 | "@ava/typescript": "*" 221 | }, 222 | "peerDependenciesMeta": { 223 | "@ava/typescript": { 224 | "optional": true 225 | } 226 | } 227 | }, 228 | "node_modules/binary-extensions": { 229 | "version": "2.2.0", 230 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 231 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 232 | "dev": true, 233 | "engines": { 234 | "node": ">=8" 235 | } 236 | }, 237 | "node_modules/blueimp-md5": { 238 | "version": "2.19.0", 239 | "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.19.0.tgz", 240 | "integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==", 241 | "dev": true 242 | }, 243 | "node_modules/braces": { 244 | "version": "3.0.3", 245 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 246 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 247 | "dev": true, 248 | "dependencies": { 249 | "fill-range": "^7.1.1" 250 | }, 251 | "engines": { 252 | "node": ">=8" 253 | } 254 | }, 255 | "node_modules/callsites": { 256 | "version": "4.1.0", 257 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-4.1.0.tgz", 258 | "integrity": "sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw==", 259 | "dev": true, 260 | "engines": { 261 | "node": ">=12.20" 262 | }, 263 | "funding": { 264 | "url": "https://github.com/sponsors/sindresorhus" 265 | } 266 | }, 267 | "node_modules/cbor": { 268 | "version": "8.1.0", 269 | "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", 270 | "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", 271 | "dev": true, 272 | "dependencies": { 273 | "nofilter": "^3.1.0" 274 | }, 275 | "engines": { 276 | "node": ">=12.19" 277 | } 278 | }, 279 | "node_modules/chalk": { 280 | "version": "5.3.0", 281 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", 282 | "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", 283 | "dev": true, 284 | "engines": { 285 | "node": "^12.17.0 || ^14.13 || >=16.0.0" 286 | }, 287 | "funding": { 288 | "url": "https://github.com/chalk/chalk?sponsor=1" 289 | } 290 | }, 291 | "node_modules/chokidar": { 292 | "version": "3.5.3", 293 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 294 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 295 | "dev": true, 296 | "funding": [ 297 | { 298 | "type": "individual", 299 | "url": "https://paulmillr.com/funding/" 300 | } 301 | ], 302 | "dependencies": { 303 | "anymatch": "~3.1.2", 304 | "braces": "~3.0.2", 305 | "glob-parent": "~5.1.2", 306 | "is-binary-path": "~2.1.0", 307 | "is-glob": "~4.0.1", 308 | "normalize-path": "~3.0.0", 309 | "readdirp": "~3.6.0" 310 | }, 311 | "engines": { 312 | "node": ">= 8.10.0" 313 | }, 314 | "optionalDependencies": { 315 | "fsevents": "~2.3.2" 316 | } 317 | }, 318 | "node_modules/chunkd": { 319 | "version": "2.0.1", 320 | "resolved": "https://registry.npmjs.org/chunkd/-/chunkd-2.0.1.tgz", 321 | "integrity": "sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==", 322 | "dev": true 323 | }, 324 | "node_modules/ci-info": { 325 | "version": "3.8.0", 326 | "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", 327 | "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", 328 | "dev": true, 329 | "funding": [ 330 | { 331 | "type": "github", 332 | "url": "https://github.com/sponsors/sibiraj-s" 333 | } 334 | ], 335 | "engines": { 336 | "node": ">=8" 337 | } 338 | }, 339 | "node_modules/ci-parallel-vars": { 340 | "version": "1.0.1", 341 | "resolved": "https://registry.npmjs.org/ci-parallel-vars/-/ci-parallel-vars-1.0.1.tgz", 342 | "integrity": "sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==", 343 | "dev": true 344 | }, 345 | "node_modules/clean-stack": { 346 | "version": "4.2.0", 347 | "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", 348 | "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", 349 | "dev": true, 350 | "dependencies": { 351 | "escape-string-regexp": "5.0.0" 352 | }, 353 | "engines": { 354 | "node": ">=12" 355 | }, 356 | "funding": { 357 | "url": "https://github.com/sponsors/sindresorhus" 358 | } 359 | }, 360 | "node_modules/clean-yaml-object": { 361 | "version": "0.1.0", 362 | "resolved": "https://registry.npmjs.org/clean-yaml-object/-/clean-yaml-object-0.1.0.tgz", 363 | "integrity": "sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==", 364 | "dev": true, 365 | "engines": { 366 | "node": ">=0.10.0" 367 | } 368 | }, 369 | "node_modules/cli-truncate": { 370 | "version": "3.1.0", 371 | "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", 372 | "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", 373 | "dev": true, 374 | "dependencies": { 375 | "slice-ansi": "^5.0.0", 376 | "string-width": "^5.0.0" 377 | }, 378 | "engines": { 379 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 380 | }, 381 | "funding": { 382 | "url": "https://github.com/sponsors/sindresorhus" 383 | } 384 | }, 385 | "node_modules/cliui": { 386 | "version": "8.0.1", 387 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", 388 | "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", 389 | "dev": true, 390 | "dependencies": { 391 | "string-width": "^4.2.0", 392 | "strip-ansi": "^6.0.1", 393 | "wrap-ansi": "^7.0.0" 394 | }, 395 | "engines": { 396 | "node": ">=12" 397 | } 398 | }, 399 | "node_modules/cliui/node_modules/ansi-regex": { 400 | "version": "5.0.1", 401 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 402 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 403 | "dev": true, 404 | "engines": { 405 | "node": ">=8" 406 | } 407 | }, 408 | "node_modules/cliui/node_modules/emoji-regex": { 409 | "version": "8.0.0", 410 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 411 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 412 | "dev": true 413 | }, 414 | "node_modules/cliui/node_modules/is-fullwidth-code-point": { 415 | "version": "3.0.0", 416 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 417 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 418 | "dev": true, 419 | "engines": { 420 | "node": ">=8" 421 | } 422 | }, 423 | "node_modules/cliui/node_modules/string-width": { 424 | "version": "4.2.3", 425 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 426 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 427 | "dev": true, 428 | "dependencies": { 429 | "emoji-regex": "^8.0.0", 430 | "is-fullwidth-code-point": "^3.0.0", 431 | "strip-ansi": "^6.0.1" 432 | }, 433 | "engines": { 434 | "node": ">=8" 435 | } 436 | }, 437 | "node_modules/cliui/node_modules/strip-ansi": { 438 | "version": "6.0.1", 439 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 440 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 441 | "dev": true, 442 | "dependencies": { 443 | "ansi-regex": "^5.0.1" 444 | }, 445 | "engines": { 446 | "node": ">=8" 447 | } 448 | }, 449 | "node_modules/code-excerpt": { 450 | "version": "4.0.0", 451 | "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", 452 | "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==", 453 | "dev": true, 454 | "dependencies": { 455 | "convert-to-spaces": "^2.0.1" 456 | }, 457 | "engines": { 458 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 459 | } 460 | }, 461 | "node_modules/color-convert": { 462 | "version": "2.0.1", 463 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 464 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 465 | "dev": true, 466 | "dependencies": { 467 | "color-name": "~1.1.4" 468 | }, 469 | "engines": { 470 | "node": ">=7.0.0" 471 | } 472 | }, 473 | "node_modules/color-name": { 474 | "version": "1.1.4", 475 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 476 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 477 | "dev": true 478 | }, 479 | "node_modules/common-path-prefix": { 480 | "version": "3.0.0", 481 | "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", 482 | "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", 483 | "dev": true 484 | }, 485 | "node_modules/concordance": { 486 | "version": "5.0.4", 487 | "resolved": "https://registry.npmjs.org/concordance/-/concordance-5.0.4.tgz", 488 | "integrity": "sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==", 489 | "dev": true, 490 | "dependencies": { 491 | "date-time": "^3.1.0", 492 | "esutils": "^2.0.3", 493 | "fast-diff": "^1.2.0", 494 | "js-string-escape": "^1.0.1", 495 | "lodash": "^4.17.15", 496 | "md5-hex": "^3.0.1", 497 | "semver": "^7.3.2", 498 | "well-known-symbols": "^2.0.0" 499 | }, 500 | "engines": { 501 | "node": ">=10.18.0 <11 || >=12.14.0 <13 || >=14" 502 | } 503 | }, 504 | "node_modules/convert-to-spaces": { 505 | "version": "2.0.1", 506 | "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", 507 | "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", 508 | "dev": true, 509 | "engines": { 510 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 511 | } 512 | }, 513 | "node_modules/currently-unhandled": { 514 | "version": "0.4.1", 515 | "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", 516 | "integrity": "sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==", 517 | "dev": true, 518 | "dependencies": { 519 | "array-find-index": "^1.0.1" 520 | }, 521 | "engines": { 522 | "node": ">=0.10.0" 523 | } 524 | }, 525 | "node_modules/date-time": { 526 | "version": "3.1.0", 527 | "resolved": "https://registry.npmjs.org/date-time/-/date-time-3.1.0.tgz", 528 | "integrity": "sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==", 529 | "dev": true, 530 | "dependencies": { 531 | "time-zone": "^1.0.0" 532 | }, 533 | "engines": { 534 | "node": ">=6" 535 | } 536 | }, 537 | "node_modules/debug": { 538 | "version": "4.3.4", 539 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 540 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 541 | "dev": true, 542 | "dependencies": { 543 | "ms": "2.1.2" 544 | }, 545 | "engines": { 546 | "node": ">=6.0" 547 | }, 548 | "peerDependenciesMeta": { 549 | "supports-color": { 550 | "optional": true 551 | } 552 | } 553 | }, 554 | "node_modules/debug/node_modules/ms": { 555 | "version": "2.1.2", 556 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 557 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 558 | "dev": true 559 | }, 560 | "node_modules/dir-glob": { 561 | "version": "3.0.1", 562 | "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", 563 | "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", 564 | "dev": true, 565 | "dependencies": { 566 | "path-type": "^4.0.0" 567 | }, 568 | "engines": { 569 | "node": ">=8" 570 | } 571 | }, 572 | "node_modules/eastasianwidth": { 573 | "version": "0.2.0", 574 | "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", 575 | "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", 576 | "dev": true 577 | }, 578 | "node_modules/emittery": { 579 | "version": "1.0.1", 580 | "resolved": "https://registry.npmjs.org/emittery/-/emittery-1.0.1.tgz", 581 | "integrity": "sha512-2ID6FdrMD9KDLldGesP6317G78K7km/kMcwItRtVFva7I/cSEOIaLpewaUb+YLXVwdAp3Ctfxh/V5zIl1sj7dQ==", 582 | "dev": true, 583 | "engines": { 584 | "node": ">=14.16" 585 | }, 586 | "funding": { 587 | "url": "https://github.com/sindresorhus/emittery?sponsor=1" 588 | } 589 | }, 590 | "node_modules/emoji-regex": { 591 | "version": "9.2.2", 592 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", 593 | "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", 594 | "dev": true 595 | }, 596 | "node_modules/escalade": { 597 | "version": "3.1.1", 598 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 599 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 600 | "dev": true, 601 | "engines": { 602 | "node": ">=6" 603 | } 604 | }, 605 | "node_modules/escape-string-regexp": { 606 | "version": "5.0.0", 607 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", 608 | "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", 609 | "dev": true, 610 | "engines": { 611 | "node": ">=12" 612 | }, 613 | "funding": { 614 | "url": "https://github.com/sponsors/sindresorhus" 615 | } 616 | }, 617 | "node_modules/esprima": { 618 | "version": "4.0.1", 619 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 620 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 621 | "dev": true, 622 | "bin": { 623 | "esparse": "bin/esparse.js", 624 | "esvalidate": "bin/esvalidate.js" 625 | }, 626 | "engines": { 627 | "node": ">=4" 628 | } 629 | }, 630 | "node_modules/esutils": { 631 | "version": "2.0.3", 632 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 633 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 634 | "dev": true, 635 | "engines": { 636 | "node": ">=0.10.0" 637 | } 638 | }, 639 | "node_modules/fast-diff": { 640 | "version": "1.3.0", 641 | "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", 642 | "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", 643 | "dev": true 644 | }, 645 | "node_modules/fast-glob": { 646 | "version": "3.3.1", 647 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", 648 | "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", 649 | "dev": true, 650 | "dependencies": { 651 | "@nodelib/fs.stat": "^2.0.2", 652 | "@nodelib/fs.walk": "^1.2.3", 653 | "glob-parent": "^5.1.2", 654 | "merge2": "^1.3.0", 655 | "micromatch": "^4.0.4" 656 | }, 657 | "engines": { 658 | "node": ">=8.6.0" 659 | } 660 | }, 661 | "node_modules/fastq": { 662 | "version": "1.15.0", 663 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", 664 | "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", 665 | "dev": true, 666 | "dependencies": { 667 | "reusify": "^1.0.4" 668 | } 669 | }, 670 | "node_modules/figures": { 671 | "version": "5.0.0", 672 | "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", 673 | "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", 674 | "dev": true, 675 | "dependencies": { 676 | "escape-string-regexp": "^5.0.0", 677 | "is-unicode-supported": "^1.2.0" 678 | }, 679 | "engines": { 680 | "node": ">=14" 681 | }, 682 | "funding": { 683 | "url": "https://github.com/sponsors/sindresorhus" 684 | } 685 | }, 686 | "node_modules/fill-range": { 687 | "version": "7.1.1", 688 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 689 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 690 | "dev": true, 691 | "dependencies": { 692 | "to-regex-range": "^5.0.1" 693 | }, 694 | "engines": { 695 | "node": ">=8" 696 | } 697 | }, 698 | "node_modules/find-up": { 699 | "version": "6.3.0", 700 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", 701 | "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", 702 | "dev": true, 703 | "dependencies": { 704 | "locate-path": "^7.1.0", 705 | "path-exists": "^5.0.0" 706 | }, 707 | "engines": { 708 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 709 | }, 710 | "funding": { 711 | "url": "https://github.com/sponsors/sindresorhus" 712 | } 713 | }, 714 | "node_modules/fsevents": { 715 | "version": "2.3.3", 716 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 717 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 718 | "dev": true, 719 | "hasInstallScript": true, 720 | "optional": true, 721 | "os": [ 722 | "darwin" 723 | ], 724 | "engines": { 725 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 726 | } 727 | }, 728 | "node_modules/get-caller-file": { 729 | "version": "2.0.5", 730 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 731 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 732 | "dev": true, 733 | "engines": { 734 | "node": "6.* || 8.* || >= 10.*" 735 | } 736 | }, 737 | "node_modules/glob-parent": { 738 | "version": "5.1.2", 739 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 740 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 741 | "dev": true, 742 | "dependencies": { 743 | "is-glob": "^4.0.1" 744 | }, 745 | "engines": { 746 | "node": ">= 6" 747 | } 748 | }, 749 | "node_modules/globby": { 750 | "version": "13.2.2", 751 | "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", 752 | "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", 753 | "dev": true, 754 | "dependencies": { 755 | "dir-glob": "^3.0.1", 756 | "fast-glob": "^3.3.0", 757 | "ignore": "^5.2.4", 758 | "merge2": "^1.4.1", 759 | "slash": "^4.0.0" 760 | }, 761 | "engines": { 762 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 763 | }, 764 | "funding": { 765 | "url": "https://github.com/sponsors/sindresorhus" 766 | } 767 | }, 768 | "node_modules/ignore": { 769 | "version": "5.2.4", 770 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", 771 | "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", 772 | "dev": true, 773 | "engines": { 774 | "node": ">= 4" 775 | } 776 | }, 777 | "node_modules/ignore-by-default": { 778 | "version": "2.1.0", 779 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-2.1.0.tgz", 780 | "integrity": "sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==", 781 | "dev": true, 782 | "engines": { 783 | "node": ">=10 <11 || >=12 <13 || >=14" 784 | } 785 | }, 786 | "node_modules/imurmurhash": { 787 | "version": "0.1.4", 788 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 789 | "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", 790 | "dev": true, 791 | "engines": { 792 | "node": ">=0.8.19" 793 | } 794 | }, 795 | "node_modules/indent-string": { 796 | "version": "5.0.0", 797 | "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", 798 | "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", 799 | "dev": true, 800 | "engines": { 801 | "node": ">=12" 802 | }, 803 | "funding": { 804 | "url": "https://github.com/sponsors/sindresorhus" 805 | } 806 | }, 807 | "node_modules/irregular-plurals": { 808 | "version": "3.5.0", 809 | "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.5.0.tgz", 810 | "integrity": "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==", 811 | "dev": true, 812 | "engines": { 813 | "node": ">=8" 814 | } 815 | }, 816 | "node_modules/is-binary-path": { 817 | "version": "2.1.0", 818 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 819 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 820 | "dev": true, 821 | "dependencies": { 822 | "binary-extensions": "^2.0.0" 823 | }, 824 | "engines": { 825 | "node": ">=8" 826 | } 827 | }, 828 | "node_modules/is-error": { 829 | "version": "2.2.2", 830 | "resolved": "https://registry.npmjs.org/is-error/-/is-error-2.2.2.tgz", 831 | "integrity": "sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==", 832 | "dev": true 833 | }, 834 | "node_modules/is-extglob": { 835 | "version": "2.1.1", 836 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 837 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 838 | "dev": true, 839 | "engines": { 840 | "node": ">=0.10.0" 841 | } 842 | }, 843 | "node_modules/is-fullwidth-code-point": { 844 | "version": "4.0.0", 845 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", 846 | "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", 847 | "dev": true, 848 | "engines": { 849 | "node": ">=12" 850 | }, 851 | "funding": { 852 | "url": "https://github.com/sponsors/sindresorhus" 853 | } 854 | }, 855 | "node_modules/is-glob": { 856 | "version": "4.0.3", 857 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 858 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 859 | "dev": true, 860 | "dependencies": { 861 | "is-extglob": "^2.1.1" 862 | }, 863 | "engines": { 864 | "node": ">=0.10.0" 865 | } 866 | }, 867 | "node_modules/is-number": { 868 | "version": "7.0.0", 869 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 870 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 871 | "dev": true, 872 | "engines": { 873 | "node": ">=0.12.0" 874 | } 875 | }, 876 | "node_modules/is-plain-object": { 877 | "version": "5.0.0", 878 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", 879 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", 880 | "dev": true, 881 | "engines": { 882 | "node": ">=0.10.0" 883 | } 884 | }, 885 | "node_modules/is-promise": { 886 | "version": "4.0.0", 887 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", 888 | "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", 889 | "dev": true 890 | }, 891 | "node_modules/is-unicode-supported": { 892 | "version": "1.3.0", 893 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", 894 | "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", 895 | "dev": true, 896 | "engines": { 897 | "node": ">=12" 898 | }, 899 | "funding": { 900 | "url": "https://github.com/sponsors/sindresorhus" 901 | } 902 | }, 903 | "node_modules/js-string-escape": { 904 | "version": "1.0.1", 905 | "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", 906 | "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", 907 | "dev": true, 908 | "engines": { 909 | "node": ">= 0.8" 910 | } 911 | }, 912 | "node_modules/js-yaml": { 913 | "version": "3.14.1", 914 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", 915 | "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", 916 | "dev": true, 917 | "dependencies": { 918 | "argparse": "^1.0.7", 919 | "esprima": "^4.0.0" 920 | }, 921 | "bin": { 922 | "js-yaml": "bin/js-yaml.js" 923 | } 924 | }, 925 | "node_modules/load-json-file": { 926 | "version": "7.0.1", 927 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-7.0.1.tgz", 928 | "integrity": "sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==", 929 | "dev": true, 930 | "engines": { 931 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 932 | }, 933 | "funding": { 934 | "url": "https://github.com/sponsors/sindresorhus" 935 | } 936 | }, 937 | "node_modules/locate-path": { 938 | "version": "7.2.0", 939 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", 940 | "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", 941 | "dev": true, 942 | "dependencies": { 943 | "p-locate": "^6.0.0" 944 | }, 945 | "engines": { 946 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 947 | }, 948 | "funding": { 949 | "url": "https://github.com/sponsors/sindresorhus" 950 | } 951 | }, 952 | "node_modules/lodash": { 953 | "version": "4.17.21", 954 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 955 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 956 | "dev": true 957 | }, 958 | "node_modules/lru-cache": { 959 | "version": "6.0.0", 960 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 961 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 962 | "dev": true, 963 | "dependencies": { 964 | "yallist": "^4.0.0" 965 | }, 966 | "engines": { 967 | "node": ">=10" 968 | } 969 | }, 970 | "node_modules/map-age-cleaner": { 971 | "version": "0.1.3", 972 | "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", 973 | "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", 974 | "dev": true, 975 | "dependencies": { 976 | "p-defer": "^1.0.0" 977 | }, 978 | "engines": { 979 | "node": ">=6" 980 | } 981 | }, 982 | "node_modules/matcher": { 983 | "version": "5.0.0", 984 | "resolved": "https://registry.npmjs.org/matcher/-/matcher-5.0.0.tgz", 985 | "integrity": "sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==", 986 | "dev": true, 987 | "dependencies": { 988 | "escape-string-regexp": "^5.0.0" 989 | }, 990 | "engines": { 991 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 992 | }, 993 | "funding": { 994 | "url": "https://github.com/sponsors/sindresorhus" 995 | } 996 | }, 997 | "node_modules/md5-hex": { 998 | "version": "3.0.1", 999 | "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-3.0.1.tgz", 1000 | "integrity": "sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==", 1001 | "dev": true, 1002 | "dependencies": { 1003 | "blueimp-md5": "^2.10.0" 1004 | }, 1005 | "engines": { 1006 | "node": ">=8" 1007 | } 1008 | }, 1009 | "node_modules/mem": { 1010 | "version": "9.0.2", 1011 | "resolved": "https://registry.npmjs.org/mem/-/mem-9.0.2.tgz", 1012 | "integrity": "sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==", 1013 | "dev": true, 1014 | "dependencies": { 1015 | "map-age-cleaner": "^0.1.3", 1016 | "mimic-fn": "^4.0.0" 1017 | }, 1018 | "engines": { 1019 | "node": ">=12.20" 1020 | }, 1021 | "funding": { 1022 | "url": "https://github.com/sindresorhus/mem?sponsor=1" 1023 | } 1024 | }, 1025 | "node_modules/merge2": { 1026 | "version": "1.4.1", 1027 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 1028 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 1029 | "dev": true, 1030 | "engines": { 1031 | "node": ">= 8" 1032 | } 1033 | }, 1034 | "node_modules/micromatch": { 1035 | "version": "4.0.5", 1036 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", 1037 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 1038 | "dev": true, 1039 | "dependencies": { 1040 | "braces": "^3.0.2", 1041 | "picomatch": "^2.3.1" 1042 | }, 1043 | "engines": { 1044 | "node": ">=8.6" 1045 | } 1046 | }, 1047 | "node_modules/mimic-fn": { 1048 | "version": "4.0.0", 1049 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", 1050 | "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", 1051 | "dev": true, 1052 | "engines": { 1053 | "node": ">=12" 1054 | }, 1055 | "funding": { 1056 | "url": "https://github.com/sponsors/sindresorhus" 1057 | } 1058 | }, 1059 | "node_modules/ms": { 1060 | "version": "2.1.3", 1061 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1062 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1063 | "dev": true 1064 | }, 1065 | "node_modules/nofilter": { 1066 | "version": "3.1.0", 1067 | "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", 1068 | "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", 1069 | "dev": true, 1070 | "engines": { 1071 | "node": ">=12.19" 1072 | } 1073 | }, 1074 | "node_modules/normalize-path": { 1075 | "version": "3.0.0", 1076 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1077 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1078 | "dev": true, 1079 | "engines": { 1080 | "node": ">=0.10.0" 1081 | } 1082 | }, 1083 | "node_modules/p-defer": { 1084 | "version": "1.0.0", 1085 | "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", 1086 | "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", 1087 | "dev": true, 1088 | "engines": { 1089 | "node": ">=4" 1090 | } 1091 | }, 1092 | "node_modules/p-event": { 1093 | "version": "5.0.1", 1094 | "resolved": "https://registry.npmjs.org/p-event/-/p-event-5.0.1.tgz", 1095 | "integrity": "sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==", 1096 | "dev": true, 1097 | "dependencies": { 1098 | "p-timeout": "^5.0.2" 1099 | }, 1100 | "engines": { 1101 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 1102 | }, 1103 | "funding": { 1104 | "url": "https://github.com/sponsors/sindresorhus" 1105 | } 1106 | }, 1107 | "node_modules/p-limit": { 1108 | "version": "4.0.0", 1109 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", 1110 | "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", 1111 | "dev": true, 1112 | "dependencies": { 1113 | "yocto-queue": "^1.0.0" 1114 | }, 1115 | "engines": { 1116 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 1117 | }, 1118 | "funding": { 1119 | "url": "https://github.com/sponsors/sindresorhus" 1120 | } 1121 | }, 1122 | "node_modules/p-locate": { 1123 | "version": "6.0.0", 1124 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", 1125 | "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", 1126 | "dev": true, 1127 | "dependencies": { 1128 | "p-limit": "^4.0.0" 1129 | }, 1130 | "engines": { 1131 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 1132 | }, 1133 | "funding": { 1134 | "url": "https://github.com/sponsors/sindresorhus" 1135 | } 1136 | }, 1137 | "node_modules/p-map": { 1138 | "version": "5.5.0", 1139 | "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", 1140 | "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", 1141 | "dev": true, 1142 | "dependencies": { 1143 | "aggregate-error": "^4.0.0" 1144 | }, 1145 | "engines": { 1146 | "node": ">=12" 1147 | }, 1148 | "funding": { 1149 | "url": "https://github.com/sponsors/sindresorhus" 1150 | } 1151 | }, 1152 | "node_modules/p-timeout": { 1153 | "version": "5.1.0", 1154 | "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz", 1155 | "integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==", 1156 | "dev": true, 1157 | "engines": { 1158 | "node": ">=12" 1159 | }, 1160 | "funding": { 1161 | "url": "https://github.com/sponsors/sindresorhus" 1162 | } 1163 | }, 1164 | "node_modules/parse-ms": { 1165 | "version": "3.0.0", 1166 | "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-3.0.0.tgz", 1167 | "integrity": "sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==", 1168 | "dev": true, 1169 | "engines": { 1170 | "node": ">=12" 1171 | }, 1172 | "funding": { 1173 | "url": "https://github.com/sponsors/sindresorhus" 1174 | } 1175 | }, 1176 | "node_modules/path-exists": { 1177 | "version": "5.0.0", 1178 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", 1179 | "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", 1180 | "dev": true, 1181 | "engines": { 1182 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 1183 | } 1184 | }, 1185 | "node_modules/path-type": { 1186 | "version": "4.0.0", 1187 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", 1188 | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", 1189 | "dev": true, 1190 | "engines": { 1191 | "node": ">=8" 1192 | } 1193 | }, 1194 | "node_modules/picomatch": { 1195 | "version": "2.3.1", 1196 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1197 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1198 | "dev": true, 1199 | "engines": { 1200 | "node": ">=8.6" 1201 | }, 1202 | "funding": { 1203 | "url": "https://github.com/sponsors/jonschlinkert" 1204 | } 1205 | }, 1206 | "node_modules/pkg-conf": { 1207 | "version": "4.0.0", 1208 | "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-4.0.0.tgz", 1209 | "integrity": "sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==", 1210 | "dev": true, 1211 | "dependencies": { 1212 | "find-up": "^6.0.0", 1213 | "load-json-file": "^7.0.0" 1214 | }, 1215 | "engines": { 1216 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 1217 | }, 1218 | "funding": { 1219 | "url": "https://github.com/sponsors/sindresorhus" 1220 | } 1221 | }, 1222 | "node_modules/plur": { 1223 | "version": "5.1.0", 1224 | "resolved": "https://registry.npmjs.org/plur/-/plur-5.1.0.tgz", 1225 | "integrity": "sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==", 1226 | "dev": true, 1227 | "dependencies": { 1228 | "irregular-plurals": "^3.3.0" 1229 | }, 1230 | "engines": { 1231 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 1232 | }, 1233 | "funding": { 1234 | "url": "https://github.com/sponsors/sindresorhus" 1235 | } 1236 | }, 1237 | "node_modules/pretty-ms": { 1238 | "version": "8.0.0", 1239 | "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-8.0.0.tgz", 1240 | "integrity": "sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==", 1241 | "dev": true, 1242 | "dependencies": { 1243 | "parse-ms": "^3.0.0" 1244 | }, 1245 | "engines": { 1246 | "node": ">=14.16" 1247 | }, 1248 | "funding": { 1249 | "url": "https://github.com/sponsors/sindresorhus" 1250 | } 1251 | }, 1252 | "node_modules/queue-microtask": { 1253 | "version": "1.2.3", 1254 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 1255 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 1256 | "dev": true, 1257 | "funding": [ 1258 | { 1259 | "type": "github", 1260 | "url": "https://github.com/sponsors/feross" 1261 | }, 1262 | { 1263 | "type": "patreon", 1264 | "url": "https://www.patreon.com/feross" 1265 | }, 1266 | { 1267 | "type": "consulting", 1268 | "url": "https://feross.org/support" 1269 | } 1270 | ] 1271 | }, 1272 | "node_modules/readdirp": { 1273 | "version": "3.6.0", 1274 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1275 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1276 | "dev": true, 1277 | "dependencies": { 1278 | "picomatch": "^2.2.1" 1279 | }, 1280 | "engines": { 1281 | "node": ">=8.10.0" 1282 | } 1283 | }, 1284 | "node_modules/require-directory": { 1285 | "version": "2.1.1", 1286 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1287 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 1288 | "dev": true, 1289 | "engines": { 1290 | "node": ">=0.10.0" 1291 | } 1292 | }, 1293 | "node_modules/resolve-cwd": { 1294 | "version": "3.0.0", 1295 | "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", 1296 | "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", 1297 | "dev": true, 1298 | "dependencies": { 1299 | "resolve-from": "^5.0.0" 1300 | }, 1301 | "engines": { 1302 | "node": ">=8" 1303 | } 1304 | }, 1305 | "node_modules/resolve-from": { 1306 | "version": "5.0.0", 1307 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", 1308 | "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", 1309 | "dev": true, 1310 | "engines": { 1311 | "node": ">=8" 1312 | } 1313 | }, 1314 | "node_modules/reusify": { 1315 | "version": "1.0.4", 1316 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 1317 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 1318 | "dev": true, 1319 | "engines": { 1320 | "iojs": ">=1.0.0", 1321 | "node": ">=0.10.0" 1322 | } 1323 | }, 1324 | "node_modules/run-parallel": { 1325 | "version": "1.2.0", 1326 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1327 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1328 | "dev": true, 1329 | "funding": [ 1330 | { 1331 | "type": "github", 1332 | "url": "https://github.com/sponsors/feross" 1333 | }, 1334 | { 1335 | "type": "patreon", 1336 | "url": "https://www.patreon.com/feross" 1337 | }, 1338 | { 1339 | "type": "consulting", 1340 | "url": "https://feross.org/support" 1341 | } 1342 | ], 1343 | "dependencies": { 1344 | "queue-microtask": "^1.2.2" 1345 | } 1346 | }, 1347 | "node_modules/semver": { 1348 | "version": "7.5.4", 1349 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", 1350 | "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", 1351 | "dev": true, 1352 | "dependencies": { 1353 | "lru-cache": "^6.0.0" 1354 | }, 1355 | "bin": { 1356 | "semver": "bin/semver.js" 1357 | }, 1358 | "engines": { 1359 | "node": ">=10" 1360 | } 1361 | }, 1362 | "node_modules/serialize-error": { 1363 | "version": "7.0.1", 1364 | "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", 1365 | "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", 1366 | "dev": true, 1367 | "dependencies": { 1368 | "type-fest": "^0.13.1" 1369 | }, 1370 | "engines": { 1371 | "node": ">=10" 1372 | }, 1373 | "funding": { 1374 | "url": "https://github.com/sponsors/sindresorhus" 1375 | } 1376 | }, 1377 | "node_modules/signal-exit": { 1378 | "version": "4.1.0", 1379 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", 1380 | "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", 1381 | "dev": true, 1382 | "engines": { 1383 | "node": ">=14" 1384 | }, 1385 | "funding": { 1386 | "url": "https://github.com/sponsors/isaacs" 1387 | } 1388 | }, 1389 | "node_modules/slash": { 1390 | "version": "4.0.0", 1391 | "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", 1392 | "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", 1393 | "dev": true, 1394 | "engines": { 1395 | "node": ">=12" 1396 | }, 1397 | "funding": { 1398 | "url": "https://github.com/sponsors/sindresorhus" 1399 | } 1400 | }, 1401 | "node_modules/slice-ansi": { 1402 | "version": "5.0.0", 1403 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", 1404 | "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", 1405 | "dev": true, 1406 | "dependencies": { 1407 | "ansi-styles": "^6.0.0", 1408 | "is-fullwidth-code-point": "^4.0.0" 1409 | }, 1410 | "engines": { 1411 | "node": ">=12" 1412 | }, 1413 | "funding": { 1414 | "url": "https://github.com/chalk/slice-ansi?sponsor=1" 1415 | } 1416 | }, 1417 | "node_modules/sprintf-js": { 1418 | "version": "1.0.3", 1419 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1420 | "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", 1421 | "dev": true 1422 | }, 1423 | "node_modules/stack-utils": { 1424 | "version": "2.0.6", 1425 | "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", 1426 | "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", 1427 | "dev": true, 1428 | "dependencies": { 1429 | "escape-string-regexp": "^2.0.0" 1430 | }, 1431 | "engines": { 1432 | "node": ">=10" 1433 | } 1434 | }, 1435 | "node_modules/stack-utils/node_modules/escape-string-regexp": { 1436 | "version": "2.0.0", 1437 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", 1438 | "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", 1439 | "dev": true, 1440 | "engines": { 1441 | "node": ">=8" 1442 | } 1443 | }, 1444 | "node_modules/string-width": { 1445 | "version": "5.1.2", 1446 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", 1447 | "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", 1448 | "dev": true, 1449 | "dependencies": { 1450 | "eastasianwidth": "^0.2.0", 1451 | "emoji-regex": "^9.2.2", 1452 | "strip-ansi": "^7.0.1" 1453 | }, 1454 | "engines": { 1455 | "node": ">=12" 1456 | }, 1457 | "funding": { 1458 | "url": "https://github.com/sponsors/sindresorhus" 1459 | } 1460 | }, 1461 | "node_modules/strip-ansi": { 1462 | "version": "7.1.0", 1463 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", 1464 | "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", 1465 | "dev": true, 1466 | "dependencies": { 1467 | "ansi-regex": "^6.0.1" 1468 | }, 1469 | "engines": { 1470 | "node": ">=12" 1471 | }, 1472 | "funding": { 1473 | "url": "https://github.com/chalk/strip-ansi?sponsor=1" 1474 | } 1475 | }, 1476 | "node_modules/supertap": { 1477 | "version": "3.0.1", 1478 | "resolved": "https://registry.npmjs.org/supertap/-/supertap-3.0.1.tgz", 1479 | "integrity": "sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==", 1480 | "dev": true, 1481 | "dependencies": { 1482 | "indent-string": "^5.0.0", 1483 | "js-yaml": "^3.14.1", 1484 | "serialize-error": "^7.0.1", 1485 | "strip-ansi": "^7.0.1" 1486 | }, 1487 | "engines": { 1488 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 1489 | } 1490 | }, 1491 | "node_modules/temp-dir": { 1492 | "version": "3.0.0", 1493 | "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", 1494 | "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", 1495 | "dev": true, 1496 | "engines": { 1497 | "node": ">=14.16" 1498 | } 1499 | }, 1500 | "node_modules/time-zone": { 1501 | "version": "1.0.0", 1502 | "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz", 1503 | "integrity": "sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==", 1504 | "dev": true, 1505 | "engines": { 1506 | "node": ">=4" 1507 | } 1508 | }, 1509 | "node_modules/to-regex-range": { 1510 | "version": "5.0.1", 1511 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1512 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1513 | "dev": true, 1514 | "dependencies": { 1515 | "is-number": "^7.0.0" 1516 | }, 1517 | "engines": { 1518 | "node": ">=8.0" 1519 | } 1520 | }, 1521 | "node_modules/type-fest": { 1522 | "version": "0.13.1", 1523 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", 1524 | "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", 1525 | "dev": true, 1526 | "engines": { 1527 | "node": ">=10" 1528 | }, 1529 | "funding": { 1530 | "url": "https://github.com/sponsors/sindresorhus" 1531 | } 1532 | }, 1533 | "node_modules/well-known-symbols": { 1534 | "version": "2.0.0", 1535 | "resolved": "https://registry.npmjs.org/well-known-symbols/-/well-known-symbols-2.0.0.tgz", 1536 | "integrity": "sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==", 1537 | "dev": true, 1538 | "engines": { 1539 | "node": ">=6" 1540 | } 1541 | }, 1542 | "node_modules/wrap-ansi": { 1543 | "version": "7.0.0", 1544 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1545 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1546 | "dev": true, 1547 | "dependencies": { 1548 | "ansi-styles": "^4.0.0", 1549 | "string-width": "^4.1.0", 1550 | "strip-ansi": "^6.0.0" 1551 | }, 1552 | "engines": { 1553 | "node": ">=10" 1554 | }, 1555 | "funding": { 1556 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 1557 | } 1558 | }, 1559 | "node_modules/wrap-ansi/node_modules/ansi-regex": { 1560 | "version": "5.0.1", 1561 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 1562 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 1563 | "dev": true, 1564 | "engines": { 1565 | "node": ">=8" 1566 | } 1567 | }, 1568 | "node_modules/wrap-ansi/node_modules/ansi-styles": { 1569 | "version": "4.3.0", 1570 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 1571 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 1572 | "dev": true, 1573 | "dependencies": { 1574 | "color-convert": "^2.0.1" 1575 | }, 1576 | "engines": { 1577 | "node": ">=8" 1578 | }, 1579 | "funding": { 1580 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 1581 | } 1582 | }, 1583 | "node_modules/wrap-ansi/node_modules/emoji-regex": { 1584 | "version": "8.0.0", 1585 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 1586 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 1587 | "dev": true 1588 | }, 1589 | "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { 1590 | "version": "3.0.0", 1591 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1592 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1593 | "dev": true, 1594 | "engines": { 1595 | "node": ">=8" 1596 | } 1597 | }, 1598 | "node_modules/wrap-ansi/node_modules/string-width": { 1599 | "version": "4.2.3", 1600 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1601 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1602 | "dev": true, 1603 | "dependencies": { 1604 | "emoji-regex": "^8.0.0", 1605 | "is-fullwidth-code-point": "^3.0.0", 1606 | "strip-ansi": "^6.0.1" 1607 | }, 1608 | "engines": { 1609 | "node": ">=8" 1610 | } 1611 | }, 1612 | "node_modules/wrap-ansi/node_modules/strip-ansi": { 1613 | "version": "6.0.1", 1614 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1615 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1616 | "dev": true, 1617 | "dependencies": { 1618 | "ansi-regex": "^5.0.1" 1619 | }, 1620 | "engines": { 1621 | "node": ">=8" 1622 | } 1623 | }, 1624 | "node_modules/write-file-atomic": { 1625 | "version": "5.0.1", 1626 | "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", 1627 | "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", 1628 | "dev": true, 1629 | "dependencies": { 1630 | "imurmurhash": "^0.1.4", 1631 | "signal-exit": "^4.0.1" 1632 | }, 1633 | "engines": { 1634 | "node": "^14.17.0 || ^16.13.0 || >=18.0.0" 1635 | } 1636 | }, 1637 | "node_modules/y18n": { 1638 | "version": "5.0.8", 1639 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 1640 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 1641 | "dev": true, 1642 | "engines": { 1643 | "node": ">=10" 1644 | } 1645 | }, 1646 | "node_modules/yallist": { 1647 | "version": "4.0.0", 1648 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 1649 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 1650 | "dev": true 1651 | }, 1652 | "node_modules/yargs": { 1653 | "version": "17.7.2", 1654 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", 1655 | "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", 1656 | "dev": true, 1657 | "dependencies": { 1658 | "cliui": "^8.0.1", 1659 | "escalade": "^3.1.1", 1660 | "get-caller-file": "^2.0.5", 1661 | "require-directory": "^2.1.1", 1662 | "string-width": "^4.2.3", 1663 | "y18n": "^5.0.5", 1664 | "yargs-parser": "^21.1.1" 1665 | }, 1666 | "engines": { 1667 | "node": ">=12" 1668 | } 1669 | }, 1670 | "node_modules/yargs-parser": { 1671 | "version": "21.1.1", 1672 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", 1673 | "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", 1674 | "dev": true, 1675 | "engines": { 1676 | "node": ">=12" 1677 | } 1678 | }, 1679 | "node_modules/yargs/node_modules/ansi-regex": { 1680 | "version": "5.0.1", 1681 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 1682 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 1683 | "dev": true, 1684 | "engines": { 1685 | "node": ">=8" 1686 | } 1687 | }, 1688 | "node_modules/yargs/node_modules/emoji-regex": { 1689 | "version": "8.0.0", 1690 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 1691 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 1692 | "dev": true 1693 | }, 1694 | "node_modules/yargs/node_modules/is-fullwidth-code-point": { 1695 | "version": "3.0.0", 1696 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1697 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1698 | "dev": true, 1699 | "engines": { 1700 | "node": ">=8" 1701 | } 1702 | }, 1703 | "node_modules/yargs/node_modules/string-width": { 1704 | "version": "4.2.3", 1705 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1706 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1707 | "dev": true, 1708 | "dependencies": { 1709 | "emoji-regex": "^8.0.0", 1710 | "is-fullwidth-code-point": "^3.0.0", 1711 | "strip-ansi": "^6.0.1" 1712 | }, 1713 | "engines": { 1714 | "node": ">=8" 1715 | } 1716 | }, 1717 | "node_modules/yargs/node_modules/strip-ansi": { 1718 | "version": "6.0.1", 1719 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1720 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1721 | "dev": true, 1722 | "dependencies": { 1723 | "ansi-regex": "^5.0.1" 1724 | }, 1725 | "engines": { 1726 | "node": ">=8" 1727 | } 1728 | }, 1729 | "node_modules/yocto-queue": { 1730 | "version": "1.0.0", 1731 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", 1732 | "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", 1733 | "dev": true, 1734 | "engines": { 1735 | "node": ">=12.20" 1736 | }, 1737 | "funding": { 1738 | "url": "https://github.com/sponsors/sindresorhus" 1739 | } 1740 | } 1741 | } 1742 | } 1743 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mycro-db", 3 | "version": "1.2.5", 4 | "description": "MycroDB is a JavaScript library for managing Document Databases stored in a single JSON file.", 5 | "license": "MIT", 6 | "main": "./lib/index.js", 7 | "type": "module", 8 | "author": { 9 | "name": "Diegiwg (Diego Queiroz)", 10 | "email": "diegiwg@gmail.com", 11 | "url": "https://github.com/Diegiwg" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/Diegiwg/mycro-db" 16 | }, 17 | "keywords": [ 18 | "MycroDB", 19 | "JavaScript", 20 | "Database Library", 21 | "Document Database", 22 | "JSON Storage" 23 | ], 24 | "devDependencies": { 25 | "ava": "^5.3.1" 26 | }, 27 | "scripts": { 28 | "test": "npx ava" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /test/class.test.js: -------------------------------------------------------------------------------- 1 | import ava from "ava"; 2 | import fs from "fs"; 3 | 4 | import { JsonStorage, MemoryStorage, MycroDatabase } from "../lib/index.js"; 5 | 6 | ava("Database in Memory only mode", (t) => { 7 | const storage = new MemoryStorage(); 8 | 9 | const db = new MycroDatabase(storage); 10 | const col = db.collection("col", { value: String() }); 11 | 12 | col.insert({ value: "a" }); 13 | 14 | const result = col.query(); 15 | const expected = { 16 | docs: [ 17 | { 18 | id: 1, 19 | value: "a", 20 | }, 21 | ], 22 | limit: 25, 23 | offset: 0, 24 | }; 25 | 26 | t.deepEqual(result, expected); 27 | }); 28 | 29 | const storage = new JsonStorage("./test/test.json"); 30 | 31 | ava("Database synced to a JSON file", (t) => { 32 | const db = new MycroDatabase(storage); 33 | 34 | const col = db.collection("col", { value: String() }); 35 | 36 | col.insert({ value: "a" }); 37 | 38 | const result = col.query(); 39 | const expected = { 40 | docs: [ 41 | { 42 | id: 1, 43 | value: "a", 44 | }, 45 | ], 46 | limit: 25, 47 | offset: 0, 48 | }; 49 | 50 | t.deepEqual(result, expected); 51 | }); 52 | 53 | ava("Load a data from JSON file", (t) => { 54 | const db = new MycroDatabase(storage); 55 | 56 | const col = db.collection("col", { value: String() }); 57 | 58 | const result = col.query(); 59 | const expected = { 60 | docs: [ 61 | { 62 | id: 1, 63 | value: "a", 64 | }, 65 | ], 66 | limit: 25, 67 | offset: 0, 68 | }; 69 | 70 | t.deepEqual(result, expected); 71 | 72 | fs.unlinkSync("./test/test.json"); 73 | }); 74 | -------------------------------------------------------------------------------- /test/count.test.js: -------------------------------------------------------------------------------- 1 | import ava from "ava"; 2 | 3 | import { MemoryStorage, MycroDatabase } from "../lib/index.js"; 4 | 5 | ava("Count the number of documents in the collection", (t) => { 6 | const db = new MycroDatabase(new MemoryStorage()); 7 | const col = db.collection("col", { value: String() }); 8 | 9 | col.insert([{ value: "a" }, { value: "b" }]); 10 | 11 | const result = col.count(); 12 | const expected = 2; 13 | 14 | t.deepEqual(result, expected); 15 | }); 16 | -------------------------------------------------------------------------------- /test/get.test.js: -------------------------------------------------------------------------------- 1 | import ava from "ava"; 2 | 3 | import { MemoryStorage, MycroDatabase } from "../lib/index.js"; 4 | 5 | ava("Get a single document from the collection", (t) => { 6 | const db = new MycroDatabase(new MemoryStorage()); 7 | const col = db.collection("col", { value: String() }); 8 | 9 | col.insert([{ value: "a" }, { value: "b" }]); 10 | 11 | const result = col.get(1); 12 | const expected = [ 13 | { 14 | id: 1, 15 | value: "a", 16 | }, 17 | ]; 18 | 19 | t.deepEqual(result, expected); 20 | }); 21 | 22 | ava("Get tree documents from the collection", (t) => { 23 | const db = new MycroDatabase(new MemoryStorage()); 24 | const col = db.collection("col", { value: String(), another: String() }); 25 | 26 | col.insert([ 27 | { value: "a", another: "x" }, 28 | { value: "b", another: "y" }, 29 | { value: "c", another: "y" }, 30 | { value: "d", another: "y" }, 31 | ]); 32 | 33 | const result = col.get([2, 3, 4]); 34 | const expected = [ 35 | { id: 2, value: "b", another: "y" }, 36 | { id: 3, value: "c", another: "y" }, 37 | { id: 4, value: "d", another: "y" }, 38 | ]; 39 | t.deepEqual(result, expected); 40 | }); 41 | 42 | ava("Try get a non-existing document from the collection", (t) => { 43 | const db = new MycroDatabase(new MemoryStorage()); 44 | const col = db.collection("col", { value: String() }); 45 | 46 | const result = col.get(0); 47 | const expected = []; 48 | 49 | t.deepEqual(result, expected); 50 | }); 51 | -------------------------------------------------------------------------------- /test/insert.test.js: -------------------------------------------------------------------------------- 1 | import ava from "ava"; 2 | 3 | import { MemoryStorage, MycroDatabase } from "../lib/index.js"; 4 | 5 | ava("Insert a unique document into the collection", (t) => { 6 | const db = new MycroDatabase(new MemoryStorage()); 7 | const col = db.collection("col", { value: String() }); 8 | 9 | col.insert({ value: "a" }); 10 | 11 | const result = col.query(); 12 | const expected = { 13 | docs: [ 14 | { 15 | id: 1, 16 | value: "a", 17 | }, 18 | ], 19 | limit: 25, 20 | offset: 0, 21 | }; 22 | 23 | t.deepEqual(result, expected); 24 | }); 25 | 26 | ava("Insert tree documents into the collection", (t) => { 27 | const db = new MycroDatabase(new MemoryStorage()); 28 | const col = db.collection("col", { 29 | id: Number(), 30 | value: String(), 31 | }); 32 | 33 | col.insert([{ value: "a" }, { value: "b" }, { value: "c" }]); 34 | 35 | const result = col.query(); 36 | const expected = { 37 | docs: [ 38 | { id: 1, value: "a" }, 39 | { id: 2, value: "b" }, 40 | { id: 3, value: "c" }, 41 | ], 42 | limit: 25, 43 | offset: 0, 44 | }; 45 | t.deepEqual(result, expected); 46 | }); 47 | -------------------------------------------------------------------------------- /test/query.test.js: -------------------------------------------------------------------------------- 1 | import ava from "ava"; 2 | 3 | import { MemoryStorage, MycroDatabase } from "../lib/index.js"; 4 | 5 | ava("Query a single document from the collection", (t) => { 6 | const db = new MycroDatabase(new MemoryStorage()); 7 | const col = db.collection("col", { value: String() }); 8 | 9 | col.insert([{ value: "a" }, { value: "b" }]); 10 | 11 | const result = col.query((doc) => doc.value === "a"); 12 | const expected = { 13 | docs: [ 14 | { 15 | id: 1, 16 | value: "a", 17 | }, 18 | ], 19 | limit: 25, 20 | offset: 0, 21 | }; 22 | 23 | t.deepEqual(result, expected); 24 | }); 25 | 26 | ava("Query tree documents from the collection", (t) => { 27 | const db = new MycroDatabase(new MemoryStorage()); 28 | const col = db.collection("col", { value: String(), another: String() }); 29 | 30 | col.insert([ 31 | { value: "a", another: "x" }, 32 | { value: "b", another: "y" }, 33 | { value: "c", another: "y" }, 34 | { value: "d", another: "y" }, 35 | ]); 36 | 37 | const result = col.query((doc) => doc.another === "y"); 38 | const expected = { 39 | docs: [ 40 | { id: 2, value: "b", another: "y" }, 41 | { id: 3, value: "c", another: "y" }, 42 | { id: 4, value: "d", another: "y" }, 43 | ], 44 | limit: 25, 45 | offset: 0, 46 | }; 47 | t.deepEqual(result, expected); 48 | }); 49 | 50 | ava("Query all documents from the collection", (t) => { 51 | const db = new MycroDatabase(new MemoryStorage()); 52 | const col = db.collection("col", { value: String() }); 53 | 54 | col.insert([{ value: "a" }, { value: "b" }, { value: "c" }]); 55 | 56 | const DOCS_IN_DB = col.count(); 57 | 58 | const result = col.query(null, DOCS_IN_DB); 59 | const expected = { 60 | docs: [ 61 | { id: 1, value: "a" }, 62 | { id: 2, value: "b" }, 63 | { id: 3, value: "c" }, 64 | ], 65 | limit: DOCS_IN_DB, 66 | offset: 0, 67 | }; 68 | 69 | t.deepEqual(result, expected); 70 | }); 71 | 72 | ava("Try query a non-existing document from the collection", (t) => { 73 | const db = new MycroDatabase(new MemoryStorage()); 74 | const col = db.collection("col", { value: String() }); 75 | 76 | col.query((doc) => doc.value === "a"); 77 | 78 | const result = col.query(); 79 | const expected = { 80 | docs: [], 81 | limit: 25, 82 | offset: 0, 83 | }; 84 | 85 | t.deepEqual(result, expected); 86 | }); 87 | -------------------------------------------------------------------------------- /test/remove.test.js: -------------------------------------------------------------------------------- 1 | import ava from "ava"; 2 | 3 | import { MemoryStorage, MycroDatabase } from "../lib/index.js"; 4 | 5 | ava("Remove a unique document from the collection", (t) => { 6 | const db = new MycroDatabase(new MemoryStorage()); 7 | 8 | const col = db.collection("col", { value: String() }); 9 | 10 | col.insert([{ value: "a" }, { value: "b" }]); 11 | 12 | col.remove(1); 13 | 14 | const result = col.query(); 15 | const expected = { 16 | docs: [ 17 | { 18 | id: 2, 19 | value: "b", 20 | }, 21 | ], 22 | limit: 25, 23 | offset: 0, 24 | }; 25 | 26 | t.deepEqual(result, expected); 27 | }); 28 | 29 | ava("Remove tree documents from the collection", (t) => { 30 | const db = new MycroDatabase(new MemoryStorage()); 31 | const col = db.collection("col", { value: String(), another: String() }); 32 | 33 | col.insert([ 34 | { value: "a", another: "x" }, 35 | { value: "b", another: "y" }, 36 | { value: "c", another: "y" }, 37 | { value: "d", another: "y" }, 38 | ]); 39 | 40 | col.remove([2, 3, 4]); 41 | 42 | const result = col.query(); 43 | const expected = { 44 | docs: [ 45 | { 46 | another: "x", 47 | id: 1, 48 | value: "a", 49 | }, 50 | ], 51 | limit: 25, 52 | offset: 0, 53 | }; 54 | 55 | t.deepEqual(result, expected); 56 | }); 57 | 58 | ava("Try remove a non-existing document from the collection", (t) => { 59 | const db = new MycroDatabase(new MemoryStorage()); 60 | const col = db.collection("col", { value: String() }); 61 | 62 | col.remove(1); 63 | 64 | const result = col.query(); 65 | const expected = { 66 | docs: [], 67 | limit: 25, 68 | offset: 0, 69 | }; 70 | 71 | t.deepEqual(result, expected); 72 | }); 73 | -------------------------------------------------------------------------------- /test/storage.test.js: -------------------------------------------------------------------------------- 1 | import ava from "ava"; 2 | 3 | import { MycroDatabase } from "../lib/index.js"; 4 | 5 | ava("Testing a Expanded Storage API", (t) => { 6 | const fakeStorage = { 7 | read: () => {}, 8 | write: () => {}, 9 | 10 | create: () => { 11 | return "Expanded Storage API"; 12 | }, 13 | 14 | insert: (ref) => { 15 | return () => { 16 | return "Expanded Storage API"; 17 | }; 18 | }, 19 | }; 20 | 21 | const db = new MycroDatabase(fakeStorage); 22 | const col = db.collection("col", { value: String() }); 23 | 24 | const result = col.insert(); // Always returns "Expanded Storage API" for testing purpose 25 | const expected = "Expanded Storage API"; 26 | 27 | t.is(result, expected); 28 | }); 29 | -------------------------------------------------------------------------------- /test/typedJson.storage.test.js: -------------------------------------------------------------------------------- 1 | import ava from "ava"; 2 | import fs from "fs"; 3 | 4 | import { MycroDatabase, TypedJsonStorage } from "../lib/index.js"; 5 | 6 | function clearFile() { 7 | if (fs.existsSync("./test/test.json")) fs.unlinkSync("./test/test.json"); 8 | } 9 | 10 | clearFile(); 11 | 12 | ava( 13 | "Insert a unique (complex) document into the collection with correct type", 14 | (t) => { 15 | const storage = new TypedJsonStorage("./test/test.json"); 16 | const db = new MycroDatabase(storage); 17 | 18 | const col = db.collection("col", { 19 | value: { extend: [{ key: [Number()] }], another: String() }, 20 | }); 21 | 22 | col.insert({ 23 | value: { 24 | extend: [{ key: [1, 2] }, { key: [3] }], 25 | another: "hello", 26 | }, 27 | }); 28 | 29 | const result = col.query(); 30 | const expected = { 31 | docs: [ 32 | { 33 | id: 1, 34 | value: { 35 | extend: [{ key: [1, 2] }, { key: [3] }], 36 | another: "hello", 37 | }, 38 | }, 39 | ], 40 | limit: 25, 41 | offset: 0, 42 | }; 43 | 44 | t.deepEqual(result, expected); 45 | 46 | clearFile(); 47 | } 48 | ); 49 | 50 | ava("Insert tree documents into the collection with correct type", (t) => { 51 | const storage = new TypedJsonStorage("./test/test.json"); 52 | const db = new MycroDatabase(storage); 53 | 54 | const col = db.collection("col", { 55 | value: String(), 56 | }); 57 | 58 | col.insert([{ value: "a" }, { value: "b" }, { value: "c" }]); 59 | 60 | const result = col.query(); 61 | const expected = { 62 | docs: [ 63 | { id: 1, value: "a" }, 64 | { id: 2, value: "b" }, 65 | { id: 3, value: "c" }, 66 | ], 67 | limit: 25, 68 | offset: 0, 69 | }; 70 | 71 | t.deepEqual(result, expected); 72 | 73 | clearFile(); 74 | }); 75 | 76 | ava( 77 | "Throws an error when insert a unique document into the collection with incorrect type", 78 | (t) => { 79 | const storage = new TypedJsonStorage("./test/test.json"); 80 | const db = new MycroDatabase(storage); 81 | 82 | const col = db.collection("col", { value: String() }); 83 | 84 | t.throws(() => { 85 | col.insert({ value: 9999 }); 86 | }); 87 | 88 | clearFile(); 89 | } 90 | ); 91 | 92 | ava("Throws an error when insert tree documents into the collection", (t) => { 93 | const storage = new TypedJsonStorage("./test/test.json"); 94 | const db = new MycroDatabase(storage); 95 | 96 | const col = db.collection("col", { 97 | value: String(), 98 | }); 99 | 100 | t.throws(() => { 101 | col.insert([{ value: 1 }, { value: 2 }]); 102 | }); 103 | 104 | clearFile(); 105 | }); 106 | 107 | ava( 108 | "Throws an error when insert a document with a non-existent key in schema", 109 | (t) => { 110 | const storage = new TypedJsonStorage("./test/test.json"); 111 | const db = new MycroDatabase(storage); 112 | 113 | const col = db.collection("col", { 114 | value: String(), 115 | }); 116 | 117 | t.throws(() => { 118 | col.insert({ value: "a", another: "b" }); 119 | }); 120 | 121 | clearFile(); 122 | } 123 | ); 124 | 125 | ava("Update a unique document in the collection with correct type", (t) => { 126 | const storage = new TypedJsonStorage("./test/test.json"); 127 | const db = new MycroDatabase(storage); 128 | 129 | const col = db.collection("col", { value: String() }); 130 | 131 | col.insert([{ value: "a" }, { value: "b" }]); 132 | 133 | col.update({ id: 1, data: { value: "c" } }); 134 | 135 | const result = col.query(); 136 | const expected = { 137 | docs: [ 138 | { id: 1, value: "c" }, 139 | { id: 2, value: "b" }, 140 | ], 141 | limit: 25, 142 | offset: 0, 143 | }; 144 | 145 | t.deepEqual(result, expected); 146 | 147 | clearFile(); 148 | }); 149 | 150 | ava("Update tree documents in the collection with correct type", (t) => { 151 | const storage = new TypedJsonStorage("./test/test.json"); 152 | const db = new MycroDatabase(storage); 153 | 154 | const col = db.collection("col", { value: String(), another: String() }); 155 | 156 | col.insert([ 157 | { value: "a", another: "x" }, 158 | { value: "b", another: "y" }, 159 | { value: "c", another: "y" }, 160 | { value: "d", another: "y" }, 161 | ]); 162 | 163 | col.update([ 164 | { id: 2, data: { another: "z" } }, 165 | { id: 3, data: { another: "z" } }, 166 | { id: 4, data: { another: "z" } }, 167 | ]); 168 | 169 | const result = col.query(); 170 | const expected = { 171 | docs: [ 172 | { another: "x", id: 1, value: "a" }, 173 | { another: "z", id: 2, value: "b" }, 174 | { another: "z", id: 3, value: "c" }, 175 | { another: "z", id: 4, value: "d" }, 176 | ], 177 | limit: 25, 178 | offset: 0, 179 | }; 180 | 181 | t.deepEqual(result, expected); 182 | 183 | clearFile(); 184 | }); 185 | 186 | ava( 187 | "Throws an error when update a unique document in the collection with incorrect type", 188 | (t) => { 189 | const storage = new TypedJsonStorage("./test/test.json"); 190 | const db = new MycroDatabase(storage); 191 | 192 | const col = db.collection("col", { 193 | value: String(), 194 | another: String(), 195 | }); 196 | 197 | col.insert([{ value: "a" }]); 198 | 199 | t.throws(() => { 200 | col.update({ id: 1, data: { value: 9999 } }); 201 | }); 202 | 203 | clearFile(); 204 | } 205 | ); 206 | 207 | ava( 208 | "Throws an error when update tree documents in the collection with incorrect type", 209 | (t) => { 210 | const storage = new TypedJsonStorage("./test/test.json"); 211 | const db = new MycroDatabase(storage); 212 | 213 | const col = db.collection("col", { 214 | value: String(), 215 | another: String(), 216 | }); 217 | 218 | col.insert([ 219 | { value: "a", another: "x" }, 220 | { value: "b", another: "y" }, 221 | { value: "c", another: "y" }, 222 | { value: "d", another: "y" }, 223 | ]); 224 | 225 | t.throws(() => { 226 | col.update([ 227 | { id: 2, data: { another: 1 } }, 228 | { id: 3, data: { another: 2 } }, 229 | { id: 4, data: { another: 3 } }, 230 | ]); 231 | }); 232 | 233 | clearFile(); 234 | } 235 | ); 236 | -------------------------------------------------------------------------------- /test/update.test.js: -------------------------------------------------------------------------------- 1 | import ava from "ava"; 2 | 3 | import { MemoryStorage, MycroDatabase } from "../lib/index.js"; 4 | 5 | ava("Update a unique document in the collection", (t) => { 6 | const db = new MycroDatabase(new MemoryStorage()); 7 | const col = db.collection("col", { value: String() }); 8 | 9 | col.insert([{ value: "a" }, { value: "b" }]); 10 | 11 | col.update({ id: 1, data: { value: "c" } }); 12 | 13 | const result = col.query(); 14 | const expected = { 15 | docs: [ 16 | { id: 1, value: "c" }, 17 | { id: 2, value: "b" }, 18 | ], 19 | limit: 25, 20 | offset: 0, 21 | }; 22 | 23 | t.deepEqual(result, expected); 24 | }); 25 | 26 | ava("Update tree documents in the collection", (t) => { 27 | const db = new MycroDatabase(new MemoryStorage()); 28 | const col = db.collection("col", { value: String(), another: String() }); 29 | 30 | col.insert([ 31 | { value: "a", another: "x" }, 32 | { value: "b", another: "y" }, 33 | { value: "c", another: "y" }, 34 | { value: "d", another: "y" }, 35 | ]); 36 | 37 | col.update([ 38 | { id: 2, data: { another: "z" } }, 39 | { id: 3, data: { another: "z" } }, 40 | { id: 4, data: { another: "z" } }, 41 | ]); 42 | 43 | const result = col.query(); 44 | const expected = { 45 | docs: [ 46 | { another: "x", id: 1, value: "a" }, 47 | { another: "z", id: 2, value: "b" }, 48 | { another: "z", id: 3, value: "c" }, 49 | { another: "z", id: 4, value: "d" }, 50 | ], 51 | limit: 25, 52 | offset: 0, 53 | }; 54 | 55 | t.deepEqual(result, expected); 56 | }); 57 | 58 | ava("Try update a non-existing document in the collection", (t) => { 59 | const db = new MycroDatabase(new MemoryStorage()); 60 | const col = db.collection("col", { value: String() }); 61 | 62 | col.update({ id: 1, data: { value: "c" } }); 63 | 64 | const result = col.query(); 65 | const expected = { 66 | docs: [], 67 | limit: 25, 68 | offset: 0, 69 | }; 70 | 71 | t.deepEqual(result, expected); 72 | }); 73 | --------------------------------------------------------------------------------