diff --git a/.forceignore b/.forceignore index 637ef25a3..d12b69942 100644 --- a/.forceignore +++ b/.forceignore @@ -4,7 +4,7 @@ nebula-logger/**/main/default/ nebula-logger/managed-package/sfdx-project.json -nebula-logger/managed-package/**/testSuites/** +nebula-logger/managed-package/**/*.testSuite-meta.xml # Directory/package-specific README files **/README.md diff --git a/.github/codecov.yml b/.github/codecov.yml index 0d7eb5e21..a8d661d84 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -7,6 +7,6 @@ coverage: if_ci_failed: success patch: off ignore: - - 'nebula-logger-recipes/**/*' + - 'nebula-logger/recipes/**/*' comment: behavior: new diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2f9a39e82..d0e8d514f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -160,8 +160,8 @@ jobs: - name: 'Create Base Scratch Org' run: npx sfdx force:org:create --durationdays 1 --definitionfile ./config/scratch-orgs/base-scratch-def.json --wait 20 --setdefaultusername --json - - name: 'Push Source to Scratch Org' - run: npm run source:push + - name: 'Deploy Source to Scratch Org' + run: npm run source:deploy - name: 'Assign Logger Admin Permission Set' run: npm run permset:assign:admin @@ -213,8 +213,8 @@ jobs: - name: 'Deploy Test Experience Site Metadata' run: npm run experience:deploy - - name: 'Push Source to Scratch Org' - run: npm run source:push + - name: 'Deploy Source to Scratch Org' + run: npm run source:deploy - name: 'Assign Logger Admin Permission Set' run: npm run permset:assign:admin diff --git a/README.md b/README.md index e0ac9bb3b..8fa307f18 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,10 @@ Designed for Salesforce admins, developers & architects. A robust logger for Apex, Lightning Components, Flow, Process Builder & Integrations. -## Unlocked Package - v4.7.0 +## Unlocked Package - v4.7.1 -[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015lXSQAY) -[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015lXSQAY) +[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015lgBQAQ) +[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015lgBQAQ) [![View Documentation](./images/btn-view-documentation.png)](https://jongpie.github.io/NebulaLogger/) ## Managed Package - v4.7.0 @@ -702,9 +702,9 @@ The optional [Slack plugin](./nebula-logger-plugins/Slack/) leverages the Nebula - Extend permission sets to include field-level security for your custom fields - Leverage the new `LoggerParameter__mdt` CMDT object to store configuration for your plugin -Check out the [Slack plugin](./nebula-logger-plugins/Slack/) for more details on how to install & customize the plugin +Check out the [Slack plugin](./nebula-logger-plugins/slack/) for more details on how to install & customize the plugin -![Slack plugin: notification](./nebula-logger-plugins/Slack/images/slack-plugin-notification.png) +![Slack plugin: notification](./nebula-logger/plugins/slack/.images/slack-plugin-notification.png) --- diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1.site-meta.xml b/config/experience-cloud/experiences/Logger_Test_Site1.site-meta.xml similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1.site-meta.xml rename to config/experience-cloud/experiences/Logger_Test_Site1.site-meta.xml diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/brandingSets/buildYourOwnLWR.json b/config/experience-cloud/experiences/Logger_Test_Site1/brandingSets/buildYourOwnLWR.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/brandingSets/buildYourOwnLWR.json rename to config/experience-cloud/experiences/Logger_Test_Site1/brandingSets/buildYourOwnLWR.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/config/languages.json b/config/experience-cloud/experiences/Logger_Test_Site1/config/languages.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/config/languages.json rename to config/experience-cloud/experiences/Logger_Test_Site1/config/languages.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/config/loggerTestSite.json b/config/experience-cloud/experiences/Logger_Test_Site1/config/loggerTestSite.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/config/loggerTestSite.json rename to config/experience-cloud/experiences/Logger_Test_Site1/config/loggerTestSite.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/config/mainAppPage.json b/config/experience-cloud/experiences/Logger_Test_Site1/config/mainAppPage.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/config/mainAppPage.json rename to config/experience-cloud/experiences/Logger_Test_Site1/config/mainAppPage.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/routes/checkPassword.json b/config/experience-cloud/experiences/Logger_Test_Site1/routes/checkPassword.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/routes/checkPassword.json rename to config/experience-cloud/experiences/Logger_Test_Site1/routes/checkPassword.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/routes/error.json b/config/experience-cloud/experiences/Logger_Test_Site1/routes/error.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/routes/error.json rename to config/experience-cloud/experiences/Logger_Test_Site1/routes/error.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/routes/forgotPassword.json b/config/experience-cloud/experiences/Logger_Test_Site1/routes/forgotPassword.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/routes/forgotPassword.json rename to config/experience-cloud/experiences/Logger_Test_Site1/routes/forgotPassword.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/routes/home.json b/config/experience-cloud/experiences/Logger_Test_Site1/routes/home.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/routes/home.json rename to config/experience-cloud/experiences/Logger_Test_Site1/routes/home.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/routes/login.json b/config/experience-cloud/experiences/Logger_Test_Site1/routes/login.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/routes/login.json rename to config/experience-cloud/experiences/Logger_Test_Site1/routes/login.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/routes/register.json b/config/experience-cloud/experiences/Logger_Test_Site1/routes/register.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/routes/register.json rename to config/experience-cloud/experiences/Logger_Test_Site1/routes/register.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/routes/serviceNotAvailable.json b/config/experience-cloud/experiences/Logger_Test_Site1/routes/serviceNotAvailable.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/routes/serviceNotAvailable.json rename to config/experience-cloud/experiences/Logger_Test_Site1/routes/serviceNotAvailable.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/themes/buildYourOwnLWR.json b/config/experience-cloud/experiences/Logger_Test_Site1/themes/buildYourOwnLWR.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/themes/buildYourOwnLWR.json rename to config/experience-cloud/experiences/Logger_Test_Site1/themes/buildYourOwnLWR.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/views/checkPassword.json b/config/experience-cloud/experiences/Logger_Test_Site1/views/checkPassword.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/views/checkPassword.json rename to config/experience-cloud/experiences/Logger_Test_Site1/views/checkPassword.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/views/error.json b/config/experience-cloud/experiences/Logger_Test_Site1/views/error.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/views/error.json rename to config/experience-cloud/experiences/Logger_Test_Site1/views/error.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/views/forgotPassword.json b/config/experience-cloud/experiences/Logger_Test_Site1/views/forgotPassword.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/views/forgotPassword.json rename to config/experience-cloud/experiences/Logger_Test_Site1/views/forgotPassword.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/views/home.json b/config/experience-cloud/experiences/Logger_Test_Site1/views/home.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/views/home.json rename to config/experience-cloud/experiences/Logger_Test_Site1/views/home.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/views/login.json b/config/experience-cloud/experiences/Logger_Test_Site1/views/login.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/views/login.json rename to config/experience-cloud/experiences/Logger_Test_Site1/views/login.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/views/register.json b/config/experience-cloud/experiences/Logger_Test_Site1/views/register.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/views/register.json rename to config/experience-cloud/experiences/Logger_Test_Site1/views/register.json diff --git a/nebula-logger/experience-cloud/experiences/Logger_Test_Site1/views/serviceNotAvailable.json b/config/experience-cloud/experiences/Logger_Test_Site1/views/serviceNotAvailable.json similarity index 100% rename from nebula-logger/experience-cloud/experiences/Logger_Test_Site1/views/serviceNotAvailable.json rename to config/experience-cloud/experiences/Logger_Test_Site1/views/serviceNotAvailable.json diff --git a/nebula-logger/experience-cloud/networks/Logger Test Site.network-meta.xml b/config/experience-cloud/networks/Logger Test Site.network-meta.xml similarity index 100% rename from nebula-logger/experience-cloud/networks/Logger Test Site.network-meta.xml rename to config/experience-cloud/networks/Logger Test Site.network-meta.xml diff --git a/nebula-logger/experience-cloud/pages/BandwidthExceeded.page b/config/experience-cloud/pages/BandwidthExceeded.page similarity index 100% rename from nebula-logger/experience-cloud/pages/BandwidthExceeded.page rename to config/experience-cloud/pages/BandwidthExceeded.page diff --git a/nebula-logger/experience-cloud/pages/BandwidthExceeded.page-meta.xml b/config/experience-cloud/pages/BandwidthExceeded.page-meta.xml similarity index 100% rename from nebula-logger/experience-cloud/pages/BandwidthExceeded.page-meta.xml rename to config/experience-cloud/pages/BandwidthExceeded.page-meta.xml diff --git a/nebula-logger/experience-cloud/pages/ChangePassword.page b/config/experience-cloud/pages/ChangePassword.page similarity index 100% rename from nebula-logger/experience-cloud/pages/ChangePassword.page rename to config/experience-cloud/pages/ChangePassword.page diff --git a/nebula-logger/experience-cloud/pages/ChangePassword.page-meta.xml b/config/experience-cloud/pages/ChangePassword.page-meta.xml similarity index 100% rename from nebula-logger/experience-cloud/pages/ChangePassword.page-meta.xml rename to config/experience-cloud/pages/ChangePassword.page-meta.xml diff --git a/nebula-logger/experience-cloud/pages/CommunitiesLanding.page b/config/experience-cloud/pages/CommunitiesLanding.page similarity index 100% rename from nebula-logger/experience-cloud/pages/CommunitiesLanding.page rename to config/experience-cloud/pages/CommunitiesLanding.page diff --git a/nebula-logger/experience-cloud/pages/CommunitiesLanding.page-meta.xml b/config/experience-cloud/pages/CommunitiesLanding.page-meta.xml similarity index 100% rename from nebula-logger/experience-cloud/pages/CommunitiesLanding.page-meta.xml rename to config/experience-cloud/pages/CommunitiesLanding.page-meta.xml diff --git a/nebula-logger/experience-cloud/pages/CommunitiesLogin.page b/config/experience-cloud/pages/CommunitiesLogin.page similarity index 100% rename from nebula-logger/experience-cloud/pages/CommunitiesLogin.page rename to config/experience-cloud/pages/CommunitiesLogin.page diff --git a/nebula-logger/experience-cloud/pages/CommunitiesLogin.page-meta.xml b/config/experience-cloud/pages/CommunitiesLogin.page-meta.xml similarity index 100% rename from nebula-logger/experience-cloud/pages/CommunitiesLogin.page-meta.xml rename to config/experience-cloud/pages/CommunitiesLogin.page-meta.xml diff --git a/nebula-logger/experience-cloud/pages/CommunitiesSelfReg.page b/config/experience-cloud/pages/CommunitiesSelfReg.page similarity index 100% rename from nebula-logger/experience-cloud/pages/CommunitiesSelfReg.page rename to config/experience-cloud/pages/CommunitiesSelfReg.page diff --git a/nebula-logger/experience-cloud/pages/CommunitiesSelfReg.page-meta.xml b/config/experience-cloud/pages/CommunitiesSelfReg.page-meta.xml similarity index 100% rename from nebula-logger/experience-cloud/pages/CommunitiesSelfReg.page-meta.xml rename to config/experience-cloud/pages/CommunitiesSelfReg.page-meta.xml diff --git a/nebula-logger/experience-cloud/pages/CommunitiesSelfRegConfirm.page b/config/experience-cloud/pages/CommunitiesSelfRegConfirm.page similarity index 100% rename from nebula-logger/experience-cloud/pages/CommunitiesSelfRegConfirm.page rename to config/experience-cloud/pages/CommunitiesSelfRegConfirm.page diff --git a/nebula-logger/experience-cloud/pages/CommunitiesSelfRegConfirm.page-meta.xml b/config/experience-cloud/pages/CommunitiesSelfRegConfirm.page-meta.xml similarity index 100% rename from nebula-logger/experience-cloud/pages/CommunitiesSelfRegConfirm.page-meta.xml rename to config/experience-cloud/pages/CommunitiesSelfRegConfirm.page-meta.xml diff --git a/nebula-logger/experience-cloud/pages/Exception.page b/config/experience-cloud/pages/Exception.page similarity index 100% rename from nebula-logger/experience-cloud/pages/Exception.page rename to config/experience-cloud/pages/Exception.page diff --git a/nebula-logger/experience-cloud/pages/Exception.page-meta.xml b/config/experience-cloud/pages/Exception.page-meta.xml similarity index 100% rename from nebula-logger/experience-cloud/pages/Exception.page-meta.xml rename to config/experience-cloud/pages/Exception.page-meta.xml diff --git a/nebula-logger/experience-cloud/pages/FileNotFound.page b/config/experience-cloud/pages/FileNotFound.page similarity index 100% rename from nebula-logger/experience-cloud/pages/FileNotFound.page rename to config/experience-cloud/pages/FileNotFound.page diff --git a/nebula-logger/experience-cloud/pages/FileNotFound.page-meta.xml b/config/experience-cloud/pages/FileNotFound.page-meta.xml similarity index 100% rename from nebula-logger/experience-cloud/pages/FileNotFound.page-meta.xml rename to config/experience-cloud/pages/FileNotFound.page-meta.xml diff --git a/nebula-logger/experience-cloud/pages/ForgotPasswordConfirm.page b/config/experience-cloud/pages/ForgotPasswordConfirm.page similarity index 100% rename from nebula-logger/experience-cloud/pages/ForgotPasswordConfirm.page rename to config/experience-cloud/pages/ForgotPasswordConfirm.page diff --git a/nebula-logger/experience-cloud/pages/ForgotPasswordConfirm.page-meta.xml b/config/experience-cloud/pages/ForgotPasswordConfirm.page-meta.xml similarity index 100% rename from nebula-logger/experience-cloud/pages/ForgotPasswordConfirm.page-meta.xml rename to config/experience-cloud/pages/ForgotPasswordConfirm.page-meta.xml diff --git a/nebula-logger/experience-cloud/pages/InMaintenance.page b/config/experience-cloud/pages/InMaintenance.page similarity index 100% rename from nebula-logger/experience-cloud/pages/InMaintenance.page rename to config/experience-cloud/pages/InMaintenance.page diff --git a/nebula-logger/experience-cloud/pages/InMaintenance.page-meta.xml b/config/experience-cloud/pages/InMaintenance.page-meta.xml similarity index 100% rename from nebula-logger/experience-cloud/pages/InMaintenance.page-meta.xml rename to config/experience-cloud/pages/InMaintenance.page-meta.xml diff --git a/nebula-logger/experience-cloud/pages/SiteRegisterConfirm.page b/config/experience-cloud/pages/SiteRegisterConfirm.page similarity index 100% rename from nebula-logger/experience-cloud/pages/SiteRegisterConfirm.page rename to config/experience-cloud/pages/SiteRegisterConfirm.page diff --git a/nebula-logger/experience-cloud/pages/SiteRegisterConfirm.page-meta.xml b/config/experience-cloud/pages/SiteRegisterConfirm.page-meta.xml similarity index 100% rename from nebula-logger/experience-cloud/pages/SiteRegisterConfirm.page-meta.xml rename to config/experience-cloud/pages/SiteRegisterConfirm.page-meta.xml diff --git a/nebula-logger/experience-cloud/profiles/Logger Test Site Profile.profile-meta.xml b/config/experience-cloud/profiles/Logger Test Site Profile.profile-meta.xml similarity index 100% rename from nebula-logger/experience-cloud/profiles/Logger Test Site Profile.profile-meta.xml rename to config/experience-cloud/profiles/Logger Test Site Profile.profile-meta.xml diff --git a/nebula-logger/experience-cloud/sites/Logger_Test_Site.site-meta.xml b/config/experience-cloud/sites/Logger_Test_Site.site-meta.xml similarity index 100% rename from nebula-logger/experience-cloud/sites/Logger_Test_Site.site-meta.xml rename to config/experience-cloud/sites/Logger_Test_Site.site-meta.xml diff --git a/config/scratch-orgs/base-scratch-def.json b/config/scratch-orgs/base-scratch-def.json index ce7b50fd4..f565da5ed 100644 --- a/config/scratch-orgs/base-scratch-def.json +++ b/config/scratch-orgs/base-scratch-def.json @@ -12,6 +12,9 @@ "communitiesSettings": { "enableNetworksEnabled": false }, + "pathAssistantSettings": { + "pathAssistantEnabled": true + }, "userManagementSettings": { "enableEnhancedPermsetMgmt": true, "enableEnhancedProfileMgmt": true, diff --git a/config/scratch-orgs/experience-cloud-scratch-def.json b/config/scratch-orgs/experience-cloud-scratch-def.json index 86f826db1..e68b9efaf 100644 --- a/config/scratch-orgs/experience-cloud-scratch-def.json +++ b/config/scratch-orgs/experience-cloud-scratch-def.json @@ -15,6 +15,9 @@ "experienceBundleSettings": { "enableExperienceBundleMetadata": true }, + "pathAssistantSettings": { + "pathAssistantEnabled": true + }, "userManagementSettings": { "enableEnhancedPermsetMgmt": true, "enableEnhancedProfileMgmt": true, diff --git a/docs/apex/configuration/LoggerParameter.md b/docs/apex/Configuration/LoggerParameter.md similarity index 96% rename from docs/apex/configuration/LoggerParameter.md rename to docs/apex/Configuration/LoggerParameter.md index 7cd4c46aa..f758d5de1 100644 --- a/docs/apex/configuration/LoggerParameter.md +++ b/docs/apex/Configuration/LoggerParameter.md @@ -458,4 +458,24 @@ List<String> A list that's retrieved using the parameter if it's not null, otherwise the default list is returned. +#### `matchOnPrefix(String developerNamePrefix)` → `List` + +matchOnPrefix description + +##### Parameters + +| Param | Description | +| --------------------- | ------------------------------------------------------------------------------------------- | +| `developerNamePrefix` | A prefix that has been used in the `DeveloperName` for multiple `LoggerParameter_t` records | + +##### Return + +**Type** + +List<LoggerParameter_t> + +**Description** + +The list of matching `LoggerParameter_t` records + --- diff --git a/docs/apex/Configuration/LoggerPlugin.md b/docs/apex/Configuration/LoggerPlugin.md new file mode 100644 index 000000000..7473b9b6e --- /dev/null +++ b/docs/apex/Configuration/LoggerPlugin.md @@ -0,0 +1,116 @@ +--- +layout: default +--- + +## LoggerPlugin class + +The core of the plugin framework, used to create custom Apex & Flow plugins for `LoggerSObjectHandler` and `LogBatchPurger` based on configurations stored in the custom metadata type `LoggerPlugin_t` + +--- + +### Properties + +#### `pluginConfiguration` → `LoggerPlugin_t` + +--- + +### Methods + +#### `PluginConfigurationSorter(LoggerPlugin_t pluginConfiguration)` → `public` + +#### `compareTo(Object compareTo)` → `Integer` + +#### `getFilteredPluginConfigurations(List populatedFilterFields, Schema.SObjectField sortByField)` → `List` + +Filters the configured `LoggerPlugin_t` records based on a list of `SObjectField` - only records that have a value for 1 or more of the specified `populatedFilterFields` will be returned, sorted by the specified `SObjectField` parameter `sortByField` + +##### Parameters + +| Param | Description | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| `populatedFilterFields` | The list of `SObjectField` to check on each `LoggerPlugin_t` record - filtering logic checks for a non-null value | +| `sortByField` | The `SObjectField` to use to sort the list of matches. The method also uses `DeveloperName` as a secondary field for sorting. | + +##### Return + +**Type** + +List<LoggerPlugin_t> + +**Description** + +The list of matching `LoggerPlugin_t` records + +#### `newBatchableInstance(String apexClassTypeName)` → `Batchable` + +Creates an instance of the class `LoggerPlugin.Batchable` based on the provided `LoggerPlugin_t` configuration + +##### Parameters + +| Param | Description | +| ------------------- | ------------------------------------------------------------------- | +| `apexClassTypeName` | The name of the Apex class that implements `LoggerPlugin.Batchable` | + +##### Return + +**Type** + +Batchable + +**Description** + +The dynamically created instance of `LoggerPlugin.Batchable`, + +#### `newTriggerableInstance(String apexClassTypeName)` → `Triggerable` + +Creates an instance of the class `LoggerPlugin.Triggerable` based on the provided `LoggerPlugin_t` configuration + +##### Parameters + +| Param | Description | +| ------------------- | --------------------------------------------------------------------- | +| `apexClassTypeName` | The name of the Apex class that implements `LoggerPlugin.Triggerable` | + +##### Return + +**Type** + +Triggerable + +**Description** + +The dynamically created instance of `LoggerPlugin.Triggerable`, + +#### `sortBy(Schema.SObjectField field)` → `PluginConfigurationSorter` + +--- + +### Inner Classes + +#### LoggerPlugin.Batchable interface + +Interface used to create plugins that can be used within Logger's batch job `LogBatchPurger` + +--- + +##### Methods + +###### `execute(LoggerPlugin_t configuration, LoggerBatchableContext input, List scopeRecords)` → `void` + +###### `finish(LoggerPlugin_t configuration, LoggerBatchableContext input)` → `void` + +###### `start(LoggerPlugin_t configuration, LoggerBatchableContext input)` → `void` + +--- + +#### LoggerPlugin.Triggerable interface + +Interface used to create plugins that can be used within Logger's trigger handler framework `LoggerSObjectHandler` + +--- + +##### Methods + +###### `execute(LoggerPlugin_t configuration, LoggerTriggerableContext input)` → `void` + +--- diff --git a/docs/apex/log-management/LogBatchPurgeScheduler.md b/docs/apex/Log-Management/LogBatchPurgeScheduler.md similarity index 100% rename from docs/apex/log-management/LogBatchPurgeScheduler.md rename to docs/apex/Log-Management/LogBatchPurgeScheduler.md diff --git a/docs/apex/log-management/LogBatchPurger.md b/docs/apex/Log-Management/LogBatchPurger.md similarity index 73% rename from docs/apex/log-management/LogBatchPurger.md rename to docs/apex/Log-Management/LogBatchPurger.md index b735cfd35..6b4109924 100644 --- a/docs/apex/log-management/LogBatchPurger.md +++ b/docs/apex/Log-Management/LogBatchPurger.md @@ -31,7 +31,7 @@ Required by the Database.Batchable interface, this method executes the logic for | `batchableContext` | - The context of the current batch job. | | `logRecords` | - The log records to purge. | -#### `execute(Database.BatchableContext batchableContext, List loggerRecords)` → `void` +#### `execute(Database.BatchableContext batchableContext, List scopeRecords)` → `void` Required by the Database.Batchable interface, this method executes the logic for purging log records. @@ -40,7 +40,7 @@ Required by the Database.Batchable interface, this method executes the logic for | Param | Description | | ------------------ | --------------------------------------- | | `batchableContext` | - The context of the current batch job. | -| `loggerRecords` | - The log records to purge. | +| `scopeRecords` | - The log records to purge. | #### `finish(Database.BatchableContext batchableContext)` → `void` @@ -52,6 +52,26 @@ Required by the Database.Batchable interface. This method runs after all batch j | ------------------ | ------------------------------- | | `batchableContext` | - The context of the batch jobs | +#### `setChainedBatchSize(Integer chainedBatchSize)` → `LogBatchPurger` + +The `LogBatchPurger` job is designed to run several instances - typically, it runs on `LogEntryTag__c`, then `LogEntry__c`, and finally `Log__c`. This method provides a way to control the batch size used for the chained instances of `LogBachPurger` + +##### Parameters + +| Param | Description | +| ------------------ | ------------------------------------------------------------------------------ | +| `chainedBatchSize` | The batch size to use for any subsequent chained instances of `LogBatchPurger` | + +##### Return + +**Type** + +LogBatchPurger + +**Description** + +The same instance of `LogBatchPurger`, useful for chaining methods + #### `start(Database.BatchableContext batchableContext)` → `Database.QueryLocator` Required by the Database.Batchable interface. Collects the records / objects passed in to the batch instance and returns a Databae.QueryLocator reference representing the current iteration. diff --git a/docs/apex/Log-Management/LogEntryEventHandler.md b/docs/apex/Log-Management/LogEntryEventHandler.md new file mode 100644 index 000000000..15e6b8279 --- /dev/null +++ b/docs/apex/Log-Management/LogEntryEventHandler.md @@ -0,0 +1,45 @@ +--- +layout: default +--- + +## LogEntryEventHandler class + +Processes `LogEntryEvent__e` platform events and normalizes the data into `Log__c` and `LogEntry__c` records + +--- + +### Constructors + +#### `LogEntryEventHandler()` + +## Default constructor, used by the trigger `LogEntryEvent.trigger` + +### Properties + +#### `releaseNumber` → `String` + +String containing the release number. + +#### `releaseVersion` → `String` + +String containing the release version. + +--- + +### Methods + +#### `getSObjectType()` → `SObjectType` + +Returns SObject Type that the handler is responsible for processing + +##### Return + +**Type** + +SObjectType + +**Description** + +The instance of `SObjectType` + +--- diff --git a/docs/apex/log-management/LogEntryFieldSetPicklist.md b/docs/apex/Log-Management/LogEntryFieldSetPicklist.md similarity index 100% rename from docs/apex/log-management/LogEntryFieldSetPicklist.md rename to docs/apex/Log-Management/LogEntryFieldSetPicklist.md diff --git a/docs/apex/log-management/LogEntryHandler.md b/docs/apex/Log-Management/LogEntryHandler.md similarity index 100% rename from docs/apex/log-management/LogEntryHandler.md rename to docs/apex/Log-Management/LogEntryHandler.md diff --git a/docs/apex/log-management/LogEntryTagHandler.md b/docs/apex/Log-Management/LogEntryTagHandler.md similarity index 100% rename from docs/apex/log-management/LogEntryTagHandler.md rename to docs/apex/Log-Management/LogEntryTagHandler.md diff --git a/docs/apex/log-management/LogHandler.md b/docs/apex/Log-Management/LogHandler.md similarity index 100% rename from docs/apex/log-management/LogHandler.md rename to docs/apex/Log-Management/LogHandler.md diff --git a/docs/apex/log-management/LogMassDeleteExtension.md b/docs/apex/Log-Management/LogMassDeleteExtension.md similarity index 100% rename from docs/apex/log-management/LogMassDeleteExtension.md rename to docs/apex/Log-Management/LogMassDeleteExtension.md diff --git a/docs/apex/Log-Management/LoggerBatchableContext.md b/docs/apex/Log-Management/LoggerBatchableContext.md new file mode 100644 index 000000000..9a2b9661d --- /dev/null +++ b/docs/apex/Log-Management/LoggerBatchableContext.md @@ -0,0 +1,40 @@ +--- +layout: default +--- + +## LoggerBatchableContext class + +Class used by the logging system for batch contextual details + +### Related + +[LogBatchPurger](LogBatchPurger) + +[LoggerPlugin](LoggerPlugin) + +--- + +### Constructors + +#### `LoggerBatchableContext(Database.BatchableContext batchableContext, Schema.SObjectType sobjectType)` + +Constructor used to set the 2 properties + +##### Parameters + +| Param | Description | +| ------------------ | ------------------------------------------------------------------------------------------------- | +| `batchableContext` | The instance of `Database.BatchableContextbatchableContext`, provided by the platform at run-time | +| `sobjectType` | The `SObjectType` that will be queried & purged | + +--- + +### Properties + +#### `batchableContext` → `Database.BatchableContext` + +#### `sobjectType` → `Schema.SObjectType` + +#### `sobjectTypeName` → `String` + +--- diff --git a/docs/apex/Log-Management/LoggerEmailSender.md b/docs/apex/Log-Management/LoggerEmailSender.md new file mode 100644 index 000000000..4a37e8515 --- /dev/null +++ b/docs/apex/Log-Management/LoggerEmailSender.md @@ -0,0 +1,35 @@ +--- +layout: default +--- + +## LoggerEmailSender class + +Builds and sends email notifications when internal exceptions occur within the logging system + +--- + +### Methods + +#### `sendErrorEmail(Schema.SObjectType sobjectType, List saveResults)` → `void` + +Sends an error email notification to the org's list of Apex Exception Email recipients, configured under Setup --> Email --> Apex Exception Email + +##### Parameters + +| Param | Description | +| ------------- | -------------------------------------------------------------- | +| `sobjectType` | The SObjectType of records being saved. | +| `saveResults` | The list of Database.SaveResult instances to use in the email. | + +#### `sendErrorEmail(Schema.SObjectType sobjectType, List upsertResults)` → `void` + +Sends an error email notification to the org's list of Apex Exception Email recipients, configured under Setup --> Email --> Apex Exception Email + +##### Parameters + +| Param | Description | +| --------------- | ---------------------------------------------------------------- | +| `sobjectType` | The SObjectType of records being saved. | +| `upsertResults` | The list of Database.UpsertResult instances to use in the email. | + +--- diff --git a/docs/apex/configuration/LoggerEmailUtils.md b/docs/apex/Log-Management/LoggerEmailUtils.md similarity index 100% rename from docs/apex/configuration/LoggerEmailUtils.md rename to docs/apex/Log-Management/LoggerEmailUtils.md diff --git a/docs/apex/Log-Management/LoggerSObjectHandler.md b/docs/apex/Log-Management/LoggerSObjectHandler.md new file mode 100644 index 000000000..e0cce2f10 --- /dev/null +++ b/docs/apex/Log-Management/LoggerSObjectHandler.md @@ -0,0 +1,51 @@ +--- +layout: default +--- + +## LoggerSObjectHandler class + +Abstract class used by trigger handlers for shared logic + +--- + +### Constructors + +#### `LoggerSObjectHandler()` + +## Default constructor + +### Methods + +#### `execute()` → `void` + +Runs the handler class's logic, as well as any configured plugins + +#### `getHandlerControlParameterName()` → `String` + +Returns the string value of the `LoggerParameter_t` record that controls if the handler is enabled. The `LoggerSObjectHandler` class uses this method to retrieve the corresponding `LoggerParameter_t` to determine if the class should execute. + +##### Return + +**Type** + +String + +**Description** + +The `DeveloperName` value of the `LoggerParameter_t` that controls if the handler is enabled + +#### `getSObjectType()` → `Schema.SObjectType` + +Returns the SObject Type that the handler is responsible for processing + +##### Return + +**Type** + +Schema.SObjectType + +**Description** + +The instance of `SObjectType` + +--- diff --git a/docs/apex/Log-Management/LoggerSObjectMetadata.md b/docs/apex/Log-Management/LoggerSObjectMetadata.md new file mode 100644 index 000000000..e72c88b3d --- /dev/null +++ b/docs/apex/Log-Management/LoggerSObjectMetadata.md @@ -0,0 +1,97 @@ +--- +layout: default +--- + +## LoggerSObjectMetadata class + +Provides details to LWCs about Logger's `SObjects`, using `@AuraEnabled` properties + +--- + +### Methods + +#### `getSchema(Schema.SObjectType sobjectType)` → `SObjectSchema` + +Provides schema details about the specified `SObjectType` + +##### Parameters + +| Param | Description | +| ------------- | ------------------------------------------------------------------------------------------------ | +| `sobjectType` | The instance of `SObjectType` to convert to an instance of `LoggerSObjectMetadata.SObjectSchema` | + +##### Return + +**Type** + +SObjectSchema + +**Description** + +An instance of `LoggerSObjectMetadata.SObjectSchema` for the specified `SObjectType` + +#### `getSchemaForName(String sobjectApiName)` → `SObjectSchema` + +Provides schema details about the specified `SObjectType` + +##### Parameters + +| Param | Description | +| ---------------- | ---------------------------------------------------------------------------------------------------- | +| `sobjectApiName` | The API name of the `SObjectType` to convert to an instance of `LoggerSObjectMetadata.SObjectSchema` | + +##### Return + +**Type** + +SObjectSchema + +**Description** + +An instance of `LoggerSObjectMetadata.SObjectSchema` for the specified `SObjectType` + +--- + +### Inner Classes + +#### LoggerSObjectMetadata.FieldSchema class + +Inner class for `SObjectField` details to LWCs, using `@AuraEnabled` properties + +--- + +##### Properties + +###### `apiName` → `String` + +###### `inlineHelpText` → `String` + +###### `label` → `String` + +###### `localApiName` → `String` + +###### `type` → `String` + +--- + +#### LoggerSObjectMetadata.SObjectSchema class + +Inner class for `SObject` details to LWCs, using `@AuraEnabled` properties + +--- + +##### Properties + +###### `apiName` → `String` + +###### `fields` → `Map` + +###### `label` → `String` + +###### `labelPlural` → `String` + +###### `localApiName` → `String` + +###### `namespacePrefix` → `String` + +--- diff --git a/docs/apex/log-management/LoggerSettingsController.md b/docs/apex/Log-Management/LoggerSettingsController.md similarity index 97% rename from docs/apex/log-management/LoggerSettingsController.md rename to docs/apex/Log-Management/LoggerSettingsController.md index 8c0bb6491..7b5eb09b2 100644 --- a/docs/apex/log-management/LoggerSettingsController.md +++ b/docs/apex/Log-Management/LoggerSettingsController.md @@ -135,6 +135,10 @@ Inner class for returning all custom `List<PicklistOption>` in a single Ap ###### `loggingLevelOptions` → `List` +###### `platformEventStorageLocationOptions` → `List` + +###### `purgeActionOptions` → `List` + ###### `saveMethodOptions` → `List` ###### `setupOwnerTypeOptions` → `List` diff --git a/docs/apex/log-management/LoggerTagHandler.md b/docs/apex/Log-Management/LoggerTagHandler.md similarity index 100% rename from docs/apex/log-management/LoggerTagHandler.md rename to docs/apex/Log-Management/LoggerTagHandler.md diff --git a/docs/apex/Log-Management/LoggerTriggerableContext.md b/docs/apex/Log-Management/LoggerTriggerableContext.md new file mode 100644 index 000000000..1b0732f11 --- /dev/null +++ b/docs/apex/Log-Management/LoggerTriggerableContext.md @@ -0,0 +1,57 @@ +--- +layout: default +--- + +## LoggerTriggerableContext class + +Class used by the logging system for trigger contextual details + +### Related + +[LoggerSObjectHandler](LoggerSObjectHandler) + +[LoggerPlugin](LoggerPlugin) + +--- + +### Constructors + +#### `LoggerTriggerableContext(Schema.SObjectType sobjectType,TriggerOperation triggerOperationType,List triggerNew,Map triggerNewMap,Map triggerOldMap)` + +--- + +### Properties + +#### `sobjectType` → `Schema.SObjectType` + +#### `sobjectTypeName` → `String` + +#### `triggerNew` → `List` + +#### `triggerNewMap` → `Map` + +#### `triggerOldMap` → `Map` + +#### `triggerOperationType` → `TriggerOperation` + +#### `triggerOperationTypeName` → `String` + +#### `triggerRecords` → `List` + +--- + +### Inner Classes + +#### LoggerTriggerableContext.RecordInput class + +Class used by the logging system to provide trigger record details to Flow + +--- + +##### Properties + +###### `triggerRecordNew` → `SObject` + +###### `triggerRecordOld` → `SObject` + +--- diff --git a/docs/apex/log-management/RelatedLogEntriesController.md b/docs/apex/Log-Management/RelatedLogEntriesController.md similarity index 100% rename from docs/apex/log-management/RelatedLogEntriesController.md rename to docs/apex/Log-Management/RelatedLogEntriesController.md diff --git a/docs/apex/logger-engine/ComponentLogger.md b/docs/apex/Logger-Engine/ComponentLogger.md similarity index 100% rename from docs/apex/logger-engine/ComponentLogger.md rename to docs/apex/Logger-Engine/ComponentLogger.md diff --git a/docs/apex/logger-engine/FlowCollectionLogEntry.md b/docs/apex/Logger-Engine/FlowCollectionLogEntry.md similarity index 100% rename from docs/apex/logger-engine/FlowCollectionLogEntry.md rename to docs/apex/Logger-Engine/FlowCollectionLogEntry.md diff --git a/docs/apex/logger-engine/FlowLogEntry.md b/docs/apex/Logger-Engine/FlowLogEntry.md similarity index 100% rename from docs/apex/logger-engine/FlowLogEntry.md rename to docs/apex/Logger-Engine/FlowLogEntry.md diff --git a/docs/apex/logger-engine/FlowLogger.md b/docs/apex/Logger-Engine/FlowLogger.md similarity index 100% rename from docs/apex/logger-engine/FlowLogger.md rename to docs/apex/Logger-Engine/FlowLogger.md diff --git a/docs/apex/logger-engine/FlowRecordLogEntry.md b/docs/apex/Logger-Engine/FlowRecordLogEntry.md similarity index 100% rename from docs/apex/logger-engine/FlowRecordLogEntry.md rename to docs/apex/Logger-Engine/FlowRecordLogEntry.md diff --git a/docs/apex/logger-engine/LogEntryEventBuilder.md b/docs/apex/Logger-Engine/LogEntryEventBuilder.md similarity index 93% rename from docs/apex/logger-engine/LogEntryEventBuilder.md rename to docs/apex/Logger-Engine/LogEntryEventBuilder.md index aea6a5c65..88889d6db 100644 --- a/docs/apex/logger-engine/LogEntryEventBuilder.md +++ b/docs/apex/Logger-Engine/LogEntryEventBuilder.md @@ -335,6 +335,46 @@ LogEntryEventBuilder The same instance of `LogEntryEventBuilder`, useful for chaining methods +#### `setHttpRequestDetails(HttpRequest request)` → `LogEntryEventBuilder` + +Sets the log entry event's HTTP Request fields + +##### Parameters + +| Param | Description | +| --------- | ------------------------------------ | +| `request` | The instance of `HttpRequest` to log | + +##### Return + +**Type** + +LogEntryEventBuilder + +**Description** + +The same instance of `LogEntryEventBuilder`, useful for chaining methods + +#### `setHttpResponseDetails(HttpResponse response)` → `LogEntryEventBuilder` + +Sets the log entry event's HTTP Response fields + +##### Parameters + +| Param | Description | +| ---------- | ------------------------------------- | +| `response` | The instance of `HttpResponse` to log | + +##### Return + +**Type** + +LogEntryEventBuilder + +**Description** + +The same instance of `LogEntryEventBuilder`, useful for chaining methods + #### `setMessage(LogMessage logMessage)` → `LogEntryEventBuilder` Sets the log entry event's message field diff --git a/docs/apex/logger-engine/LogMessage.md b/docs/apex/Logger-Engine/LogMessage.md similarity index 100% rename from docs/apex/logger-engine/LogMessage.md rename to docs/apex/Logger-Engine/LogMessage.md diff --git a/docs/apex/logger-engine/Logger.md b/docs/apex/Logger-Engine/Logger.md similarity index 99% rename from docs/apex/logger-engine/Logger.md rename to docs/apex/Logger-Engine/Logger.md index 68889c89a..a95b3e501 100644 --- a/docs/apex/logger-engine/Logger.md +++ b/docs/apex/Logger-Engine/Logger.md @@ -3216,6 +3216,20 @@ LoggingLevel The matching instance of LoggingLevel (or a default value if a match is not found) +#### `getNamespacePrefix()` → `String` + +Returns the current namespace of Nebula Logger + +##### Return + +**Type** + +String + +**Description** + +The current namespace prefix, or an empty string when no namespace is being used + #### `getParentLogTransactionId()` → `String` Returns the transaction ID value that will be used to relate the current transaction's log to a parent log @@ -3334,6 +3348,20 @@ String A string containing the UUID value. +#### `getVersionNumber()` → `String` + +Returns the current version number of Nebula Logger + +##### Return + +**Type** + +String + +**Description** + +The current version number, in the format `v0.0.0` + #### `info(LogMessage logMessage, Database.DeleteResult deleteResult)` → `LogEntryEventBuilder` Creates a new log entry with logging level == `LoggingLevel.INFO` @@ -4200,6 +4228,16 @@ Saves any entries in Logger's buffer, using the specified save method for o | ------------ | ------------------------------------------------------------------------- | | `saveMethod` | The enum value of Logger.SaveMethod to use for this specific save action. | +#### `saveLog(String saveMethodName)` → `void` + +Saves any entries in Logger's buffer, using the specified save method for only this call. All subsequent calls to saveLog() will use the transaction save method. + +##### Parameters + +| Param | Description | +| ---------------- | ------------------------------------------------------------------------- | +| `saveMethodName` | The String value of the save method to use for this specific save action. | + #### `setParentLogTransactionId(String parentTransactionId)` → `void` Relates the current transaction's log to a parent log via the field Log**c.ParentLog**c This is useful for relating multiple asynchronous operations together, such as batch & queueable jobs. @@ -5008,12 +5046,12 @@ Inner class for publishing log entries via the Queueable interface. ###### `execute(System.QueueableContext queueableContext)` → `void` -Required by the Queueable interface, this method contains the logic executed when the current instance of the queue runs. +Asynchronoulsy publishes the list of `LogEntryEvent__e` records ####### Parameters -| Param | Description | -| ------------------ | --------------------------------- | -| `queueableContext` | The context of the current queue. | +| Param | Description | +| ------------------ | ---------------------------------------------------------- | +| `queueableContext` | The context of the current queue, provided by the platform | --- diff --git a/docs/apex/Logger-Engine/LoggerDataStore.md b/docs/apex/Logger-Engine/LoggerDataStore.md new file mode 100644 index 000000000..02c043111 --- /dev/null +++ b/docs/apex/Logger-Engine/LoggerDataStore.md @@ -0,0 +1,537 @@ +--- +layout: default +--- + +## LoggerDataStore class + +Class used to manage any data-related operations, including database DML statements, publishing platform events via the event bus, and enqueueing queueable jobs + +--- + +### Methods + +#### `getDatabase()` → `Database` + +The instance `LoggerDataStore.Database` used for any DML operations in the current transaction. + +##### Return + +**Type** + +Database + +**Description** + +The singleton instance of `LoggerDataStore.Database` + +#### `getEventBus()` → `EventBus` + +The instance `LoggerDataStore.EventBus` used for publishing platform events in the current transaction. + +##### Return + +**Type** + +EventBus + +**Description** + +The singleton instance of `LoggerDataStore.EventBus` + +#### `getJobQueue()` → `JobQueue` + +The instance `LoggerDataStore.JobQueue` used for enqueuing any queueable jobs in the current transaction. + +##### Return + +**Type** + +JobQueue + +**Description** + +The singleton instance of `LoggerDataStore.JobQueue` + +--- + +### Inner Classes + +#### LoggerDataStore.Database class + +Class used to centralize the handling of any DML operations + +--- + +##### Methods + +###### `deleteRecord(SObject record)` → `Database.DeleteResult` + +Executes a `delete` DML operation for the `SObject` record + +####### Parameters + +| Param | Description | +| -------- | ------------------------------ | +| `record` | The `SObject` record to delete | + +####### Return + +**Type** + +Database.DeleteResult + +**Description** + +The instance of `Database.DeleteResult`, generated by the platform when deleting the record + +###### `deleteRecords(List records)` → `List` + +Executes a `delete` DML operation on the provided list of `SObject` records + +####### Parameters + +| Param | Description | +| --------- | --------------------------------------- | +| `records` | The list of `SObject` records to delete | + +####### Return + +**Type** + +List<Database.DeleteResult> + +**Description** + +The instance of `List<Database.DeleteResult>`, generated by the platform when deleting the records + +###### `deleteRecords(List records, Boolean allOrNone)` → `List` + +Executes a `delete` DML operation on the provided list of `SObject` records + +####### Parameters + +| Param | Description | +| ----------- | ------------------------------------------------------------------------------------------------- | +| `records` | The list of `SObject` records to delete | +| `allOrNone` | Controls if all records must be deleted (`true`), or if partial deletion should be used (`false`) | + +####### Return + +**Type** + +List<Database.DeleteResult> + +**Description** + +The instance of `List<Database.DeleteResult>`, generated by the platform when deleting the records + +###### `hardDeleteRecord(SObject record)` → `Database.DeleteResult` + +Executes a `delete` DML operation for the `SObject` record, followed by hard deleting the record using `Database.emptyRecycleBin(record)` + +####### Parameters + +| Param | Description | +| -------- | ------------------------------ | +| `record` | The `SObject` record to delete | + +####### Return + +**Type** + +Database.DeleteResult + +**Description** + +The instance of `Database.DeleteResult`, generated by the platform when deleting the record + +###### `hardDeleteRecords(List records)` → `List` + +Executes a `delete` DML operation on the provided list of `SObject` records, followed by hard deleting the records using `Database.emptyRecycleBin(records)` + +####### Parameters + +| Param | Description | +| --------- | --------------------------------------- | +| `records` | The list of `SObject` records to delete | + +####### Return + +**Type** + +List<Database.DeleteResult> + +**Description** + +The instance of `List<Database.DeleteResult>`, generated by the platform when deleting the records + +###### `insertRecord(SObject record)` → `Database.SaveResult` + +Executes an `insert` DML operation on the provided `SObject` record + +####### Parameters + +| Param | Description | +| -------- | ------------------------------ | +| `record` | The `SObject` record to insert | + +####### Return + +**Type** + +Database.SaveResult + +**Description** + +The instance of `Database.SaveResult`, generated by the platform when creating the record + +###### `insertRecords(List records)` → `List` + +Executes an `insert` DML operation on the provided list of `SObject` records + +####### Parameters + +| Param | Description | +| --------- | --------------------------------------- | +| `records` | The list of `SObject` records to insert | + +####### Return + +**Type** + +List<Database.SaveResult> + +**Description** + +The instance of `List<Database.SaveResult>`, generated by the platform when creating the records + +###### `insertRecords(List records, Boolean allOrNone)` → `List` + +Executes an `insert` DML operation on the provided list of `SObject` records + +####### Parameters + +| Param | Description | +| ----------- | ------------------------------------------------------------------------------------------------- | +| `records` | The list of `SObject` records to insert | +| `allOrNone` | Controls if all records must be created (`true`), or if partial creation should be used (`false`) | + +####### Return + +**Type** + +List<Database.SaveResult> + +**Description** + +The instance of `List<Database.SaveResult>`, generated by the platform when creating the records + +###### `insertRecords(List records, Database.DmlOptions dmlOptions)` → `List` + +Executes an `insert` DML operation on the provided list of `SObject` records + +####### Parameters + +| Param | Description | +| ------------ | ------------------------------------------------------------------------------------- | +| `records` | The list of `SObject` records to insert | +| `dmlOptions` | Controls additional DML options, using the provided instance of `Database.DmlOptions` | + +####### Return + +**Type** + +List<Database.SaveResult> + +**Description** + +The instance of `List<Database.SaveResult>`, generated by the platform when creating the records + +###### `undeleteRecord(SObject record)` → `Database.UndeleteResult` + +Executes an `undelete` DML operation on the provided `SObject` record + +####### Parameters + +| Param | Description | +| -------- | -------------------------------- | +| `record` | The `SObject` record to undelete | + +####### Return + +**Type** + +Database.UndeleteResult + +**Description** + +The instance of `Database.UndeleteResult`, generated by the platform when undeleting the record + +###### `undeleteRecords(List records)` → `List` + +Executes an `undelete` DML operation on the provided list of `SObject` records + +####### Parameters + +| Param | Description | +| --------- | ----------------------------------------- | +| `records` | The list of `SObject` records to undelete | + +####### Return + +**Type** + +List<Database.UndeleteResult> + +**Description** + +The instance of `List<Database.UndeleteResult>`, generated by the platform when deleting the records + +###### `undeleteRecords(List records, Boolean allOrNone)` → `List` + +Executes an `undelete` DML operation on the provided list of `SObject` records + +####### Parameters + +| Param | Description | +| ----------- | ----------------------------------------------------------------------------------------------------- | +| `records` | The list of `SObject` records to undelete | +| `allOrNone` | Controls if all records must be undeleted (`true`), or if partial undeletion should be used (`false`) | + +####### Return + +**Type** + +List<Database.UndeleteResult> + +**Description** + +The instance of `List<Database.DeleteResult>`, generated by the platform when undeleting the records + +###### `updateRecord(SObject record)` → `Database.SaveResult` + +Executes an `update` DML operation on the provided `SObject` record + +####### Parameters + +| Param | Description | +| -------- | ------------------------------ | +| `record` | The `SObject` record to update | + +####### Return + +**Type** + +Database.SaveResult + +**Description** + +The instance of `Database.SaveResult`, generated by the platform when updating the record + +###### `updateRecords(List records)` → `List` + +Executes an `update` DML operation on the provided list of `SObject` records + +####### Parameters + +| Param | Description | +| --------- | --------------------------------------- | +| `records` | The list of `SObject` records to update | + +####### Return + +**Type** + +List<Database.SaveResult> + +**Description** + +The instance of `List<Database.SaveResult>`, generated by the platform when updating the records + +###### `updateRecords(List records, Boolean allOrNone)` → `List` + +Executes an `update` DML operation on the provided list of `SObject` records + +####### Parameters + +| Param | Description | +| ----------- | ------------------------------------------------------------------------------------------------ | +| `records` | The list of `SObject` records to update | +| `allOrNone` | Controls if all records must be updated (`true`), or if partial updates should be used (`false`) | + +####### Return + +**Type** + +List<Database.SaveResult> + +**Description** + +The instance of `List<Database.SaveResult>`, generated by the platform when updating the records + +###### `updateRecords(List records, Database.DmlOptions dmlOptions)` → `List` + +Executes an `update` DML operation on the provided list of `SObject` records + +####### Parameters + +| Param | Description | +| ------------ | ------------------------------------------------------------------------------------- | +| `records` | The list of `SObject` records to update | +| `dmlOptions` | Controls additional DML options, using the provided instance of `Database.DmlOptions` | + +####### Return + +**Type** + +List<Database.SaveResult> + +**Description** + +The instance of `List<Database.SaveResult>`, generated by the platform when updating the records + +###### `upsertRecord(SObject record, Schema.SObjectField externalIdField)` → `Database.UpsertResult` + +Executes an `upsert` DML operation on the provided list of `SObject` records + +####### Parameters + +| Param | Description | +| ----------------- | ---------------------------------------------------------------------------------------- | +| `record` | The `SObject` record to update | +| `externalIdField` | The `SObjectField` of the external ID field on the target `SObject` to use for upserting | + +####### Return + +**Type** + +Database.UpsertResult + +**Description** + +The instance of `Database.UpsertResult`, generated by the platform when upserting the record + +###### `upsertRecords(List records, Schema.SObjectField externalIdField)` → `List` + +Executes an `upsert` DML operation on the provided list of `SObject` records + +####### Parameters + +| Param | Description | +| ----------------- | ---------------------------------------------------------------------------------------- | +| `records` | The list of `SObject` records to upsert | +| `externalIdField` | The `SObjectField` of the external ID field on the target `SObject` to use for upserting | + +####### Return + +**Type** + +List<Database.UpsertResult> + +**Description** + +The instance of `List<Database.UpsertResult>`, generated by the platform when Upserting the records + +###### `upsertRecords(List records, Schema.SObjectField externalIdField, Boolean allOrNone)` → `List` + +Executes an `upsert` DML operation on the provided list of `SObject` records + +####### Parameters + +| Param | Description | +| ----------------- | ------------------------------------------------------------------------------------------------ | +| `records` | The list of `SObject` records to upsert | +| `externalIdField` | The `SObjectField` of the external ID field on the target `SObject` to use for upserting | +| `allOrNone` | Controls if all records must be updated (`true`), or if partial updates should be used (`false`) | + +####### Return + +**Type** + +List<Database.UpsertResult> + +**Description** + +The instance of `List<Database.UpsertResult>`, generated by the platform when Upserting the records + +--- + +#### LoggerDataStore.EventBus class + +Class used to centralize the handling of any platform event publishing operations + +--- + +##### Methods + +###### `publishRecord(SObject platformEvent)` → `Database.SaveResult` + +Publishes a single platform event record, using `EventBus.publish(SObject record); + +####### Parameters + +| Param | Description | +| --------------- | ------------------------------------ | +| `platformEvent` | The platform event record to publish | + +####### Return + +**Type** + +Database.SaveResult + +**Description** + +The instance of `Database.SaveResult`, generated by the platform when publishing the platform event record + +###### `publishRecords(List platformEvents)` → `List` + +Publishes a list of platform event records, using `EventBus.publish(List<SObject> records); + +####### Parameters + +| Param | Description | +| ---------------- | --------------------------------------------- | +| `platformEvents` | The list of platform event records to publish | + +####### Return + +**Type** + +List<Database.SaveResult> + +**Description** + +The instance of `List<Database.SaveResult>`, generated by the platform when publishing the platform event records + +--- + +#### LoggerDataStore.JobQueue class + +Class used to centralize the handling of enqueueing any queueable jobs + +--- + +##### Methods + +###### `enqueueJob(Queueable queueableJob)` → `Id` + +Enqueues a queueable job to execute asynchronously, using `System.enqueueJob(Queueable queueableJob)` + +####### Parameters + +| Param | Description | +| -------------- | ---------------------------------------------------------- | +| `queueableJob` | An instance of a `Queueable` class that should be enqueued | + +####### Return + +**Type** + +Id + +**Description** + +The `Id` of the queueable job + +--- diff --git a/docs/apex/Logger-Engine/LoggerSObjectHandler.md b/docs/apex/Logger-Engine/LoggerSObjectHandler.md new file mode 100644 index 000000000..0264de571 --- /dev/null +++ b/docs/apex/Logger-Engine/LoggerSObjectHandler.md @@ -0,0 +1,98 @@ +--- +layout: default +--- + +## LoggerSObjectHandler class + +Abstract class used by trigger handlers for shared logic + +--- + +### Constructors + +#### `LoggerSObjectHandler()` + +## Default constructor + +### Methods + +#### `execute()` → `void` + +Runs the handler class's logic, as well as any configured plugins + +#### `getHandler(Schema.SObjectType sobjectType)` → `LoggerSObjectHandler` + +Returns an instance of `LoggerSObjectHandler` that has been built & configured for the specified `SObjectType` + +##### Parameters + +| Param | Description | +| ------------- | --------------------------------------------------------------------------------------- | +| `sobjectType` | The instance `SObjectType` to check for a configured instance of `LoggerSObjectHandler` | + +##### Return + +**Type** + +LoggerSObjectHandler + +**Description** + +The Apex class that extends `LoggerSObjectHandler` and has been configured for the specified `SObjectType` + +#### `getHandler(Schema.SObjectType sobjectType, LoggerSObjectHandler defaultImplementation)` → `LoggerSObjectHandler` + +Returns an instance of `LoggerSObjectHandler` that has been built & configured for the specified `SObjectType` + +##### Parameters + +| Param | Description | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| `sobjectType` | The instance `SObjectType` to check for a configured instance of `LoggerSObjectHandler` | +| `defaultImplementation` | A default implementation of `LoggerSObjectHandler` that should be used, if a configuration cannot be found `LoggerSObjectHandler_t` | + +##### Return + +**Type** + +LoggerSObjectHandler + +**Description** + +The Apex class that extends `LoggerSObjectHandler` and has been configured for the specified `SObjectType` + +#### `getSObjectType()` → `Schema.SObjectType` + +Returns the SObject Type that the handler is responsible for processing + +##### Return + +**Type** + +Schema.SObjectType + +**Description** + +The instance of `SObjectType` + +#### `overrideTriggerableContext(LoggerTriggerableContext input)` → `LoggerSObjectHandler` + +Provides the ability to override the instance `LoggerTriggerableContext` that is normally provided internally by `LoggerSObjectHandler` + +##### Parameters + +| Param | Description | +| ------- | ---------------------------------------------------------------------------------- | +| `input` | The instance of `LoggerTriggerableContext` to use within the trigger handler class | + +##### Return + +**Type** + +LoggerSObjectHandler + +**Description** + +The same instance of `LoggerSObjectHandler`, useful for chaining methods + +--- diff --git a/docs/apex/Logger-Engine/LoggerTriggerableContext.md b/docs/apex/Logger-Engine/LoggerTriggerableContext.md new file mode 100644 index 000000000..7662ab991 --- /dev/null +++ b/docs/apex/Logger-Engine/LoggerTriggerableContext.md @@ -0,0 +1,59 @@ +--- +layout: default +--- + +## LoggerTriggerableContext class + +Class used by the logging system for trigger contextual details + +### Related + +[LoggerSObjectHandler](LoggerSObjectHandler) + +[LoggerPlugin](LoggerPlugin) + +--- + +### Constructors + +#### `LoggerTriggerableContext(Schema.SObjectType sobjectType, TriggerOperation triggerOperationType, List triggerNew)` + +#### `LoggerTriggerableContext(Schema.SObjectType sobjectType,TriggerOperation triggerOperationType,List triggerNew,Map triggerNewMap,Map triggerOldMap)` + +--- + +### Properties + +#### `sobjectType` → `Schema.SObjectType` + +#### `sobjectTypeName` → `String` + +#### `triggerNew` → `List` + +#### `triggerNewMap` → `Map` + +#### `triggerOldMap` → `Map` + +#### `triggerOperationType` → `TriggerOperation` + +#### `triggerOperationTypeName` → `String` + +#### `triggerRecords` → `List` + +--- + +### Inner Classes + +#### LoggerTriggerableContext.RecordInput class + +Class used by the logging system to provide trigger record details to Flow + +--- + +##### Properties + +###### `triggerRecordNew` → `SObject` + +###### `triggerRecordOld` → `SObject` + +--- diff --git a/docs/apex/Plugins/LogEntryArchiveBuilder.md b/docs/apex/Plugins/LogEntryArchiveBuilder.md new file mode 100644 index 000000000..7b3b9a0a4 --- /dev/null +++ b/docs/apex/Plugins/LogEntryArchiveBuilder.md @@ -0,0 +1,57 @@ +--- +layout: default +--- + +## LogEntryArchiveBuilder class + +Builder class to create an instance of `LogEntryArchive__b`, used by the BigObject plugin + +### Related + +[LogEntryArchivePlugin](../Plugins/LogEntryArchivePlugin) + +[LogEntryEventBuilder](LogEntryEventBuilder) + +--- + +### Constructors + +#### `LogEntryArchiveBuilder(LogEntryEvent__e logEntryEvent)` + +Used by `LogEntryArchivePlugin` to instantiate a new instance of `LogEntryArchiveBuilder` + +##### Parameters + +| Param | Description | +| --------------- | ------------------------------------------------------------------------------------- | +| `logEntryEvent` | The `LogEntryEvent__e` record that will be converted to a `LogEntryArchive__b` record | + +#### `LogEntryArchiveBuilder(LogEntry__c logEntry)` + +Used by `LogEntryArchivePlugin` to instantiate a new instance of `LogEntryArchiveBuilder` + +##### Parameters + +| Param | Description | +| ---------- | -------------------------------------------------------------------------------- | +| `logEntry` | The `LogEntry__c` record that will be converted to a `LogEntryArchive__b` record | + +--- + +### Methods + +#### `getLogEntryArchive()` → `LogEntryArchive__b` + +Returns the `LogEntryArchive__b` record for this instance of LogEntryEventBuilder + +##### Return + +**Type** + +LogEntryArchive\_\_b + +**Description** + +The `LogEntryArchive__b` record + +--- diff --git a/docs/apex/Plugins/LogEntryArchiveController.md b/docs/apex/Plugins/LogEntryArchiveController.md new file mode 100644 index 000000000..1a9123684 --- /dev/null +++ b/docs/apex/Plugins/LogEntryArchiveController.md @@ -0,0 +1,33 @@ +--- +layout: default +--- + +## LogEntryArchiveController class + +Controller class used by the LWC `logEntryArchives` to display `LogEntryArchive__b` data + +### Related + +[LogEntryArchivePlugin](../Plugins/LogEntryArchivePlugin) + +[LogEntryEventBuilder](LogEntryEventBuilder) + +--- + +### Methods + +#### `getLogEntryArchives()` → `List` + +Returns a list of `LogEntryArchive__b` records, based on the current user's record access + +##### Return + +**Type** + +List<LogEntryArchive\_\_b> + +**Description** + +The list of `LogEntryArchive__b` records + +--- diff --git a/docs/apex/Plugins/LogEntryArchivePlugin.md b/docs/apex/Plugins/LogEntryArchivePlugin.md new file mode 100644 index 000000000..095b6a696 --- /dev/null +++ b/docs/apex/Plugins/LogEntryArchivePlugin.md @@ -0,0 +1,68 @@ +--- +layout: default +--- + +## LogEntryArchivePlugin class + +Optional plugin that provides a BigObject, `LogEntryArchive__b`, as an alternative option to the platform event `LogEntryEvent__e` + +### Related + +[LoggerPlugin](LoggerPlugin) + +--- + +### Constructors + +#### `LogEntryArchivePlugin()` + +## Default constructor + +### Methods + +#### `execute(LoggerPlugin_t configuration, LoggerBatchableContext input, List loggerRecords)` → `void` + +Converts any `LogEntry__c` records into `LogEntryArchive__b` records + +##### Parameters + +| Param | Description | +| --------------- | ------------------------------------------------------------------------ | +| `configuration` | The instance of `LoggerPlugin_t` configured for this specific plugin | +| `input` | The instance of `LoggerBatchableContext`, provided by the logging system | +| `loggerRecords` | The list of `SObject` scope records provider by `LogBatchPurger` | + +#### `execute(LoggerPlugin_t configuration, LoggerTriggerableContext input)` → `void` + +Handles converting Logger's buffer of `LogEntryEvent__e` records into `LogEntryArchive__b` records for any user with the included custom save method 'BIG_OBJECT' + +##### Parameters + +| Param | Description | +| --------------- | -------------------------------------------------------------------------- | +| `configuration` | The instance of `LoggerPlugin_t` configured for this specific plugin | +| `input` | The instance of `LoggerTriggerableContext`, provided by the logging system | + +#### `finish(LoggerPlugin_t configuration, LoggerBatchableContext input)` → `void` + +No-op method, required by the interface `LoggerPlugin.Batchable` + +##### Parameters + +| Param | Description | +| --------------- | ------------------------------------------------------------------------ | +| `configuration` | The instance of `LoggerPlugin_t` configured for this specific plugin | +| `input` | The instance of `LoggerBatchableContext`, provided by the logging system | + +#### `start(LoggerPlugin_t configuration, LoggerBatchableContext input)` → `void` + +Skips directly deleting `LogEntryTag__c` records in `LogBatchPurger` so that the tags can be included when `LogEntry__c` records are archived into `LogEntryArchive__b` + +##### Parameters + +| Param | Description | +| --------------- | ------------------------------------------------------------------------ | +| `configuration` | The instance of `LoggerPlugin_t` configured for this specific plugin | +| `input` | The instance of `LoggerBatchableContext`, provided by the logging system | + +--- diff --git a/docs/apex/Plugins/LogRetentionRulesPlugin.md b/docs/apex/Plugins/LogRetentionRulesPlugin.md new file mode 100644 index 000000000..d616a94fc --- /dev/null +++ b/docs/apex/Plugins/LogRetentionRulesPlugin.md @@ -0,0 +1,54 @@ +--- +layout: default +--- + +## LogRetentionRulesPlugin class + +Optional plugin that adds the ability to create & deploy advanced, configurable rules for setting the retention date of `Log__c` records, using custom metadata types `LogRetentionRule_t` and `LogRetentionRuleCondition_t`. + +--- + +### Properties + +#### `conditions` → `List` + +#### `conditionsLogic` → `String` + +#### `conditionsLogicType` → `String` + +#### `matchesFilter` → `Boolean` + +#### `record` → `SObject` + +#### `rule` → `LogRetentionRule_t` + +--- + +### Methods + +#### `FieldPath(Schema.SObjectType sobjectType, String fieldPath)` → `public` + +#### `FilterResult(SObject record, LogRetentionRule_t rule, List filterConditions)` → `public` + +#### `evaluate(String x)` → `Boolean` + +#### `execute(LoggerPlugin_t configuration, LoggerTriggerableContext input)` → `void` + +Handles converting Logger's buffer of `LogEntryEvent__e` records into `LogEntryArchive__b` records for any user with the included custom save method 'BIG_OBJECT' + +##### Parameters + +| Param | Description | +| --------------- | -------------------------------------------------------------------------- | +| `configuration` | The instance of `LoggerPlugin_t` configured for this specific plugin | +| `input` | The instance of `LoggerTriggerableContext`, provided by the logging system | + +#### `getCondition()` → `String` + +#### `getField()` → `Schema.SObjectField` + +#### `getValue(SObject record)` → `Object` + +#### `matchesFilter()` → `Boolean` + +--- diff --git a/docs/apex/Plugins/SlackLoggerPlugin.md b/docs/apex/Plugins/SlackLoggerPlugin.md new file mode 100644 index 000000000..295878e05 --- /dev/null +++ b/docs/apex/Plugins/SlackLoggerPlugin.md @@ -0,0 +1,82 @@ +--- +layout: default +--- + +## SlackLoggerPlugin class + +Optional plugin that integrates with Slack to send alerts for important logs + +--- + +### Constructors + +#### `SlackLoggerPlugin()` + +## Default constructor + +### Properties + +#### `actions` → `List` + +#### `attachments` → `List` + +#### `author_icon` → `String` + +#### `author_link` → `String` + +#### `author_name` → `String` + +#### `color` → `String` + +#### `fallback` → `String` + +#### `fields` → `List` + +#### `isShort` → `Boolean` + +#### `pretext` → `String` + +#### `text` → `String` + +#### `text` → `String` + +#### `text` → `String` + +#### `title` → `String` + +#### `title` → `String` + +#### `title_link` → `String` + +#### `type` → `String` + +#### `url` → `String` + +#### `value` → `String` + +--- + +### Methods + +#### `execute(LoggerPlugin_t configuration, LoggerTriggerableContext input)` → `void` + +Handles the integration with Slack. This method is automatically called by Nebula Logger's plugin framework. + +##### Parameters + +| Param | Description | +| --------------- | -------------------------------------------------------------------------- | +| `configuration` | The instance of `LoggerPlugin_t` configured for this specific plugin | +| `input` | The instance of `LoggerTriggerableContext`, provided by the logging system | + +#### `execute(System.QueueableContext queueableContext)` → `void` + +Handles the queuable execute logic. Required by the Queueable interface. + +##### Parameters + +| Param | Description | +| ------------------ | ----------------------------------------- | +| `queueableContext` | Context of the current queuable instance. | + +--- diff --git a/docs/apex/Test-Utilities/LoggerMockDataCreator.md b/docs/apex/Test-Utilities/LoggerMockDataCreator.md new file mode 100644 index 000000000..3c1ede437 --- /dev/null +++ b/docs/apex/Test-Utilities/LoggerMockDataCreator.md @@ -0,0 +1,683 @@ +--- +layout: default +--- + +## LoggerMockDataCreator class + +Utility class used to help with generating mock data when writing Apex tests for Nebula Logger. These methods are generic, and should work in any Salesforce org. These methods can be used when writing Apex tests for plugins. + +### Related + +[LoggerMockDataStore](../Test-Utilities/LoggerMockDataStore) + +[LoggerTestConfigurator](../Test-Utilities/LoggerTestConfigurator) + +--- + +### Methods + +#### `createAggregateResult()` → `AggregateResult` + +Instances of `AggregateResult` can not be created directly in Apex. This method uses a workaround to generate a mock. + +##### Return + +**Type** + +AggregateResult + +**Description** + +The mock instance of `AggregateResult` + +#### `createAggregateResult(Map mockAggregateKeyValues)` → `AggregateResult` + +Instances of `AggregateResult` can not be created directly in Apex. This method uses a workaround to generate a mock, using the provided map of aliases & aggregate values + +##### Parameters + +| Param | Description | +| ------------------------ | --------------------------------------------------------------------------------------- | +| `mockAggregateKeyValues` | A map of aliases & aggregate values to use when creating the mock `AggregateResult` | + +##### Return + +**Type** + +AggregateResult + +**Description** + +The mock instance of `AggregateResult` + +#### `createBatchableContext(String jobId)` → `MockBatchableContext` + +Creates an instance of the class `MockBatchableContext` that implements the interface `Database.BatchableContext`. This can be used when testing batch jobs. + +##### Parameters + +| Param | Description | +| ------- | --------------------------------------------------------------------------------------- | +| `jobId` | A string value to use as the batchable job ID - this can be a true ID, or just a string | + +##### Return + +**Type** + +MockBatchableContext + +**Description** + +The instance of `MockBatchableContext` + +#### `createDataBuilder(Schema.SObjectType sobjectType)` → `SObjectTestDataBuilder` + +Creates a new builder instance for the specified `SObjectType`, including creating a new `SObject` record. The new `SObject` record is created with any default field values that have been configured on the `SObjectType`. + +##### Parameters + +| Param | Description | +| ------------- | ------------------------------------------------------------------- | +| `sobjectType` | The `SObjectType` to use for generating a new test `SObject` record | + +##### Return + +**Type** + +SObjectTestDataBuilder + +**Description** + +A new instance of `SObjectTestDataBuilder` for the specified `SObjectType` + +#### `createDataBuilder(SObject record)` → `SObjectTestDataBuilder` + +Creates a new builder instance for the specified `SObject` record + +##### Parameters + +| Param | Description | +| -------- | --------------------------------------------------------------- | +| `record` | The existing test `SObject` record to populate with sample data | + +##### Return + +**Type** + +SObjectTestDataBuilder + +**Description** + +A new instance of `SObjectTestDataBuilder` for the specified `SObject` + +#### `createDatabaseDeleteResult(Boolean isSuccess)` → `Database.DeleteResult` + +Creates a mock instance of `Database.DeleteResult` - a mock is used instead of an actual instance to help speed up tests, and to support writing unit tests (instead of integration tests). A fake record ID is automatically included. + +##### Parameters + +| Param | Description | +| ----------- | --------------------------------------------------------------- | +| `isSuccess` | Indicates if the generated mock should have `isSuccess` == true | + +##### Return + +**Type** + +Database.DeleteResult + +**Description** + +The mock instance of `Database.DeleteResult` + +#### `createDatabaseDeleteResult(Boolean isSuccess, Id recordId)` → `Database.DeleteResult` + +Creates a mock instance of `Database.DeleteResult` - a mock is used instead of an actual instance to help speed up tests, and to support writing unit tests (instead of integration tests) + +##### Parameters + +| Param | Description | +| ----------- | --------------------------------------------------------------- | +| `isSuccess` | Indicates if the generated mock should have `isSuccess` == true | +| `recordId` | The record ID to use within the mock result | + +##### Return + +**Type** + +Database.DeleteResult + +**Description** + +The mock instance of `Database.DeleteResult` + +#### `createDatabaseMergeResult(Boolean isSuccess)` → `Database.MergeResult` + +Creates a mock instance of `Database.MergeResult` - a mock is used instead of an actual instance to help speed up tests, and to support writing unit tests (instead of integration tests). A fake record ID is automatically included. + +##### Parameters + +| Param | Description | +| ----------- | --------------------------------------------------------------- | +| `isSuccess` | Indicates if the generated mock should have `isSuccess` == true | + +##### Return + +**Type** + +Database.MergeResult + +**Description** + +The mock instance of `Database.MergeResult` + +#### `createDatabaseMergeResult(Boolean isSuccess, Id recordId)` → `Database.MergeResult` + +Creates a mock instance of `Database.MergeResult` - a mock is used instead of an actual instance to help speed up tests, and to support writing unit tests (instead of integration tests) + +##### Parameters + +| Param | Description | +| ----------- | --------------------------------------------------------------- | +| `isSuccess` | Indicates if the generated mock should have `isSuccess` == true | +| `recordId` | The record ID to use within the mock result | + +##### Return + +**Type** + +Database.MergeResult + +**Description** + +The mock instance of `Database.MergeResult` + +#### `createDatabaseSaveResult(Boolean isSuccess)` → `Database.SaveResult` + +Creates a mock instance of `Database.SaveResult` - a mock is used instead of an actual instance to help speed up tests, and to support writing unit tests (instead of integration tests). A fake record ID is automatically included. + +##### Parameters + +| Param | Description | +| ----------- | --------------------------------------------------------------- | +| `isSuccess` | Indicates if the generated mock should have `isSuccess` == true | + +##### Return + +**Type** + +Database.SaveResult + +**Description** + +The mock instance of `Database.SaveResult` + +#### `createDatabaseSaveResult(Boolean isSuccess, Id recordId)` → `Database.SaveResult` + +Creates a mock instance of `Database.SaveResult` - a mock is used instead of an actual instance to help speed up tests, and to support writing unit tests (instead of integration tests) + +##### Parameters + +| Param | Description | +| ----------- | --------------------------------------------------------------- | +| `isSuccess` | Indicates if the generated mock should have `isSuccess` == true | +| `recordId` | The record ID to use within the mock result | + +##### Return + +**Type** + +Database.SaveResult + +**Description** + +The mock instance of `Database.SaveResult` + +#### `createDatabaseUndeleteResult(Boolean isSuccess)` → `Database.UndeleteResult` + +Creates a mock instance of `Database.UndeleteResult` - a mock is used instead of an actual instance to help speed up tests, and to support writing unit tests (instead of integration tests). A fake record ID is automatically included. + +##### Parameters + +| Param | Description | +| ----------- | --------------------------------------------------------------- | +| `isSuccess` | Indicates if the generated mock should have `isSuccess` == true | + +##### Return + +**Type** + +Database.UndeleteResult + +**Description** + +The mock instance of `Database.UndeleteResult` + +#### `createDatabaseUndeleteResult(Boolean isSuccess, Id recordId)` → `Database.UndeleteResult` + +Creates a mock instance of `Database.UndeleteResult` - a mock is used instead of an actual instance to help speed up tests, and to support writing unit tests (instead of integration tests) + +##### Parameters + +| Param | Description | +| ----------- | --------------------------------------------------------------- | +| `isSuccess` | Indicates if the generated mock should have `isSuccess` == true | +| `recordId` | The record ID to use within the mock result | + +##### Return + +**Type** + +Database.UndeleteResult + +**Description** + +The mock instance of `Database.UndeleteResult` + +#### `createDatabaseUpsertResult(Boolean isSuccess, Boolean isCreated)` → `Database.UpsertResult` + +Creates a mock instance of `Database.UpsertResult` - a mock is used instead of an actual instance to help speed up tests, and to support writing unit tests (instead of integration tests). A fake record ID is automatically included. + +##### Parameters + +| Param | Description | +| ----------- | --------------------------------------------------------------- | +| `isSuccess` | Indicates if the generated mock should have `isSuccess` == true | +| `isCreated` | Indicates if the generated mock should have `isCreated` == true | + +##### Return + +**Type** + +Database.UpsertResult + +**Description** + +The mock instance of `Database.UpsertResult` + +#### `createDatabaseUpsertResult(Boolean isSuccess, Boolean isCreated, Id recordId)` → `Database.UpsertResult` + +Creates a mock instance of `Database.UpsertResult` - a mock is used instead of an actual instance to help speed up tests, and to support writing unit tests (instead of integration tests) + +##### Parameters + +| Param | Description | +| ----------- | --------------------------------------------------------------- | +| `isSuccess` | Indicates if the generated mock should have `isSuccess` == true | +| `isCreated` | Indicates if the generated mock should have `isCreated` == true | +| `recordId` | The record ID to use within the mock result | + +##### Return + +**Type** + +Database.UpsertResult + +**Description** + +The mock instance of `Database.UpsertResult` + +#### `createHttpCallout()` → `MockHttpCallout` + +Generates an instance of the class `MockHttpCallout` that implements the interface `HttpCalloutMock`. This can be used when testing batch jobs. + +##### Return + +**Type** + +MockHttpCallout + +**Description** + +The instance of `MockHttpCallout` + +#### `createHttpRequest()` → `HttpRequest` + +Generates an instance of `HttpRequest`. This can be used when testing logging capabilities for instances of `HttpRequest`. + +##### Return + +**Type** + +HttpRequest + +**Description** + +The instance of `HttpRequest` + +#### `createHttpResponse()` → `HttpResponse` + +Generates an instance of `HttpResponse`. This can be used when testing logging capabilities for instances of `HttpResponse`. + +##### Return + +**Type** + +HttpResponse + +**Description** + +The instance of `HttpResponse` + +#### `createId(Schema.SObjectType sobjectType)` → `String` + +Generates a mock record ID for the provided SObject Type + +##### Parameters + +| Param | Description | +| ------------- | ------------------------------------------------- | +| `sobjectType` | The SObject Type for the generated mock record ID | + +##### Return + +**Type** + +String + +**Description** + +The mock record ID for the specified SObject Type + +#### `createUser()` → `User` + +Creates a `User` record for testing purposes, using the current user's profile + +##### Return + +**Type** + +User + +**Description** + +The generated `User` record - it is not automatically inserted into the database. + +#### `createUser(Id profileId)` → `User` + +Creates a `User` record for testing purposes, using the specified profile ID + +##### Parameters + +| Param | Description | +| ----------- | ---------------------------------------------- | +| `profileId` | The `Profile` ID to use for the created `User` | + +##### Return + +**Type** + +User + +**Description** + +The generated `User` record - it is not automatically inserted into the database. + +#### `getNetwork()` → `SObject` + +Returns the current user's `Network` (Experience Cloud site) + +##### Return + +**Type** + +SObject + +**Description** + +The matching `Network` record + +#### `getOrganization()` → `Organization` + +Queries for the `Organization` record for the current environment. + +##### Return + +**Type** + +Organization + +**Description** + +The matching `Organization` record + +#### `getOrganizationEnvironmentType()` → `String` + +Returns the current environment's type - Scratch Org, Sandbox, or Production. + +##### Return + +**Type** + +String + +**Description** + +The environment type + +#### `getUser()` → `User` + +Returns the current user + +##### Return + +**Type** + +User + +**Description** + +The matching `User` record + +#### `getUser(Id userId)` → `User` + +Returns the specified user + +##### Parameters + +| Param | Description | +| -------- | ------------------------------------ | +| `userId` | The ID of the `User` record to query | + +##### Return + +**Type** + +User + +**Description** + +The matching `User` record + +#### `insertQueue(String queueDeveloperName, Schema.SObjectType sobjectType)` → `Group` + +Creates and inserts a `Group` record for testing queues, using the specified SObject Type + +##### Parameters + +| Param | Description | +| -------------------- | --------------------------------------------------------------------------------------------- | +| `queueDeveloperName` | The developer name to use for the new queue (stored in `Group.DeveloperName`) | +| `sobjectType` | The `SObjectType` that the queue should be able to own (stored in `QueueSObject.SObjectType`) | + +##### Return + +**Type** + +Group + +**Description** + +The inserted `Group` record - it is automatically inserted into the database, as well as 1 child `QueueSObject` record. + +#### `setReadOnlyField(SObject record, Schema.SObjectField field, Object value)` → `SObject` + +Sets a value for read-only fields that typically cannot be directly set on some SObjects + +##### Parameters + +| Param | Description | +| -------- | ----------------------------------------------------------- | +| `record` | The `SObject` record to update | +| `field` | The `Schema.SObjectField` for the field to update | +| `value` | The field value to populate on the provied `SObject` record | + +##### Return + +**Type** + +SObject + +**Description** + +A new copy of the original `SObject` record that has the specified read-only field populated + +#### `setReadOnlyField(SObject record, Map changesToFields)` → `SObject` + +Sets values for read-only fields that typically cannot be directly set on some SObjects + +##### Parameters + +| Param | Description | +| ----------------- | -------------------------------------------------------------------------------------------------------- | +| `record` | record description | +| `changesToFields` | An instance of `Map<Schema.SObjectField, Object> containing the read-only fields and corresponding | + +##### Return + +**Type** + +SObject + +**Description** + +A new copy of the original `SObject` record that has the specified read-only fields populated + +--- + +### Inner Classes + +#### LoggerMockDataCreator.MockBatchableContext class + +--- + +##### Constructors + +###### `MockBatchableContext(String jobId)` + +###### `MockBatchableContext(String jobId, Id childJobId)` + +--- + +##### Methods + +###### `getChildJobId()` → `String` + +###### `getJobId()` → `String` + +--- + +#### LoggerMockDataCreator.MockHttpCallout class + +--- + +##### Constructors + +###### `MockHttpCallout()` + +--- + +##### Properties + +###### `request` → `HttpRequest` + +###### `response` → `HttpResponse` + +###### `responseBody` → `String` + +###### `statusCode` → `Integer` + +--- + +##### Methods + +###### `respond(HttpRequest request)` → `HttpResponse` + +###### `setResponseBody(String responseBody)` → `MockHttpCallout` + +###### `setStatusCode(Integer statusCode)` → `MockHttpCallout` + +--- + +#### LoggerMockDataCreator.SObjectTestDataBuilder class + +Class used to create or update an `SObject` record with static fake data. This is useful in situations where you need to have fields populated, but the specific values used are not relevant to a particular test. This class can be used when Apex writing tests for plugins. + +--- + +##### Methods + +###### `getRecord()` → `SObject` + +Returns the builder's `SObject` record with fields populated based on which builder methods have been called + +####### Return + +**Type** + +SObject + +**Description** + +The builder's `SObject` record that was either provided by the calling code, or generated + +###### `populateAllFields()` → `SObjectTestDataBuilder` + +Sets a value on all editable fields, unless the `SObject` record already had a value specified for a field (including `null`) + +####### Return + +**Type** + +SObjectTestDataBuilder + +**Description** + +The `SObject` record, with all editable fields populated + +###### `populateMockId()` → `SObjectTestDataBuilder` + +Generates a mock record ID for the builder's `SObject` record + +####### Parameters + +| Param | Description | +| ------------- | ------------------------------------------------------------------- | +| `sobjectType` | The `SObjectType` to use for generating a new test `SObject` record | +| `record` | The existing test `SObject` record to populate with sample data | + +####### Return + +**Type** + +SObjectTestDataBuilder + +**Description** + +The same instance of `SObjectTestDataBuilder`, useful for chaining methods + +###### `populateRequiredFields()` → `SObjectTestDataBuilder` + +Sets a value on all editable required fields, unless the `SObject` record already had a value specified for a field (including `null`) + +####### Return + +**Type** + +SObjectTestDataBuilder + +**Description** + +The `SObject` record, with all editable required fields populated + +--- diff --git a/docs/apex/Test-Utilities/LoggerMockDataStore.md b/docs/apex/Test-Utilities/LoggerMockDataStore.md new file mode 100644 index 000000000..ceca3c5de --- /dev/null +++ b/docs/apex/Test-Utilities/LoggerMockDataStore.md @@ -0,0 +1,75 @@ +--- +layout: default +--- + +## LoggerMockDataStore class + +Utility class used to mock any data-related operations for the database, event bus, and queueable jobs. These methods are generic, and should work in any Salesforce org. These methods can be used when writing Apex tests for plugins. + +### Related + +[LoggerDataStore](LoggerDataStore) + +[LoggerMockDataCreator](../Test-Utilities/LoggerMockDataCreator) + +[LoggerTestConfigurator](../Test-Utilities/LoggerTestConfigurator) + +--- + +### Methods + +#### `getDatabase()` → `MockDatabase` + +#### `getEventBus()` → `MockEventBus` + +#### `getJobQueue()` → `MockJobQueue` + +--- + +### Inner Classes + +#### LoggerMockDataStore.MockDatabase class + +--- + +##### Methods + +###### `insertRecords(List records)` → `List` + +--- + +#### LoggerMockDataStore.MockEventBus class + +--- + +##### Methods + +###### `deliver()` → `void` + +###### `deliver(Schema.SObjectType sobjectType)` → `void` + +###### `deliver(LoggerSObjectHandler sobjectHandlerInstance)` → `void` + +###### `getPublishCallCount()` → `Integer` + +###### `getPublishedPlatformEvents()` → `List` + +###### `publishRecord(SObject platformEvent)` → `Database.SaveResult` + +###### `publishRecords(List platformEvents)` → `List` + +--- + +#### LoggerMockDataStore.MockJobQueue class + +--- + +##### Methods + +###### `enqueueJob(Queueable queueableJob)` → `Id` + +###### `executeJobs()` → `void` + +###### `getEnqueuedJobs()` → `List` + +--- diff --git a/docs/apex/Test-Utilities/LoggerTestConfigurator.md b/docs/apex/Test-Utilities/LoggerTestConfigurator.md new file mode 100644 index 000000000..022dc8d01 --- /dev/null +++ b/docs/apex/Test-Utilities/LoggerTestConfigurator.md @@ -0,0 +1,163 @@ +--- +layout: default +--- + +## LoggerTestConfigurator class + +Utility class used to help with setting up Nebula Logger's configurations within a test context. These methods are specific to metadata implemented within Nebula Logger. These methods can be used when writing Apex tests for plugins. + +### Related + +[LoggerMockDataCreator](../Test-Utilities/LoggerMockDataCreator) + +[LoggerMockDataStore](../Test-Utilities/LoggerMockDataStore) + +--- + +### Methods + +#### `assignAdminPermissionSet(Id userId)` → `void` + +Assigns the permission set `LoggerAdmin` to the specified user ID + +##### Parameters + +| Param | Description | +| -------- | ------------------------------------------------------------- | +| `userId` | The ID of the user that should be assigned the permission set | + +#### `assignEndUserPermissionSet(Id userId)` → `void` + +Assigns the permission set `LoggerEndUser` to the specified user ID + +##### Parameters + +| Param | Description | +| -------- | ------------------------------------------------------------- | +| `userId` | The ID of the user that should be assigned the permission set | + +#### `assignLogCreatorPermissionSet(Id userId)` → `void` + +Assigns the permission set `LoggerLogCreator` to the specified user ID + +##### Parameters + +| Param | Description | +| -------- | ------------------------------------------------------------- | +| `userId` | The ID of the user that should be assigned the permission set | + +#### `assignLogViewerPermissionSet(Id userId)` → `void` + +Assigns the permission set `LoggerLogViewer` to the specified user ID + +##### Parameters + +| Param | Description | +| -------- | ------------------------------------------------------------- | +| `userId` | The ID of the user that should be assigned the permission set | + +#### `getSObjectHandlerConfiguration(Schema.SObjectType sobjectType)` → `LoggerSObjectHandler_t` + +Returns an instance of `LoggerSObjectHandler_t` that has been built & configured for the specified `SObjectType` + +##### Parameters + +| Param | Description | +| ------------- | --------------------------------------------------------------------------------------- | +| `sobjectType` | The instance `SObjectType` to check for a configured instance of `LoggerSObjectHandler` | + +##### Return + +**Type** + +LoggerSObjectHandler_t + +**Description** + +The ``LoggerSObjectHandler_t` record that has been configured for the specified `SObjectType` (if any) + +#### `setMock(LogEntryDataMaskRule_t mock)` → `void` + +Loads the mock `LogEntryDataMaskRule_t` during test execution + +##### Parameters + +| Param | Description | +| ------ | ----------------------------------------------------- | +| `mock` | The mock instance of `LogEntryDataMaskRule_t` to load | + +#### `setMock(LogEntryTagRule_t mock)` → `void` + +Loads the mock `LogEntryTagRule_t` during test execution + +##### Parameters + +| Param | Description | +| ------ | ------------------------------------------------ | +| `mock` | The mock instance of `LogEntryTagRule_t` to load | + +#### `setMock(LoggerParameter_t mock)` → `void` + +Loads the mock `LoggerParameter_t` during test execution + +##### Parameters + +| Param | Description | +| ------ | ------------------------------------------------ | +| `mock` | The mock instance of `LoggerParameter_t` to load | + +#### `setMock(LoggerPlugin_t mock)` → `void` + +Loads the mock `LoggerPlugin_t` during test execution + +##### Parameters + +| Param | Description | +| ------ | --------------------------------------------- | +| `mock` | The mock instance of `LoggerPlugin_t` to load | + +#### `setMock(LoggerSObjectHandler_t mock)` → `void` + +Loads the mock `LoggerSObjectHandler_t` during test execution + +##### Parameters + +| Param | Description | +| ------ | ----------------------------------------------------- | +| `mock` | The mock instance of `LoggerSObjectHandler_t` to load | + +#### `setMock(LogScenarioRule_t mock)` → `void` + +Loads the mock `LogScenarioRule_t` during test execution + +##### Parameters + +| Param | Description | +| ------ | ------------------------------------------------ | +| `mock` | The mock instance of `LogScenarioRule_t` to load | + +#### `setMock(LogStatus_t mock)` → `void` + +Loads the mock `LogStatus_t` during test execution + +##### Parameters + +| Param | Description | +| ------ | ------------------------------------------ | +| `mock` | The mock instance of `LogStatus_t` to load | + +#### `setupMockSObjectHandlerConfigurations()` → `void` + +Creates mock instances of `LoggerSObjectHandler_t` for each `SObjectType` used by Nebula Logger, with each `LoggerSObjectHandler_t` automatically set to `IsEnabled__c == true` + +#### `setupMockSObjectHandlerConfigurations(Boolean isEnabled)` → `void` + +Creates mock instances of `LoggerSObjectHandler_t` for each `SObjectType` used by Nebula Logger, with each `LoggerSObjectHandler_t` enabled/disabled based on the provided boolean + +##### Parameters + +| Param | Description | +| ----------- | -------------------------------------------------------------------------------------------------------------------------- | +| `isEnabled` | The Boolean value to control if all mock `LoggerSObjectHandler_t` records should be enabled (`true`) or disabled (`false`) | + +--- diff --git a/docs/apex/index.md b/docs/apex/index.md index 702b14b3f..79d03b163 100644 --- a/docs/apex/index.md +++ b/docs/apex/index.md @@ -6,104 +6,128 @@ layout: default ## Logger Engine -### [ComponentLogger](logger-engine/ComponentLogger) +### [ComponentLogger](Logger-Engine/ComponentLogger) Controller class used by the lightning web component `logger` -### [FlowCollectionLogEntry](logger-engine/FlowCollectionLogEntry) +### [FlowCollectionLogEntry](Logger-Engine/FlowCollectionLogEntry) Handles adding new log entries in Flow for a particular `SObject` record collection -### [FlowLogEntry](logger-engine/FlowLogEntry) +### [FlowLogEntry](Logger-Engine/FlowLogEntry) Handles adding new log entries in Flow -### [FlowLogger](logger-engine/FlowLogger) +### [FlowLogger](Logger-Engine/FlowLogger) Handles some common logic used by `FlowLogEntry`, `FlowRecordLogEntry` and `FlowCollectionLogEntry` -### [FlowRecordLogEntry](logger-engine/FlowRecordLogEntry) +### [FlowRecordLogEntry](Logger-Engine/FlowRecordLogEntry) Handles adding new log entries in Flow for a particular `SObject` record -### [LogEntryEventBuilder](logger-engine/LogEntryEventBuilder) +### [LogEntryEventBuilder](Logger-Engine/LogEntryEventBuilder) Builder class that generates each `LogEntryEvent__e` record -### [LogMessage](logger-engine/LogMessage) +### [LogMessage](Logger-Engine/LogMessage) Provides the ability to generate string messages on demand, using String.format() -### [Logger](logger-engine/Logger) +### [Logger](Logger-Engine/Logger) The core class for logging +### [LoggerDataStore](Logger-Engine/LoggerDataStore) + +Class used to manage any data-related operations, including database DML statements, publishing platform events via the event bus, and enqueueing queueable jobs + +### [LoggerSObjectHandler](Logger-Engine/LoggerSObjectHandler) + +Abstract class used by trigger handlers for shared logic + +### [LoggerTriggerableContext](Logger-Engine/LoggerTriggerableContext) + +Class used by the logging system for trigger contextual details + ## Log Management -### [LogBatchPurgeScheduler](log-management/LogBatchPurgeScheduler) +### [LogBatchPurgeScheduler](Log-Management/LogBatchPurgeScheduler) Schedulable class used to schedule the batch job `LogBatchPurger` -### [LogBatchPurger](log-management/LogBatchPurger) +### [LogBatchPurger](Log-Management/LogBatchPurger) Batch class used to delete old logs, based on `Log__c.LogRetentionDate__c <= :System.today()` -### [LogEntryEventHandler](log-management/LogEntryEventHandler) +### [LogEntryEventHandler](Log-Management/LogEntryEventHandler) Processes `LogEntryEvent__e` platform events and normalizes the data into `Log__c` and `LogEntry__c` records -### [LogEntryFieldSetPicklist](log-management/LogEntryFieldSetPicklist) +### [LogEntryFieldSetPicklist](Log-Management/LogEntryFieldSetPicklist) Dynamically returns `LogEntry__c` field sets in App Builder when configuring the component RelatedLogEntries -### [LogEntryHandler](log-management/LogEntryHandler) +### [LogEntryHandler](Log-Management/LogEntryHandler) Manages setting fields on `LogEntry__c` before insert & before update -### [LogEntryTagHandler](log-management/LogEntryTagHandler) +### [LogEntryTagHandler](Log-Management/LogEntryTagHandler) Handles trigger events for the `LogEntryTag__c` object -### [LogHandler](log-management/LogHandler) +### [LogHandler](Log-Management/LogHandler) Manages setting fields on `Log__c` before insert & before update -### [LogMassDeleteExtension](log-management/LogMassDeleteExtension) +### [LogMassDeleteExtension](Log-Management/LogMassDeleteExtension) Manages mass deleting `Log__c` records that have been selected by a user on a `Log__c` list view -### [LoggerSObjectHandler](log-management/LoggerSObjectHandler) +### [LoggerBatchableContext](Log-Management/LoggerBatchableContext) -Abstract class used by trigger handlers for shared logic +Class used by the logging system for batch contextual details + +### [LoggerEmailSender](Log-Management/LoggerEmailSender) + +Builds and sends email notifications when internal exceptions occur within the logging system -### [LoggerSObjectMetadata](log-management/LoggerSObjectMetadata) +### [LoggerSObjectMetadata](Log-Management/LoggerSObjectMetadata) Provides details to LWCs about Logger's `SObjects`, using `@AuraEnabled` properties -### [LoggerSettingsController](log-management/LoggerSettingsController) +### [LoggerSettingsController](Log-Management/LoggerSettingsController) Controller class for lwc `loggerSettings`, used to manage records in `LoggerSettings__c` -### [LoggerTagHandler](log-management/LoggerTagHandler) +### [LoggerTagHandler](Log-Management/LoggerTagHandler) Handles trigger events for the `LoggerTag__c` object -### [RelatedLogEntriesController](log-management/RelatedLogEntriesController) +### [RelatedLogEntriesController](Log-Management/RelatedLogEntriesController) Controller class for the lightning web component `related-log-entries` -## Configuration +## Test Utilities -### [LoggerEmailUtils](configuration/LoggerEmailUtils) +### [LoggerMockDataCreator](/Test-Utilities/LoggerMockDataCreator) -Builds and sends email notifications when internal exceptions occur within the logging system +Utility class used to help with generating mock data when writing Apex tests for Nebula Logger. These methods are generic, and should work in any Salesforce org. These methods can be used when writing Apex tests for plugins. -### [LoggerParameter](configuration/LoggerParameter) +### [LoggerMockDataStore](/Test-Utilities/LoggerMockDataStore) -Provides a centralized way to load parameters for SObject handlers & plugins, and casts the parameters to common data types +Utility class used to mock any data-related operations for the database, event bus, and queueable jobs. These methods are generic, and should work in any Salesforce org. These methods can be used when writing Apex tests for plugins. + +### [LoggerTestConfigurator](/Test-Utilities/LoggerTestConfigurator) -## Plugin Framework +Utility class used to help with setting up Nebula Logger's configurations within a test context. These methods are specific to metadata implemented within Nebula Logger. These methods can be used when writing Apex tests for plugins. + +## Configuration + +### [LoggerParameter](Configuration/LoggerParameter) + +Provides a centralized way to load parameters for SObject handlers & plugins, and casts the parameters to common data types -### [LoggerSObjectHandlerPlugin](plugin-framework/LoggerSObjectHandlerPlugin) +### [LoggerPlugin](Configuration/LoggerPlugin) -Abstract class used to create custom Apex plugins to execute for all trigger operations on `Log__c` or `LogEntry__c` +The core of the plugin framework, used to create custom Apex & Flow plugins for `LoggerSObjectHandler` and `LogBatchPurger` based on configurations stored in the custom metadata type `LoggerPlugin_t` diff --git a/docs/apex/log-management/LogEntryEventHandler.md b/docs/apex/log-management/LogEntryEventHandler.md deleted file mode 100644 index c7bddfc77..000000000 --- a/docs/apex/log-management/LogEntryEventHandler.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -layout: default ---- - -## LogEntryEventHandler class - -Processes `LogEntryEvent__e` platform events and normalizes the data into `Log__c` and `LogEntry__c` records - ---- - -### Properties - -#### `releaseNumber` → `String` - -String containing the release number. - -#### `releaseVersion` → `String` - -String containing the release version. - ---- - -### Methods - -#### `executeAfterInsert(List triggerNew)` → `void` - -Public method so it can be called from Logger - this is unique to LogEntryEventHandler - -##### Parameters - -| Param | Description | -| ------------ | -------------------------------- | -| `triggerNew` | list of new LogEntryEvent events | - -#### `executeBeforeInsert(List triggerNew)` → `void` - -method so it can be called from Logger - this is unique to LogEntryEventHandler - -##### Parameters - -| Param | Description | -| ------------ | -------------------------------- | -| `triggerNew` | list of new LogEntryEvent events | - -#### `getSObjectType()` → `SObjectType` - -Returns SObject Type that the handler is responsible for processing - -##### Return - -**Type** - -SObjectType - -**Description** - -The instance of `SObjectType` - ---- diff --git a/docs/apex/log-management/LoggerSObjectHandler.md b/docs/apex/log-management/LoggerSObjectHandler.md deleted file mode 100644 index 3e0d0598a..000000000 --- a/docs/apex/log-management/LoggerSObjectHandler.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -layout: default ---- - -## LoggerSObjectHandler class - -Abstract class used by trigger handlers for shared logic - ---- - -### Constructors - -#### `LoggerSObjectHandler()` - -## Default constructor - -### Methods - -#### `execute()` → `void` - -Runs the handler class's logic - -#### `getSObjectType()` → `SObjectType` - -Returns the SObject Type that the handler is responsible for processing - -##### Return - -**Type** - -SObjectType - -**Description** - -The instance of `SObjectType` - ---- diff --git a/docs/apex/log-management/LoggerSObjectMetadata.md b/docs/apex/log-management/LoggerSObjectMetadata.md deleted file mode 100644 index 6fe5469e7..000000000 --- a/docs/apex/log-management/LoggerSObjectMetadata.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -layout: default ---- - -## LoggerSObjectMetadata class - -Provides details to LWCs about Logger's `SObjects`, using `@AuraEnabled` properties - ---- - -### Methods - -#### `getLogEntryEventSchema()` → `SObjectSchema` - -Provides schema details about the the platform event object `LogEntryEvent__e` - -##### Return - -**Type** - -SObjectSchema - -**Description** - -An instance of `LoggerSObjectMetadata.SObjectSchema` for the platform event `LogEntryEvent__e` - -#### `getLoggerSettingsSchema()` → `SObjectSchema` - -Provides schema details about the the custom settings object `LoggerSettings__c` - -##### Return - -**Type** - -SObjectSchema - -**Description** - -An instance of `LoggerSObjectMetadata.SObjectSchema` for the platform event `LoggerSettings__c` - ---- - -### Inner Classes - -#### LoggerSObjectMetadata.FieldSchema class - -Inner class for `SObjectField` details to LWCs, using `@AuraEnabled` properties - ---- - -##### Properties - -###### `apiName` → `String` - -###### `inlineHelpText` → `String` - -###### `label` → `String` - -###### `localApiName` → `String` - -###### `type` → `String` - ---- - -#### LoggerSObjectMetadata.SObjectSchema class - -Inner class for `SObject` details to LWCs, using `@AuraEnabled` properties - ---- - -##### Properties - -###### `apiName` → `String` - -###### `fields` → `Map` - -###### `label` → `String` - -###### `labelPlural` → `String` - -###### `localApiName` → `String` - -###### `namespacePrefix` → `String` - ---- diff --git a/docs/apex/plugin-framework/LoggerSObjectHandlerPlugin.md b/docs/apex/plugin-framework/LoggerSObjectHandlerPlugin.md deleted file mode 100644 index dbe008d41..000000000 --- a/docs/apex/plugin-framework/LoggerSObjectHandlerPlugin.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -layout: default ---- - -## LoggerSObjectHandlerPlugin class - -Abstract class used to create custom Apex plugins to execute for all trigger operations on `Log__c` or `LogEntry__c` - ---- - -### Constructors - -#### `LoggerSObjectHandlerPlugin()` - -## All instances of `LoggerSObjectHandlerPlugin` are dynamically created, which requires a parameterless constructor - -### Methods - -#### `execute(TriggerOperation triggerOperationType,List triggerNew,Map triggerNewMap,List triggerOld,Map triggerOldMap)` → `void` - -This method is the entry point for plugins to execute any custom logic. It is automatically called by the logging system for any enabled plugins. Several trigger-based parameters are provided - these parameters should be used by plugins, instead of calling the platform's static variables directly (e.g., use the provided `triggerNew` variable instead of using `Trigger.new` directly, and so on). - -##### Parameters - -| Param | Description | -| ---------------------- | ------------------------------------------------------------------------------------------ | -| `triggerOperationType` | The enum instance of `Trigger.operationType` at the time that the handler class is created | -| `triggerNew` | The value `Trigger.new` at the time that the handler class is created | -| `triggerNewMap` | The value `Trigger.newMap` at the time that the handler class is created | -| `triggerOld` | The value `Trigger.old` at the time that the handler class is created | -| `triggerOldMap` | The value `Trigger.oldMap` at the time that the handler class is created | - ---- diff --git a/docs/lightning-components/LogEntryBuilder.md b/docs/lightning-components/LogEntryBuilder.md index 206eaef0d..7871c275e 100644 --- a/docs/lightning-components/LogEntryBuilder.md +++ b/docs/lightning-components/LogEntryBuilder.md @@ -32,7 +32,7 @@ This class is the JavaScript-equivalent of the Apex class `LogEntryBuilder` Sets the log entry event's message field -**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder) +**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder) **Returns**: [LogEntryBuilder](#LogEntryBuilder) - The same instance of `LogEntryBuilder`, useful for chaining methods | Param | Type | Description | @@ -45,7 +45,7 @@ Sets the log entry event's message field Sets the log entry event's record fields -**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder) +**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder) **Returns**: [LogEntryBuilder](#LogEntryBuilder) - The same instance of `LogEntryBuilder`, useful for chaining methods | Param | Type | Description | @@ -58,7 +58,7 @@ Sets the log entry event's record fields Sets the log entry event's record fields -**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder) +**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder) **Returns**: [LogEntryBuilder](#LogEntryBuilder) - The same instance of `LogEntryBuilder`, useful for chaining methods | Param | Type | Description | @@ -71,7 +71,7 @@ Sets the log entry event's record fields Sets the log entry event's exception fields -**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder) +**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder) **Returns**: [LogEntryBuilder](#LogEntryBuilder) - The same instance of `LogEntryBuilder`, useful for chaining methods | Param | Type | Description | @@ -84,7 +84,7 @@ Sets the log entry event's exception fields Appends the tag to the existing list of tags -**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder) +**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder) **Returns**: [LogEntryBuilder](#LogEntryBuilder) - The same instance of `LogEntryBuilder`, useful for chaining methods | Param | Type | Description | @@ -97,7 +97,7 @@ Appends the tag to the existing list of tags Appends the tag to the existing list of tags -**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder) +**Kind**: instance method of [LogEntryBuilder](#LogEntryBuilder) **Returns**: [LogEntryBuilder](#LogEntryBuilder) - The same instance of `LogEntryBuilder`, useful for chaining methods | Param | Type | Description | diff --git a/docs/lightning-components/Logger.md b/docs/lightning-components/Logger.md index 6817a0baf..3c5427ea2 100644 --- a/docs/lightning-components/Logger.md +++ b/docs/lightning-components/Logger.md @@ -47,8 +47,8 @@ Returns information about the current user's settings, stored in `LoggerSettings__c` -**Kind**: global function -**Returns**: ComponentLogger.ComponentLoggerSettings - The current user's instance of the Apex class `ComponentLogger.ComponentLoggerSettings` +**Kind**: global function +**Returns**: ComponentLogger.ComponentLoggerSettings - The current user's instance of the Apex class `ComponentLogger.ComponentLoggerSettings` ## setScenario(scenario) @@ -68,7 +68,7 @@ and `Log__c.Scenario__c`, and can be used to filter & group logs Creates a new log entry with logging level == `LoggingLevel.ERROR` -**Kind**: global function +**Kind**: global function **Returns**: LogEntryBuilder - The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods | Param | Type | Description | @@ -81,7 +81,7 @@ Creates a new log entry with logging level == `LoggingLevel.ERROR` Creates a new log entry with logging level == `LoggingLevel.WARN` -**Kind**: global function +**Kind**: global function **Returns**: LogEntryBuilder - The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods | Param | Type | Description | @@ -94,7 +94,7 @@ Creates a new log entry with logging level == `LoggingLevel.WARN` Creates a new log entry with logging level == `LoggingLevel.INFO` -**Kind**: global function +**Kind**: global function **Returns**: LogEntryBuilder - The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods | Param | Type | Description | @@ -107,7 +107,7 @@ Creates a new log entry with logging level == `LoggingLevel.INFO` Creates a new log entry with logging level == `LoggingLevel.DEBUG` -**Kind**: global function +**Kind**: global function **Returns**: LogEntryBuilder - The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods | Param | Type | Description | @@ -120,7 +120,7 @@ Creates a new log entry with logging level == `LoggingLevel.DEBUG` Creates a new log entry with logging level == `LoggingLevel.FINE` -**Kind**: global function +**Kind**: global function **Returns**: LogEntryBuilder - The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods | Param | Type | Description | @@ -133,7 +133,7 @@ Creates a new log entry with logging level == `LoggingLevel.FINE` Creates a new log entry with logging level == `LoggingLevel.FINER` -**Kind**: global function +**Kind**: global function **Returns**: LogEntryBuilder - The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods | Param | Type | Description | @@ -146,7 +146,7 @@ Creates a new log entry with logging level == `LoggingLevel.FINER` Creates a new log entry with logging level == `LoggingLevel.FINEST` -**Kind**: global function +**Kind**: global function **Returns**: LogEntryBuilder - The new entry's instance of `LogEntryEventBuilder`, useful for chaining methods | Param | Type | Description | @@ -159,15 +159,15 @@ Creates a new log entry with logging level == `LoggingLevel.FINEST` Returns the number of entries that have been generated but not yet saved -**Kind**: global function -**Returns**: Integer - The buffer's current size +**Kind**: global function +**Returns**: Integer - The buffer's current size ## flushBuffer() Discards any entries that have been generated but not yet saved -**Kind**: global function +**Kind**: global function ## saveLog(saveMethod) diff --git a/nebula-logger/core/main/configuration/classes/LoggerParameter.cls b/nebula-logger/core/main/configuration/classes/LoggerParameter.cls index 70d5f6d30..d6c88f932 100644 --- a/nebula-logger/core/main/configuration/classes/LoggerParameter.cls +++ b/nebula-logger/core/main/configuration/classes/LoggerParameter.cls @@ -10,8 +10,10 @@ */ @SuppressWarnings('PMD.CyclomaticComplexity, PMD.ExcessivePublicCount, PMD.PropertyNamingConventions') public class LoggerParameter { - private static Set parametersToLoadDuringTests = new Set(); - private static Map mockParameterByDeveloperName = new Map(); + // During tests, always load this CMDT record + // so that tests use the same format when calling System.debug() + private static final String SYSTEM_DEBUG_MESSAGE_FORMAT_PARAMETER = 'SystemDebugMessageFormat'; + private static final Set PARAMETERS_TO_LOAD_DURING_TESTS = new Set{ SYSTEM_DEBUG_MESSAGE_FORMAT_PARAMETER }; /** * @description Indicates if Logger will make an async callout to https://api.status.salesforce.com @@ -63,11 +65,7 @@ public class LoggerParameter { public static final String SYSTEM_DEBUG_MESSAGE_FORMAT { get { if (SYSTEM_DEBUG_MESSAGE_FORMAT == null) { - // During tests, always load this CMDT record - // so that tests use the same format when calling System.debug() - String systemDebugMessageFormatParameter = 'SystemDebugMessageFormat'; - parametersToLoadDuringTests.add(systemDebugMessageFormatParameter); - SYSTEM_DEBUG_MESSAGE_FORMAT = getString(systemDebugMessageFormatParameter, '{OriginLocation__c}\n{Message__c}'); + SYSTEM_DEBUG_MESSAGE_FORMAT = getString(SYSTEM_DEBUG_MESSAGE_FORMAT_PARAMETER, '{OriginLocation__c}\n{Message__c}'); } return SYSTEM_DEBUG_MESSAGE_FORMAT; } @@ -101,6 +99,16 @@ public class LoggerParameter { private set; } + private static final Map DEVELOPER_NAME_TO_RECORD { + get { + if (DEVELOPER_NAME_TO_RECORD == null) { + DEVELOPER_NAME_TO_RECORD = loadRecords(); + } + return DEVELOPER_NAME_TO_RECORD; + } + private set; + } + /** * @description Returns the configured value of the field `Value__c` as a `Boolean` * @param parameterDeveloperName The developer name of the instance of `LoggerParameter__mdt` @@ -340,10 +348,45 @@ public class LoggerParameter { return parameterValue != null ? parameterValue : defaultValue; } - // Private methods + /** + * @description matchOnPrefix description + * @param developerNamePrefix A prefix that has been used in the `DeveloperName` for multiple `LoggerParameter__mdt` records + * @return The list of matching `LoggerParameter__mdt` records + */ + public static List matchOnPrefix(String developerNamePrefix) { + List matchingParameters = new List(); + for (String parameterDeveloperName : DEVELOPER_NAME_TO_RECORD.keySet()) { + if (parameterDeveloperName.startsWith(developerNamePrefix) == true) { + matchingParameters.add(DEVELOPER_NAME_TO_RECORD.get(parameterDeveloperName)); + } + } + return matchingParameters; + } + + private static Map loadRecords() { + Map parameters = LoggerParameter__mdt.getAll().clone(); + if (System.Test.isRunningTest() == true) { + // Keep a copy of any records that *should* be loaded during tests + // Currently, only the record `SystemDebugMessageFormat` has a use case for this functionality, + // but others can be easily added if other use cases are found + Map parametersToLoadDuringTests = new Map(); + for (String testContextParameterName : PARAMETERS_TO_LOAD_DURING_TESTS) { + if (parameters.containsKey(testContextParameterName) == true) { + parametersToLoadDuringTests.put(testContextParameterName, parameters.get(testContextParameterName)); + } + } + parameters.clear(); + parameters.putAll(parametersToLoadDuringTests); + } + return parameters; + } + @TestVisible - private static void setMockParameter(LoggerParameter__mdt parameter) { - mockParameterByDeveloperName.put(parameter.DeveloperName, parameter); + private static void setMock(LoggerParameter__mdt parameter) { + if (String.isBlank(parameter.DeveloperName) == true) { + throw new IllegalArgumentException('DeveloperName is required on `LoggerParameter__mdt: \n' + JSON.serializePretty(parameter)); + } + DEVELOPER_NAME_TO_RECORD.put(parameter.DeveloperName, parameter); } private static Object castParameterValue(String parameterDeveloperName, Type dataType) { @@ -356,16 +399,6 @@ public class LoggerParameter { } private static String loadParameterValue(String parameterDeveloperName) { - String parameterValue = LoggerParameter__mdt.getInstance(parameterDeveloperName)?.Value__c; - - Boolean useMockParameter = - parametersToLoadDuringTests.contains(parameterDeveloperName) == false || - mockParameterByDeveloperName.containsKey(parameterDeveloperName) == true; - if (System.Test.isRunningTest() == true && useMockParameter == true) { - // During tests, don't actually use the org's CMDT records - only use mock records - parameterValue = (String) mockParameterByDeveloperName.get(parameterDeveloperName)?.get('Value__c'); - } - - return parameterValue; + return DEVELOPER_NAME_TO_RECORD.get(parameterDeveloperName)?.Value__c; } } diff --git a/nebula-logger/core/main/configuration/classes/LoggerPlugin.cls b/nebula-logger/core/main/configuration/classes/LoggerPlugin.cls new file mode 100644 index 000000000..3bdbd1fdb --- /dev/null +++ b/nebula-logger/core/main/configuration/classes/LoggerPlugin.cls @@ -0,0 +1,139 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @group Configuration + * @description The core of the plugin framework, used to create custom Apex & Flow plugins for `LoggerSObjectHandler` and `LogBatchPurger` + * based on configurations stored in the custom metadata type `LoggerPlugin__mdt` + */ +public without sharing class LoggerPlugin { + private static final Map DEVELOPER_NAME_TO_RECORD = loadRecords(); + + /** + * @description Interface used to create plugins that can be used within Logger's batch job `LogBatchPurger` + */ + @SuppressWarnings('PMD.ApexDoc') + public interface Batchable { + void start(LoggerPlugin__mdt configuration, LoggerBatchableContext input); + void execute(LoggerPlugin__mdt configuration, LoggerBatchableContext input, List scopeRecords); + void finish(LoggerPlugin__mdt configuration, LoggerBatchableContext input); + } + + /** + * @description Interface used to create plugins that can be used within Logger's trigger handler framework `LoggerSObjectHandler` + */ + @SuppressWarnings('PMD.ApexDoc') + public interface Triggerable { + void execute(LoggerPlugin__mdt configuration, LoggerTriggerableContext input); + } + + /** + * @description Filters the configured `LoggerPlugin__mdt` records based on a list of `SObjectField` - only records that have a value for 1 or more + * of the specified `populatedFilterFields` will be returned, sorted by the specified `SObjectField` parameter `sortByField` + * @param populatedFilterFields The list of `SObjectField` to check on each `LoggerPlugin__mdt` record - filtering logic checks for a non-null value + * @param sortByField The `SObjectField` to use to sort the list of matches. The method also uses `DeveloperName` as a secondary field for sorting. + * @return The list of matching `LoggerPlugin__mdt` records + */ + public static List getFilteredPluginConfigurations(List populatedFilterFields, Schema.SObjectField sortByField) { + List matchingPluginConfigurationSorters = new List(); + for (LoggerPlugin__mdt pluginConfiguration : DEVELOPER_NAME_TO_RECORD.values()) { + Boolean matchesFilterFields = false; + for (Schema.SObjectField filterField : populatedFilterFields) { + if (pluginConfiguration.get(filterField) != null) { + matchesFilterFields = true; + break; + } + } + if (matchesFilterFields == true) { + matchingPluginConfigurationSorters.add( + new PluginConfigurationSorter(pluginConfiguration).sortBy(sortByField).sortBy(Schema.LoggerPlugin__mdt.DeveloperName) + ); + } + } + matchingPluginConfigurationSorters.sort(); + List matchingPluginConfigurations = new List(); + for (PluginConfigurationSorter sorter : matchingPluginConfigurationSorters) { + matchingPluginConfigurations.add(sorter.pluginConfiguration); + } + return matchingPluginConfigurations; + } + + /** + * @description Creates an instance of the class `LoggerPlugin.Batchable` based on the provided `LoggerPlugin__mdt` configuration + * @param apexClassTypeName The name of the Apex class that implements `LoggerPlugin.Batchable` + * @return The dynamically created instance of `LoggerPlugin.Batchable`, + * or null if an instance could not be created based on the provided configuration + */ + public static Batchable newBatchableInstance(String apexClassTypeName) { + return (Batchable) Type.forName(apexClassTypeName)?.newInstance(); + } + + /** + * @description Creates an instance of the class `LoggerPlugin.Triggerable` based on the provided `LoggerPlugin__mdt` configuration + * @param apexClassTypeName The name of the Apex class that implements `LoggerPlugin.Triggerable` + * @return The dynamically created instance of `LoggerPlugin.Triggerable`, + * or null if an instance could not be created based on the provided configuration + */ + public static Triggerable newTriggerableInstance(String apexClassTypeName) { + return (Triggerable) Type.forName(apexClassTypeName)?.newInstance(); + } + + private static Map loadRecords() { + Map pluginConfigurations = LoggerPlugin__mdt.getAll().clone(); + if (System.Test.isRunningTest() == true) { + pluginConfigurations.clear(); + } + return pluginConfigurations; + } + + @TestVisible + private static void setMock(LoggerPlugin__mdt pluginConfiguration) { + if (String.isBlank(pluginConfiguration.DeveloperName) == true) { + throw new IllegalArgumentException('DeveloperName is required on mock LoggerPlugin__mdt: \n' + JSON.serializePretty(pluginConfiguration)); + } + if (pluginConfiguration.IsEnabled__c == true) { + DEVELOPER_NAME_TO_RECORD.put(pluginConfiguration.DeveloperName, pluginConfiguration); + } + } + + @SuppressWarnings('PMD.ApexDoc') + private class PluginConfigurationSorter implements Comparable { + public LoggerPlugin__mdt pluginConfiguration; + private List sortByFields = new List(); + + public PluginConfigurationSorter(LoggerPlugin__mdt pluginConfiguration) { + this.pluginConfiguration = pluginConfiguration; + } + + public PluginConfigurationSorter sortBy(Schema.SObjectField field) { + sortByFields.add(field); + return this; + } + + public Integer compareTo(Object compareTo) { + PluginConfigurationSorter that = (PluginConfigurationSorter) compareTo; + + for (Schema.SObjectField field : this.sortByFields) { + // Ugly block to handle numeric comparisons vs string comparisons (based on the field type) + Boolean thisIsGreaterThanThat = false; + if (field.getDescribe().getSoapType() == Schema.SoapType.DOUBLE) { + thisIsGreaterThanThat = (Decimal) this.pluginConfiguration.get(field) > (Decimal) that.pluginConfiguration.get(field); + } else { + thisIsGreaterThanThat = (String) this.pluginConfiguration.get(field) > (String) that.pluginConfiguration.get(field); + } + + // Now, the actual comparisons + if (this.pluginConfiguration.get(field) == that.pluginConfiguration.get(field)) { + continue; + } else if (this.pluginConfiguration.get(field) == null && that.pluginConfiguration.get(field) != null || thisIsGreaterThanThat == true) { + return 1; + } else { + return -1; + } + } + return 0; + } + } +} diff --git a/nebula-logger/core/main/configuration/classes/LoggerEmailUtils.cls-meta.xml b/nebula-logger/core/main/configuration/classes/LoggerPlugin.cls-meta.xml similarity index 100% rename from nebula-logger/core/main/configuration/classes/LoggerEmailUtils.cls-meta.xml rename to nebula-logger/core/main/configuration/classes/LoggerPlugin.cls-meta.xml diff --git a/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.IsLogEntryEventHandlerEnabled.md-meta.xml b/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.IsLogEntryEventHandlerEnabled.md-meta.xml new file mode 100644 index 000000000..d09af9772 --- /dev/null +++ b/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.IsLogEntryEventHandlerEnabled.md-meta.xml @@ -0,0 +1,17 @@ + + + + false + + Description__c + Controls if the trigger handler class LogEntryEventHandler executes for LogEntryEvent__e records + + + Value__c + true + + diff --git a/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.IsLogEntryHandlerEnabled.md-meta.xml b/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.IsLogEntryHandlerEnabled.md-meta.xml new file mode 100644 index 000000000..e7e66e4c0 --- /dev/null +++ b/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.IsLogEntryHandlerEnabled.md-meta.xml @@ -0,0 +1,17 @@ + + + + false + + Description__c + Controls if the trigger handler class LogEntryHandler executes for LogEntry__c records + + + Value__c + true + + diff --git a/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.IsLogEntryTagHandlerEnabled.md-meta.xml b/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.IsLogEntryTagHandlerEnabled.md-meta.xml new file mode 100644 index 000000000..ba3dff458 --- /dev/null +++ b/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.IsLogEntryTagHandlerEnabled.md-meta.xml @@ -0,0 +1,17 @@ + + + + false + + Description__c + Controls if the trigger handler class LogEntryTagHandler executes for LogEntryTag__c records + + + Value__c + true + + diff --git a/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.IsLogHandlerEnabled.md-meta.xml b/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.IsLogHandlerEnabled.md-meta.xml new file mode 100644 index 000000000..86069e05b --- /dev/null +++ b/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.IsLogHandlerEnabled.md-meta.xml @@ -0,0 +1,17 @@ + + + + false + + Description__c + Controls if the trigger handler class LogEntryHandler executes for LogEntry__c records + + + Value__c + true + + diff --git a/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.IsLoggerTagHandlerEnabled.md-meta.xml b/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.IsLoggerTagHandlerEnabled.md-meta.xml new file mode 100644 index 000000000..77d91950b --- /dev/null +++ b/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.IsLoggerTagHandlerEnabled.md-meta.xml @@ -0,0 +1,17 @@ + + + + false + + Description__c + Controls if the trigger handler class LoggerTagHandler executes for LoggerTag__c records + + + Value__c + true + + diff --git a/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.SendErrorEmailNotifications.md-meta.xml b/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.SendErrorEmailNotifications.md-meta.xml index 2261d1690..271e59d0b 100644 --- a/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.SendErrorEmailNotifications.md-meta.xml +++ b/nebula-logger/core/main/configuration/customMetadata/LoggerParameter.SendErrorEmailNotifications.md-meta.xml @@ -10,7 +10,7 @@ Description__c When set to 'true' (default), if an internal error occurs within Logger, an email notification will be sent to the org's list of Apex Exception Email recipients, configured under Setup --> Email --> Apex Exception Email. + >When set to 'true' (default), if an internal error occurs within Logger, an email notification will be sent to the org's list of Apex Exception Email recipients, configured under Setup --> Email --> Apex Exception Email. When set to 'false', no emails will be sent by Logger. diff --git a/nebula-logger/managed-package/core/main/deprecated/customMetadata/LoggerSObjectHandler.LogEntryEventHandler.md-meta.xml b/nebula-logger/core/main/configuration/customMetadata/LoggerSObjectHandler.LogEntryEventHandler.md-meta.xml similarity index 63% rename from nebula-logger/managed-package/core/main/deprecated/customMetadata/LoggerSObjectHandler.LogEntryEventHandler.md-meta.xml rename to nebula-logger/core/main/configuration/customMetadata/LoggerSObjectHandler.LogEntryEventHandler.md-meta.xml index 1bc52dc7f..f6c7d3e37 100644 --- a/nebula-logger/managed-package/core/main/deprecated/customMetadata/LoggerSObjectHandler.LogEntryEventHandler.md-meta.xml +++ b/nebula-logger/core/main/configuration/customMetadata/LoggerSObjectHandler.LogEntryEventHandler.md-meta.xml @@ -6,6 +6,14 @@ > false + + IsEnabled__c + true + + + SObjectHandlerApexClass__c + LogEntryEventHandler + SObjectType__c LogEntryEvent__e diff --git a/nebula-logger/managed-package/core/main/deprecated/customMetadata/LoggerSObjectHandler.LogEntryHandler.md-meta.xml b/nebula-logger/core/main/configuration/customMetadata/LoggerSObjectHandler.LogEntryHandler.md-meta.xml similarity index 63% rename from nebula-logger/managed-package/core/main/deprecated/customMetadata/LoggerSObjectHandler.LogEntryHandler.md-meta.xml rename to nebula-logger/core/main/configuration/customMetadata/LoggerSObjectHandler.LogEntryHandler.md-meta.xml index 1fa2d72d0..5cb69a7c2 100644 --- a/nebula-logger/managed-package/core/main/deprecated/customMetadata/LoggerSObjectHandler.LogEntryHandler.md-meta.xml +++ b/nebula-logger/core/main/configuration/customMetadata/LoggerSObjectHandler.LogEntryHandler.md-meta.xml @@ -6,6 +6,14 @@ > false + + IsEnabled__c + true + + + SObjectHandlerApexClass__c + LogEntryHandler + SObjectType__c LogEntry__c diff --git a/nebula-logger/managed-package/core/main/deprecated/customMetadata/LoggerSObjectHandler.LogEntryTagHandler.md-meta.xml b/nebula-logger/core/main/configuration/customMetadata/LoggerSObjectHandler.LogEntryTagHandler.md-meta.xml similarity index 63% rename from nebula-logger/managed-package/core/main/deprecated/customMetadata/LoggerSObjectHandler.LogEntryTagHandler.md-meta.xml rename to nebula-logger/core/main/configuration/customMetadata/LoggerSObjectHandler.LogEntryTagHandler.md-meta.xml index ca5175002..749122218 100644 --- a/nebula-logger/managed-package/core/main/deprecated/customMetadata/LoggerSObjectHandler.LogEntryTagHandler.md-meta.xml +++ b/nebula-logger/core/main/configuration/customMetadata/LoggerSObjectHandler.LogEntryTagHandler.md-meta.xml @@ -6,6 +6,14 @@ > false + + IsEnabled__c + true + + + SObjectHandlerApexClass__c + LogEntryTagHandler + SObjectType__c LogEntryTag__c diff --git a/nebula-logger/managed-package/core/main/deprecated/customMetadata/LoggerSObjectHandler.LogHandler.md-meta.xml b/nebula-logger/core/main/configuration/customMetadata/LoggerSObjectHandler.LogHandler.md-meta.xml similarity index 63% rename from nebula-logger/managed-package/core/main/deprecated/customMetadata/LoggerSObjectHandler.LogHandler.md-meta.xml rename to nebula-logger/core/main/configuration/customMetadata/LoggerSObjectHandler.LogHandler.md-meta.xml index 77c2ad016..93ed4638a 100644 --- a/nebula-logger/managed-package/core/main/deprecated/customMetadata/LoggerSObjectHandler.LogHandler.md-meta.xml +++ b/nebula-logger/core/main/configuration/customMetadata/LoggerSObjectHandler.LogHandler.md-meta.xml @@ -6,6 +6,14 @@ > false + + IsEnabled__c + true + + + SObjectHandlerApexClass__c + LogHandler + SObjectType__c Log__c diff --git a/nebula-logger/managed-package/core/main/deprecated/customMetadata/LoggerSObjectHandler.LoggerTagHandler.md-meta.xml b/nebula-logger/core/main/configuration/customMetadata/LoggerSObjectHandler.LoggerTagHandler.md-meta.xml similarity index 79% rename from nebula-logger/managed-package/core/main/deprecated/customMetadata/LoggerSObjectHandler.LoggerTagHandler.md-meta.xml rename to nebula-logger/core/main/configuration/customMetadata/LoggerSObjectHandler.LoggerTagHandler.md-meta.xml index 5a1fdd053..6ee82a774 100644 --- a/nebula-logger/managed-package/core/main/deprecated/customMetadata/LoggerSObjectHandler.LoggerTagHandler.md-meta.xml +++ b/nebula-logger/core/main/configuration/customMetadata/LoggerSObjectHandler.LoggerTagHandler.md-meta.xml @@ -10,6 +10,10 @@ IsEnabled__c true + + SObjectHandlerApexClass__c + LoggerTagHandler + SObjectType__c LoggerTag__c diff --git a/nebula-logger/core/main/configuration/layouts/LogEntryDataMaskRule__mdt-Log Entry Data Mask Rule Layout.layout-meta.xml b/nebula-logger/core/main/configuration/layouts/LogEntryDataMaskRule__mdt-Log Entry Data Mask Rule Layout.layout-meta.xml index 73e37b0ba..dfc86a88f 100644 --- a/nebula-logger/core/main/configuration/layouts/LogEntryDataMaskRule__mdt-Log Entry Data Mask Rule Layout.layout-meta.xml +++ b/nebula-logger/core/main/configuration/layouts/LogEntryDataMaskRule__mdt-Log Entry Data Mask Rule Layout.layout-meta.xml @@ -20,14 +20,6 @@ Edit IsEnabled__c - - Edit - ApplyToMessage__c - - - Edit - ApplyToRecordJson__c - diff --git a/nebula-logger/core/main/configuration/layouts/LoggerPlugin__mdt-Logger Plugin Layout.layout-meta.xml b/nebula-logger/core/main/configuration/layouts/LoggerPlugin__mdt-Logger Plugin Layout.layout-meta.xml new file mode 100644 index 000000000..2e002a970 --- /dev/null +++ b/nebula-logger/core/main/configuration/layouts/LoggerPlugin__mdt-Logger Plugin Layout.layout-meta.xml @@ -0,0 +1,152 @@ + + + + false + true + true + + + + Required + MasterLabel + + + Required + DeveloperName + + + + + Edit + IsEnabled__c + + + + + + true + false + false + + + + Edit + Description__c + + + + + + true + true + true + + + + Edit + SObjectHandlerApexClass__c + + + Edit + SObjectHandlerFlowName__c + + + + + Edit + SObjectHandlerExecutionOrder__c + + + + + + true + true + true + + + + Edit + BatchPurgerApexClass__c + + + Edit + BatchPurgerFlowName__c + + + + + Edit + BatchPurgerExecutionOrder__c + + + + + + true + true + true + + + + Edit + VersionNumber__c + + + + + Edit + Link__c + + + + + + false + true + true + + + + Required + NamespacePrefix + + + Readonly + CreatedById + + + + + Edit + IsProtected + + + Readonly + LastModifiedById + + + + + + true + true + false + + + + + + + false + false + false + false + false + + 00h1F000006uWJh + 4 + 0 + Default + + diff --git a/nebula-logger/managed-package/core/main/deprecated/layouts/LoggerSObjectHandler__mdt-Logger SObject Handler Layout.layout-meta.xml b/nebula-logger/core/main/configuration/layouts/LoggerSObjectHandler__mdt-Logger SObject Handler Layout.layout-meta.xml similarity index 77% rename from nebula-logger/managed-package/core/main/deprecated/layouts/LoggerSObjectHandler__mdt-Logger SObject Handler Layout.layout-meta.xml rename to nebula-logger/core/main/configuration/layouts/LoggerSObjectHandler__mdt-Logger SObject Handler Layout.layout-meta.xml index 3680063db..055e5a5c6 100644 --- a/nebula-logger/managed-package/core/main/deprecated/layouts/LoggerSObjectHandler__mdt-Logger SObject Handler Layout.layout-meta.xml +++ b/nebula-logger/core/main/configuration/layouts/LoggerSObjectHandler__mdt-Logger SObject Handler Layout.layout-meta.xml @@ -14,6 +14,10 @@ Required DeveloperName + + Required + SObjectHandlerApexClass__c + @@ -64,26 +68,6 @@ - - MasterLabel - DeveloperName - IsEnabled__c - CollectionType__c - DataType__c - Value__c - LoggerSObjectHandlerParameter__mdt.SObjectHandler__c - - - MasterLabel - DeveloperName - IsEnabled__c - PluginType__c - PluginApiName__c - ExecutionOrder__c - LoggerSObjectHandlerPlugin__mdt.SObjectHandler__c - ExecutionOrder__c - Asc - false false false diff --git a/nebula-logger/core/main/configuration/objects/LogEntryDataMaskRule__mdt/fields/ApplyToMessage__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LogEntryDataMaskRule__mdt/fields/ApplyToMessage__c.field-meta.xml index eac8ff40c..db3c9ad1e 100644 --- a/nebula-logger/core/main/configuration/objects/LogEntryDataMaskRule__mdt/fields/ApplyToMessage__c.field-meta.xml +++ b/nebula-logger/core/main/configuration/objects/LogEntryDataMaskRule__mdt/fields/ApplyToMessage__c.field-meta.xml @@ -1,11 +1,12 @@ ApplyToMessage__c + DeprecateCandidate true false DeveloperControlled When checked, the data mask rule is applied to log entry messages (stored in LogEntryEvent__e.Message__c and LogEntry__c.Message__c) - + Checkbox diff --git a/nebula-logger/core/main/configuration/objects/LogEntryDataMaskRule__mdt/fields/ApplyToRecordJson__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LogEntryDataMaskRule__mdt/fields/ApplyToRecordJson__c.field-meta.xml index c2a7a021e..adc3eb4f7 100644 --- a/nebula-logger/core/main/configuration/objects/LogEntryDataMaskRule__mdt/fields/ApplyToRecordJson__c.field-meta.xml +++ b/nebula-logger/core/main/configuration/objects/LogEntryDataMaskRule__mdt/fields/ApplyToRecordJson__c.field-meta.xml @@ -1,6 +1,7 @@ ApplyToRecordJson__c + DeprecateCandidate true false DeveloperControlled diff --git a/nebula-logger/core/main/configuration/objects/LogEntryDataMaskRule__mdt/listViews/All.listView-meta.xml b/nebula-logger/core/main/configuration/objects/LogEntryDataMaskRule__mdt/listViews/All.listView-meta.xml index 857957973..4a0900227 100644 --- a/nebula-logger/core/main/configuration/objects/LogEntryDataMaskRule__mdt/listViews/All.listView-meta.xml +++ b/nebula-logger/core/main/configuration/objects/LogEntryDataMaskRule__mdt/listViews/All.listView-meta.xml @@ -4,8 +4,6 @@ MasterLabel DeveloperName IsEnabled__c - ApplyToMessage__c - ApplyToRecordJson__c SensitiveDataRegEx__c ReplacementRegEx__c Everything diff --git a/nebula-logger/core/main/configuration/objects/LoggerParameter__mdt/fields/Description__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerParameter__mdt/fields/Description__c.field-meta.xml index 12250d074..8bb81ba37 100644 --- a/nebula-logger/core/main/configuration/objects/LoggerParameter__mdt/fields/Description__c.field-meta.xml +++ b/nebula-logger/core/main/configuration/objects/LoggerParameter__mdt/fields/Description__c.field-meta.xml @@ -1,10 +1,12 @@ Description__c + Active false DeveloperControlled 131072 + Confidential LongTextArea 3 diff --git a/nebula-logger/core/main/configuration/objects/LoggerParameter__mdt/fields/Value__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerParameter__mdt/fields/Value__c.field-meta.xml index ef72c996a..8e9b04d62 100644 --- a/nebula-logger/core/main/configuration/objects/LoggerParameter__mdt/fields/Value__c.field-meta.xml +++ b/nebula-logger/core/main/configuration/objects/LoggerParameter__mdt/fields/Value__c.field-meta.xml @@ -1,10 +1,12 @@ Value__c + Active false SubscriberControlled 131072 + Confidential LongTextArea 5 diff --git a/nebula-logger/core/main/configuration/objects/LoggerParameter__mdt/listViews/All.listView-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerParameter__mdt/listViews/All.listView-meta.xml index 0a99077ac..502caccd2 100644 --- a/nebula-logger/core/main/configuration/objects/LoggerParameter__mdt/listViews/All.listView-meta.xml +++ b/nebula-logger/core/main/configuration/objects/LoggerParameter__mdt/listViews/All.listView-meta.xml @@ -5,6 +5,7 @@ DeveloperName Value__c Description__c + IsProtected Everything diff --git a/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/LoggerPlugin__mdt.object-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/LoggerPlugin__mdt.object-meta.xml similarity index 100% rename from nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/LoggerPlugin__mdt.object-meta.xml rename to nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/LoggerPlugin__mdt.object-meta.xml diff --git a/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/BatchPurgerApexClass__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/BatchPurgerApexClass__c.field-meta.xml new file mode 100644 index 000000000..7cc5f650a --- /dev/null +++ b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/BatchPurgerApexClass__c.field-meta.xml @@ -0,0 +1,11 @@ + + + BatchPurgerApexClass__c + false + DeveloperControlled + + 255 + false + Text + false + diff --git a/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/ExecutionOrder__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/BatchPurgerExecutionOrder__c.field-meta.xml similarity index 88% rename from nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/ExecutionOrder__c.field-meta.xml rename to nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/BatchPurgerExecutionOrder__c.field-meta.xml index 802055ce4..74960641e 100644 --- a/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/ExecutionOrder__c.field-meta.xml +++ b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/BatchPurgerExecutionOrder__c.field-meta.xml @@ -1,13 +1,13 @@ - ExecutionOrder__c + BatchPurgerExecutionOrder__c The specific order to execute plugins in the org. Plugins are executed in order by sorting by execution order, then plugin name (ORDER BY ExecutionOrder__c NULLS LAST, DeveloperName). false SubscriberControlled The specific order to execute plugins in the org. Plugins are executed in order by sorting by execution order, then plugin name (ORDER BY ExecutionOrder__c NULLS LAST, DeveloperName). - + 3 false 0 diff --git a/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/BatchPurgerFlowName__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/BatchPurgerFlowName__c.field-meta.xml new file mode 100644 index 000000000..8bd098b7d --- /dev/null +++ b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/BatchPurgerFlowName__c.field-meta.xml @@ -0,0 +1,11 @@ + + + BatchPurgerFlowName__c + false + DeveloperControlled + + 255 + false + Text + false + diff --git a/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/Description__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/Description__c.field-meta.xml similarity index 100% rename from nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/Description__c.field-meta.xml rename to nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/Description__c.field-meta.xml diff --git a/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/ExecutionOrder__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/ExecutionOrder__c.field-meta.xml new file mode 100644 index 000000000..5a03d64e3 --- /dev/null +++ b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/ExecutionOrder__c.field-meta.xml @@ -0,0 +1,14 @@ + + + ExecutionOrder__c + Deprecated: This field is no longer used. + false + SubscriberControlled + Deprecated: This field is no longer used. + + 3 + false + 0 + Number + false + diff --git a/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/IsEnabled__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/IsEnabled__c.field-meta.xml similarity index 100% rename from nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/IsEnabled__c.field-meta.xml rename to nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/IsEnabled__c.field-meta.xml diff --git a/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/Link__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/Link__c.field-meta.xml new file mode 100644 index 000000000..d592b2fe4 --- /dev/null +++ b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/Link__c.field-meta.xml @@ -0,0 +1,10 @@ + + + Link__c + false + DeveloperControlled + An optional link for documentation about this plugin - useful for plugins that are packaged or deployed to multiple orgs + + false + Url + diff --git a/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/PluginApiName__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/PluginApiName__c.field-meta.xml new file mode 100644 index 000000000..9a2134a40 --- /dev/null +++ b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/PluginApiName__c.field-meta.xml @@ -0,0 +1,13 @@ + + + PluginApiName__c + Deprecated: This field is no longer used. + false + DeveloperControlled + Deprecated: This field is no longer used. + + 255 + false + Text + false + diff --git a/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/PluginType__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/PluginType__c.field-meta.xml similarity index 71% rename from nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/PluginType__c.field-meta.xml rename to nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/PluginType__c.field-meta.xml index 18b1d4371..b0b966f37 100644 --- a/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/PluginType__c.field-meta.xml +++ b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/PluginType__c.field-meta.xml @@ -1,12 +1,13 @@ PluginType__c - The type of plugin that the logging system should dynamically execute - Apex or Flow. + DeprecateCandidate + Deprecated: This field is no longer used. false DeveloperControlled - The type of plugin that the logging system should dynamically execute - Apex or Flow. - - true + Deprecated: This field is no longer used. + + false Picklist true diff --git a/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/SObjectHandlerApexClass__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/SObjectHandlerApexClass__c.field-meta.xml new file mode 100644 index 000000000..9fba0a7ee --- /dev/null +++ b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/SObjectHandlerApexClass__c.field-meta.xml @@ -0,0 +1,11 @@ + + + SObjectHandlerApexClass__c + false + DeveloperControlled + + 255 + false + Text + false + diff --git a/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/SObjectHandlerExecutionOrder__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/SObjectHandlerExecutionOrder__c.field-meta.xml new file mode 100644 index 000000000..8220324f8 --- /dev/null +++ b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/SObjectHandlerExecutionOrder__c.field-meta.xml @@ -0,0 +1,16 @@ + + + SObjectHandlerExecutionOrder__c + The specific order to execute plugins within Logger's trigger framework. Plugins are executed in order by sorting by execution order, then plugin name (ORDER BY ExecutionOrder__c NULLS LAST, DeveloperName). + false + SubscriberControlled + The specific order to execute plugins within Logger's trigger framework. Plugins are executed in order by sorting by execution order, then plugin name (ORDER BY ExecutionOrder__c NULLS LAST, DeveloperName). + + 3 + false + 0 + Number + false + diff --git a/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/SObjectHandlerFlowName__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/SObjectHandlerFlowName__c.field-meta.xml new file mode 100644 index 000000000..2af5ac38d --- /dev/null +++ b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/SObjectHandlerFlowName__c.field-meta.xml @@ -0,0 +1,11 @@ + + + SObjectHandlerFlowName__c + false + DeveloperControlled + + 255 + false + Text + false + diff --git a/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/SObjectType__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/SObjectType__c.field-meta.xml similarity index 63% rename from nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/SObjectType__c.field-meta.xml rename to nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/SObjectType__c.field-meta.xml index 7e6b5482a..44b23d9c4 100644 --- a/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/SObjectType__c.field-meta.xml +++ b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/SObjectType__c.field-meta.xml @@ -1,14 +1,16 @@ SObjectType__c + DeprecateCandidate + Deprecated: This field is no longer used. false DeveloperControlled - The logging system's SObject that should dynamically call the plugin. This controls when the plugin is executed. - + Deprecated: This field is no longer used. + EntityDefinition Logger Plugins LoggerSObjectHandlerPlugins - true + false MetadataRelationship false diff --git a/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/VersionNumber__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/VersionNumber__c.field-meta.xml new file mode 100644 index 000000000..a9d33f11d --- /dev/null +++ b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/fields/VersionNumber__c.field-meta.xml @@ -0,0 +1,12 @@ + + + VersionNumber__c + false + DeveloperControlled + An optional version number for the plugin - useful for plugins that are packaged or deployed to multiple orgs + + 18 + false + Text + false + diff --git a/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/listViews/All.listView-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/listViews/All.listView-meta.xml new file mode 100644 index 000000000..55e23a72f --- /dev/null +++ b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/listViews/All.listView-meta.xml @@ -0,0 +1,13 @@ + + + All + MasterLabel + DeveloperName + IsEnabled__c + SObjectHandlerExecutionOrder__c + BatchPurgerExecutionOrder__c + VersionNumber__c + Description__c + Everything + + diff --git a/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/validationRules/Plugins_are_not_supported.validationRule-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/validationRules/Plugins_are_not_supported.validationRule-meta.xml new file mode 100644 index 000000000..62c4d3c35 --- /dev/null +++ b/nebula-logger/core/main/configuration/objects/LoggerPlugin__mdt/validationRules/Plugins_are_not_supported.validationRule-meta.xml @@ -0,0 +1,9 @@ + + + Plugins_are_not_supported + false + Deprecated: this validation rule is no longer used + false + IsEnabled__c + Plugins are not supported for this SObject Handler + diff --git a/nebula-logger/managed-package/core/main/deprecated/objects/LoggerSObjectHandler__mdt/LoggerSObjectHandler__mdt.object-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerSObjectHandler__mdt/LoggerSObjectHandler__mdt.object-meta.xml similarity index 73% rename from nebula-logger/managed-package/core/main/deprecated/objects/LoggerSObjectHandler__mdt/LoggerSObjectHandler__mdt.object-meta.xml rename to nebula-logger/core/main/configuration/objects/LoggerSObjectHandler__mdt/LoggerSObjectHandler__mdt.object-meta.xml index 138dc5541..b97113ef0 100644 --- a/nebula-logger/managed-package/core/main/deprecated/objects/LoggerSObjectHandler__mdt/LoggerSObjectHandler__mdt.object-meta.xml +++ b/nebula-logger/core/main/configuration/objects/LoggerSObjectHandler__mdt/LoggerSObjectHandler__mdt.object-meta.xml @@ -1,7 +1,7 @@ Used to configure the Apex trigger handler classes that run on the objects LogEntryEvent__e, Log__c and LogEntry__c - - OLD: Logger SObject Handlers + + Logger SObject Handlers Public diff --git a/nebula-logger/managed-package/core/main/deprecated/objects/LoggerSObjectHandler__mdt/fields/IsEnabled__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerSObjectHandler__mdt/fields/IsEnabled__c.field-meta.xml similarity index 100% rename from nebula-logger/managed-package/core/main/deprecated/objects/LoggerSObjectHandler__mdt/fields/IsEnabled__c.field-meta.xml rename to nebula-logger/core/main/configuration/objects/LoggerSObjectHandler__mdt/fields/IsEnabled__c.field-meta.xml diff --git a/nebula-logger/core/main/configuration/objects/LoggerSObjectHandler__mdt/fields/SObjectHandlerApexClass__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerSObjectHandler__mdt/fields/SObjectHandlerApexClass__c.field-meta.xml new file mode 100644 index 000000000..a8741b00b --- /dev/null +++ b/nebula-logger/core/main/configuration/objects/LoggerSObjectHandler__mdt/fields/SObjectHandlerApexClass__c.field-meta.xml @@ -0,0 +1,13 @@ + + + SObjectHandlerApexClass__c + false + false + DeveloperControlled + The Apex class that extends the abstract LoggerSObjectHandler for the specified SObject Type + + 255 + false + Text + true + diff --git a/nebula-logger/managed-package/core/main/deprecated/objects/LoggerSObjectHandler__mdt/fields/SObjectType__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerSObjectHandler__mdt/fields/SObjectType__c.field-meta.xml similarity index 100% rename from nebula-logger/managed-package/core/main/deprecated/objects/LoggerSObjectHandler__mdt/fields/SObjectType__c.field-meta.xml rename to nebula-logger/core/main/configuration/objects/LoggerSObjectHandler__mdt/fields/SObjectType__c.field-meta.xml diff --git a/nebula-logger/managed-package/core/main/deprecated/objects/LoggerSObjectHandler__mdt/listViews/All.listView-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerSObjectHandler__mdt/listViews/All.listView-meta.xml similarity index 87% rename from nebula-logger/managed-package/core/main/deprecated/objects/LoggerSObjectHandler__mdt/listViews/All.listView-meta.xml rename to nebula-logger/core/main/configuration/objects/LoggerSObjectHandler__mdt/listViews/All.listView-meta.xml index f5ac4c12a..ac8c47633 100644 --- a/nebula-logger/managed-package/core/main/deprecated/objects/LoggerSObjectHandler__mdt/listViews/All.listView-meta.xml +++ b/nebula-logger/core/main/configuration/objects/LoggerSObjectHandler__mdt/listViews/All.listView-meta.xml @@ -5,6 +5,7 @@ DeveloperName IsEnabled__c SObjectType__c + SObjectHandlerApexClass__c Everything diff --git a/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/DefaultLogPurgeAction__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/DefaultLogPurgeAction__c.field-meta.xml new file mode 100644 index 000000000..a6513f00e --- /dev/null +++ b/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/DefaultLogPurgeAction__c.field-meta.xml @@ -0,0 +1,14 @@ + + + DefaultLogPurgeAction__c + 'Delete' + false + Sets the value of Log__c.LogPurgeAction__c, which is used by the batch job LogBatchPurger to indicate the action that should be taken for a Log__c record when LogRetentionDate__c < TODAY. + + 255 + false + false + Text + false + diff --git a/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/DefaultLogShareAccessLevel__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/DefaultLogShareAccessLevel__c.field-meta.xml index 1e0232424..faf8d70c7 100644 --- a/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/DefaultLogShareAccessLevel__c.field-meta.xml +++ b/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/DefaultLogShareAccessLevel__c.field-meta.xml @@ -3,8 +3,7 @@ DefaultLogShareAccessLevel__c 'Read' Uses Apex managed sharing to grants users read or edit access to their log records (on insert only). When no access level is specified, no Apex sharing logic is executed. This only gives record-level access - users will still need to be granted access to the Log__c object using permission sets or profiles. - + >Uses Apex managed sharing to grants users read or edit access to their log records (on insert only). When no access level is specified, no Apex sharing logic is executed. This only gives record-level access - users will still need to be granted access to the Log__c object using permission sets or profiles. false Uses Apex managed sharing to grants users read or edit access to their log records (on insert only). When no access level is specified, no Apex sharing logic is executed. This only gives record-level access - users will still need to be granted access to the Log__c object using permission sets or profiles. diff --git a/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/DefaultPlatformEventStorageLocation__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/DefaultPlatformEventStorageLocation__c.field-meta.xml new file mode 100644 index 000000000..329a5fa8c --- /dev/null +++ b/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/DefaultPlatformEventStorageLocation__c.field-meta.xml @@ -0,0 +1,16 @@ + + + DefaultPlatformEventStorageLocation__c + 'CUSTOM_OBJECTS' + Defaults to CUSTOM_OBJECTS. This controls the default location where LogEntryEvent__e records are stored - when null, LogEntryEvent__e records will not be stored. + false + Defaults to CUSTOM_OBJECTS. This controls the default location where LogEntryEvent__e records are stored - when null, LogEntryEvent__e records will not be stored. + + 255 + false + false + Text + false + diff --git a/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/IsSavingEnabled__c.field-meta.xml b/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/IsSavingEnabled__c.field-meta.xml index f9be7057f..250389be8 100644 --- a/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/IsSavingEnabled__c.field-meta.xml +++ b/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/IsSavingEnabled__c.field-meta.xml @@ -6,5 +6,6 @@ false Controls if saving is enabled - when disabled, any calls to saveLog() are ignored. + false Checkbox diff --git a/nebula-logger/core/main/log-management/applications/LoggerConsole.app-meta.xml b/nebula-logger/core/main/log-management/applications/LoggerConsole.app-meta.xml index c21894a87..ed1fa40be 100644 --- a/nebula-logger/core/main/log-management/applications/LoggerConsole.app-meta.xml +++ b/nebula-logger/core/main/log-management/applications/LoggerConsole.app-meta.xml @@ -9,6 +9,7 @@ Large false false + false Console Log__c diff --git a/nebula-logger/core/main/log-management/classes/LogBatchPurgeScheduler.cls b/nebula-logger/core/main/log-management/classes/LogBatchPurgeScheduler.cls index 424e55b17..9576d76c8 100644 --- a/nebula-logger/core/main/log-management/classes/LogBatchPurgeScheduler.cls +++ b/nebula-logger/core/main/log-management/classes/LogBatchPurgeScheduler.cls @@ -39,6 +39,6 @@ global with sharing class LogBatchPurgeScheduler implements System.Schedulable { Logger.saveLog(); } - Database.executebatch(new LogBatchPurger(), this.batchSize); + Database.executebatch(new LogBatchPurger().setChainedBatchSize(this.batchSize), this.batchSize); } } diff --git a/nebula-logger/core/main/log-management/classes/LogBatchPurger.cls b/nebula-logger/core/main/log-management/classes/LogBatchPurger.cls index 01121fa10..747f39549 100644 --- a/nebula-logger/core/main/log-management/classes/LogBatchPurger.cls +++ b/nebula-logger/core/main/log-management/classes/LogBatchPurger.cls @@ -8,12 +8,28 @@ * @description Batch class used to delete old logs, based on `Log__c.LogRetentionDate__c <= :System.today()` * @see LogBatchPurgeScheduler */ -@SuppressWarnings('PMD.AvoidGlobalModifier') +@SuppressWarnings('PMD.AvoidGlobalModifier, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList') global with sharing class LogBatchPurger implements Database.Batchable, Database.Stateful { + private static final Date LOG_RETENTION_END_DATE = System.today(); @TestVisible private static final String NO_DELETE_ACCESS_EXCEPTION_MESSAGE = 'User does not have access to delete logs'; + @TestVisible + private enum BatchableMethod { + START, + EXECUTE, + FINISH + } + + // Instance variables for top-level class + @TestVisible + private Integer chainedBatchSize = 200; + @TestVisible private SObjectType currentSObjectType; + private List pluginConfigurations; + private Map> methodToExecutedApexPlugins = new Map>(); + private Map> methodToExecutedFlowPlugins = new Map>(); + private String originalTransactionId; private Integer totalProcessedRecords; @@ -22,6 +38,17 @@ global with sharing class LogBatchPurger implements Database.Batchable, */ global LogBatchPurger() { this.totalProcessedRecords = 0; + this.pluginConfigurations = LoggerPlugin.getFilteredPluginConfigurations( + new List{ Schema.LoggerPlugin__mdt.BatchPurgerApexClass__c, Schema.LoggerPlugin__mdt.BatchPurgerFlowName__c }, + Schema.LoggerPlugin__mdt.BatchPurgerExecutionOrder__c + ); + + if (System.Test.isRunningTest() == true) { + for (BatchableMethod method : BatchableMethod.values()) { + this.methodToExecutedApexPlugins.put(method, new List()); + this.methodToExecutedFlowPlugins.put(method, new List()); + } + } } /** @@ -42,12 +69,16 @@ global with sharing class LogBatchPurger implements Database.Batchable, // Each batchable method runs in a separate transaction, // so store the first transaction ID to later relate the other transactions this.originalTransactionId = Logger.getTransactionId(); - this.currentSObjectType = this.getInitialSObjectType(); + + Schema.SObjectType initialSObjectType = this.getInitialSObjectType(); + LoggerBatchableContext input = new LoggerBatchableContext(batchableContext, initialSObjectType); + this.executePlugins(BatchableMethod.START, input, null); + this.currentSObjectType = input.sobjectType; if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { Logger.info('Logger - Starting LogBatchPurger job for SObject type: ' + this.currentSObjectType); - Logger.saveLog(); } + Logger.saveLog(); return this.getQueryLocator(this.currentSObjectType); } @@ -69,18 +100,23 @@ global with sharing class LogBatchPurger implements Database.Batchable, * @description Required by the Database.Batchable interface, this method executes the logic for purging * log records. * @param batchableContext - The context of the current batch job. - * @param loggerRecords - The log records to purge. + * @param scopeRecords - The log records to purge. */ - global void execute(Database.BatchableContext batchableContext, List loggerRecords) { + global void execute(Database.BatchableContext batchableContext, List scopeRecords) { + Logger.setParentLogTransactionId(this.originalTransactionId); try { - this.totalProcessedRecords += loggerRecords.size(); - this.hardDelete(loggerRecords); + this.totalProcessedRecords += scopeRecords.size(); + LoggerBatchableContext input = new LoggerBatchableContext(batchableContext, this.currentSObjectType); + this.executePlugins(BatchableMethod.EXECUTE, input, scopeRecords); + + LoggerDataStore.getDatabase().hardDeleteRecords(scopeRecords); + Logger.saveLog(); } catch (Exception apexException) { if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { Logger.error('Logger - Error deleting logs', apexException); } - } finally { Logger.saveLog(); + throw apexException; } } @@ -90,13 +126,16 @@ global with sharing class LogBatchPurger implements Database.Batchable, * @param batchableContext - The context of the batch jobs */ global void finish(Database.BatchableContext batchableContext) { + Logger.setParentLogTransactionId(this.originalTransactionId); + LoggerBatchableContext input = new LoggerBatchableContext(batchableContext, this.currentSObjectType); + this.executePlugins(BatchableMethod.FINISH, input, null); + Id nextBatchJobId; if (this.currentSObjectType != Schema.Log__c.SObjectType) { - nextBatchJobId = Database.executeBatch(new LogBatchPurger()); + nextBatchJobId = Database.executeBatch(this, this.chainedBatchSize); } if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { - Logger.setParentLogTransactionId(this.originalTransactionId); Logger.info( new LogMessage( 'Logger - Finished LogBatchPurger job for {0}, {1} total log records processed', @@ -111,14 +150,16 @@ global with sharing class LogBatchPurger implements Database.Batchable, } } - private void hardDelete(List records) { - // normally this would be an anti-pattern since most DML operations - // are a no-op with an empty list - but emptyRecycleBin throws - // for empty lists! - if (!records.isEmpty()) { - delete records; - Database.emptyRecycleBin(records); - } + /** + * @description The `LogBatchPurger` job is designed to run several instances - typically, it runs on `LogEntryTag__c`, + * then `LogEntry__c`, and finally `Log__c`. This method provides a way to control the batch size used for + * the chained instances of `LogBachPurger` + * @param chainedBatchSize The batch size to use for any subsequent chained instances of `LogBatchPurger` + * @return The same instance of `LogBatchPurger`, useful for chaining methods + */ + public LogBatchPurger setChainedBatchSize(Integer chainedBatchSize) { + this.chainedBatchSize = chainedBatchSize; + return this; } private Schema.SObjectType getInitialSObjectType() { @@ -137,12 +178,12 @@ global with sharing class LogBatchPurger implements Database.Batchable, return [ SELECT COUNT() FROM LogEntryTag__c - WHERE LogEntry__r.Log__r.LogRetentionDate__c <= :System.today() AND LogEntry__r.Log__r.LogRetentionDate__c != NULL + WHERE LogEntry__r.Log__r.LogRetentionDate__c <= :LOG_RETENTION_END_DATE AND LogEntry__r.Log__r.LogRetentionDate__c != NULL ]; } private Integer getLogEntryCount() { - return [SELECT COUNT() FROM LogEntry__c WHERE Log__r.LogRetentionDate__c <= :System.today() AND Log__r.LogRetentionDate__c != NULL]; + return [SELECT COUNT() FROM LogEntry__c WHERE Log__r.LogRetentionDate__c <= :LOG_RETENTION_END_DATE AND Log__r.LogRetentionDate__c != NULL]; } /** @@ -162,7 +203,7 @@ global with sharing class LogBatchPurger implements Database.Batchable, [ SELECT Id FROM LogEntryTag__c - WHERE LogEntry__r.Log__r.LogRetentionDate__c <= :System.today() AND LogEntry__r.Log__r.LogRetentionDate__c != NULL + WHERE LogEntry__r.Log__r.LogRetentionDate__c <= :LOG_RETENTION_END_DATE AND LogEntry__r.Log__r.LogRetentionDate__c != NULL ORDER BY LogEntry__r.Log__r.LogRetentionDate__c, LogEntry__r.Log__c ] ); @@ -172,7 +213,7 @@ global with sharing class LogBatchPurger implements Database.Batchable, [ SELECT Id FROM LogEntry__c - WHERE Log__r.LogRetentionDate__c <= :System.today() AND Log__r.LogRetentionDate__c != NULL + WHERE Log__r.LogRetentionDate__c <= :LOG_RETENTION_END_DATE AND Log__r.LogRetentionDate__c != NULL ORDER BY Log__r.LogRetentionDate__c, Log__c ] ); @@ -182,7 +223,7 @@ global with sharing class LogBatchPurger implements Database.Batchable, [ SELECT Id FROM Log__c - WHERE (LogRetentionDate__c <= :System.today() AND LogRetentionDate__c != NULL) OR TotalLogEntries__c = 0 + WHERE (LogRetentionDate__c <= :LOG_RETENTION_END_DATE AND LogRetentionDate__c != NULL) OR TotalLogEntries__c = 0 ORDER BY LogRetentionDate__c ] ); @@ -191,4 +232,84 @@ global with sharing class LogBatchPurger implements Database.Batchable, return queryLocator; } + + private void executePlugins(BatchableMethod method, LoggerBatchableContext input, List scopeRecords) { + for (LoggerPlugin__mdt pluginConfiguration : this.pluginConfigurations) { + if (String.isNotBlank(pluginConfiguration.BatchPurgerApexClass__c) == true) { + this.executeApexPlugin(method, pluginConfiguration, input, scopeRecords); + } + if (String.isNotBlank(pluginConfiguration.BatchPurgerFlowName__c) == true) { + this.executeFlowPlugin(method, pluginConfiguration, input, scopeRecords); + } + } + } + + @SuppressWarnings('PMD.AvoidDebugStatements') + private void executeApexPlugin(BatchableMethod method, LoggerPlugin__mdt pluginConfiguration, LoggerBatchableContext input, List scopeRecords) { + if (String.isBlank(pluginConfiguration.BatchPurgerApexClass__c) == true) { + return; + } + + try { + LoggerPlugin.Batchable apexPlugin = LoggerPlugin.newBatchableInstance(pluginConfiguration.BatchPurgerApexClass__c); + switch on method { + when START { + apexPlugin.start(pluginConfiguration, input); + } + when EXECUTE { + apexPlugin.execute(pluginConfiguration, input, scopeRecords); + } + when FINISH { + apexPlugin.finish(pluginConfiguration, input); + } + } + + if (System.Test.isRunningTest() == true && apexPlugin != null) { + this.methodToExecutedApexPlugins.get(method).add(apexPlugin); + } + } catch (TypeException ex) { + if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { + Logger.warn('Unknown Apex class ' + pluginConfiguration.BatchPurgerApexClass__c + ', skipping plugin execution', pluginConfiguration, ex); + } + } + } + + @SuppressWarnings('PMD.AvoidDebugStatements') + private void executeFlowPlugin(BatchableMethod method, LoggerPlugin__mdt pluginConfiguration, LoggerBatchableContext input, List scopeRecords) { + if (String.isBlank(pluginConfiguration.BatchPurgerFlowName__c) == true) { + return; + } + + try { + Map flowInputs = new Map(); + flowInputs.put('pluginConfiguration', pluginConfiguration); + flowInputs.put('pluginInput', input); + if (scopeRecords != null) { + flowInputs.put('scopeRecords', scopeRecords); + } + + Flow.Interview flowPlugin = Flow.Interview.createInterview(pluginConfiguration.BatchPurgerFlowName__c, flowInputs); + flowPlugin.start(); + + if (System.Test.isRunningTest() == true && flowPlugin != null) { + this.methodToExecutedFlowPlugins.get(method).add(flowPlugin); + } + } catch (TypeException ex) { + if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { + Logger.warn('Unknown Flow ' + pluginConfiguration.BatchPurgerFlowName__c + ', skipping plugin execution', pluginConfiguration, ex); + } + } + } + + // TODO Before v4.8.0, consider changing visibility from `@TestVisbile private` to `public`. This would + // provide a way for downstream code (within core and plugins) to retrieve info about the executed plugins + @TestVisible + private Map> getExecutedApexPlugins() { + return this.methodToExecutedApexPlugins; + } + + @TestVisible + private Map> getExecutedFlowPlugins() { + return this.methodToExecutedFlowPlugins; + } } diff --git a/nebula-logger/core/main/log-management/classes/LogEntryEventHandler.cls b/nebula-logger/core/main/log-management/classes/LogEntryEventHandler.cls index c15d7ab5e..b4054d678 100644 --- a/nebula-logger/core/main/log-management/classes/LogEntryEventHandler.cls +++ b/nebula-logger/core/main/log-management/classes/LogEntryEventHandler.cls @@ -7,8 +7,10 @@ * @group Log Management * @description Processes `LogEntryEvent__e` platform events and normalizes the data into `Log__c` and `LogEntry__c` records */ -@SuppressWarnings('PMD.ApexCRUDViolation, PMD.AvoidDebugStatements, PMD.CyclomaticComplexity, PMD.CognitiveComplexity') +@SuppressWarnings('PMD.ApexCrudViolation, PMD.AvoidDebugStatements, PMD.CognitiveComplexity, PMD.CyclomaticComplexity') public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { + @TestVisible + private static final String DEFAULT_STORAGE_LOCATION_NAME = 'CUSTOM_OBJECTS'; private static final Database.DmlOptions DML_OPTIONS = createDmlOptions(); private static final Map TRANSACTION_ID_TO_LOG = new Map(); @TestVisible @@ -22,32 +24,29 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { private Set tagNames = new Set(); /** - * @description Returns SObject Type that the handler is responsible for processing - * @return The instance of `SObjectType` + * @description Default constructor, used by the trigger `LogEntryEvent.trigger` */ - public override SObjectType getSObjectType() { - return Schema.LogEntryEvent__e.SObjectType; + public LogEntryEventHandler() { + super(); } /** - * @description method so it can be called from Logger - this is unique to LogEntryEventHandler - * @param triggerNew list of new LogEntryEvent events + * @description Returns SObject Type that the handler is responsible for processing + * @return The instance of `SObjectType` */ - public override void executeBeforeInsert(List triggerNew) { - this.logEntryEvents = (List) triggerNew; + public override SObjectType getSObjectType() { + return Schema.LogEntryEvent__e.SObjectType; } - /** - * @description Public method so it can be called from Logger - this is unique to LogEntryEventHandler - * @param triggerNew list of new LogEntryEvent events - */ - public override void executeAfterInsert(List triggerNew) { + protected override void executeAfterInsert(List triggerNew) { this.logEntryEvents = this.filterLogEntryEventsToSave((List) triggerNew); - this.upsertLogs(); - this.insertLogEntries(); - this.appendRuleBasedTags(); - this.insertLogEntryTags(); + if (this.logEntryEvents.isEmpty() == false) { + this.upsertLogs(); + this.insertLogEntries(); + this.appendRuleBasedTags(); + this.insertLogEntryTags(); + } } private List filterLogEntryEventsToSave(List newLogEntryEvents) { @@ -55,7 +54,7 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { for (LogEntryEvent__e logEntryEvent : newLogEntryEvents) { User loggingUser = new User(Id = logEntryEvent.LoggedById__c, ProfileId = logEntryEvent.ProfileId__c); LoggerSettings__c loggingUserSettings = Logger.getUserSettings(loggingUser); - if (loggingUserSettings.IsPlatformEventStorageEnabled__c == true) { + if (loggingUserSettings.DefaultPlatformEventStorageLocation__c == DEFAULT_STORAGE_LOCATION_NAME) { logEntryEventsToSave.add(logEntryEvent); } } @@ -142,10 +141,12 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { TRANSACTION_ID_TO_LOG.put(log.TransactionId__c, log); } - List upsertResults = Database.upsert(TRANSACTION_ID_TO_LOG.values(), Schema.Log__c.TransactionId__c, false); - LoggerEmailUtils.sendErrorEmail(Schema.Log__c.SObjectType, upsertResults); + List upsertResults = LoggerDataStore.getDatabase() + .upsertRecords(TRANSACTION_ID_TO_LOG.values(), Schema.Log__c.TransactionId__c, System.Test.isRunningTest()); + LoggerEmailSender.sendErrorEmail(Schema.Log__c.SObjectType, upsertResults); // If no recent logs have the details, and there is not another instance of the job in progress, then start a new one + // TODO this probably should be moved to LogHandler instead of here if (LoggerParameter.CALL_STATUS_API == true && recentLogWithApiReleaseDetails == null && getCountOfOpenJobs() == 0) { setStatusApiDetails(); } @@ -160,6 +161,7 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { LogEntry__c logEntry = new LogEntry__c( ComponentType__c = logEntryEvent.ComponentType__c, + DatabaseResultCollectionSize__c = logEntryEvent.DatabaseResultCollectionSize__c, DatabaseResultCollectionType__c = logEntryEvent.DatabaseResultCollectionType__c, DatabaseResultJson__c = logEntryEvent.DatabaseResultJson__c, DatabaseResultType__c = logEntryEvent.DatabaseResultType__c, @@ -168,6 +170,16 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { ExceptionMessage__c = logEntryEvent.ExceptionMessage__c, ExceptionStackTrace__c = logEntryEvent.ExceptionStackTrace__c, ExceptionType__c = logEntryEvent.ExceptionType__c, + HttpRequestBody__c = logEntryEvent.HttpRequestBody__c, + HttpRequestBodyMasked__c = logEntryEvent.HttpRequestBodyMasked__c, + HttpRequestCompressed__c = logEntryEvent.HttpRequestCompressed__c, + HttpRequestEndpoint__c = logEntryEvent.HttpRequestEndpoint__c, + HttpRequestMethod__c = logEntryEvent.HttpRequestMethod__c, + HttpResponseBody__c = logEntryEvent.HttpResponseBody__c, + HttpResponseBodyMasked__c = logEntryEvent.HttpResponseBodyMasked__c, + HttpResponseHeaderKeys__c = logEntryEvent.HttpResponseHeaderKeys__c, + HttpResponseStatus__c = logEntryEvent.HttpResponseStatus__c, + HttpResponseStatusCode__c = logEntryEvent.HttpResponseStatusCode__c, LimitsAggregateQueriesMax__c = logEntryEvent.LimitsAggregateQueriesMax__c, LimitsAggregateQueriesUsed__c = logEntryEvent.LimitsAggregateQueriesUsed__c, LimitsAsyncCallsMax__c = logEntryEvent.LimitsAsyncCallsMax__c, @@ -209,6 +221,7 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { Name = null, // Salesforce will auto-set the record ID as the name when null OriginLocation__c = logEntryEvent.OriginLocation__c, OriginType__c = logEntryEvent.OriginType__c, + RecordCollectionSize__c = logEntryEvent.RecordCollectionSize__c, RecordCollectionType__c = logEntryEvent.RecordCollectionType__c, RecordId__c = logEntryEvent.RecordId__c, RecordJson__c = logEntryEvent.RecordJson__c, @@ -233,8 +246,8 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { } } - List saveResults = Database.insert(this.logEntries, DML_OPTIONS); - LoggerEmailUtils.sendErrorEmail(Schema.LogEntry__c.SObjectType, saveResults); + List saveResults = LoggerDataStore.getDatabase().insertRecords(this.logEntries, DML_OPTIONS); + LoggerEmailSender.sendErrorEmail(Schema.LogEntry__c.SObjectType, saveResults); } private void appendRuleBasedTags() { @@ -295,8 +308,8 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { } } - List saveResults = Database.insert(new List(tagAssignments), DML_OPTIONS); - LoggerEmailUtils.sendErrorEmail(tagAssignmentSObjectType, saveResults); + List saveResults = LoggerDataStore.getDatabase().insertRecords(new List(tagAssignments), DML_OPTIONS); + LoggerEmailSender.sendErrorEmail(tagAssignmentSObjectType, saveResults); } private Map getTagNameToId(Schema.SObjectType tagSObjectType) { @@ -324,8 +337,8 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { } if (!missingTagsToCreate.isEmpty()) { - List saveResults = Database.insert(missingTagsToCreate, DML_OPTIONS); - LoggerEmailUtils.sendErrorEmail(tagSObjectType, saveResults); + List saveResults = LoggerDataStore.getDatabase().insertRecords(missingTagsToCreate, DML_OPTIONS); + LoggerEmailSender.sendErrorEmail(tagSObjectType, saveResults); for (SObject tag : missingTagsToCreate) { missingTagNameToId.put((String) tag.get('Name'), (Id) tag.get('Id')); } @@ -338,7 +351,7 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { private static Database.DmlOptions createDmlOptions() { Database.DmlOptions dmlOptions = new Database.DmlOptions(); dmlOptions.AllowFieldTruncation = true; - dmlOptions.OptAllOrNone = false; + dmlOptions.OptAllOrNone = System.Test.isRunningTest(); return dmlOptions; } @@ -427,7 +440,9 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { @future(callout=true) private static void setStatusApiDetails() { - System.debug(LoggingLevel.DEBUG, 'Logger - Calling Status API for org details'); + if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { + Logger.debug('Logger - Calling Status API for org details'); + } Organization organization = [SELECT InstanceName FROM Organization]; String statusApiEndpoint = 'https://api.status.salesforce.com/v1/instances/' + organization.InstanceName + '/status'; @@ -450,7 +465,9 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { } StatusApiResponse statusApiResponse = (StatusApiResponse) JSON.deserialize(response.getBody(), StatusApiResponse.class); - System.debug(LoggingLevel.DEBUG, 'Logger - Status API response: ' + statusApiResponse); + if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { + Logger.debug('Logger - Status API response: ' + statusApiResponse); + } List logsToUpdate = new List(); for (Log__c log : [ @@ -465,8 +482,13 @@ public without sharing class LogEntryEventHandler extends LoggerSObjectHandler { logsToUpdate.add(log); } - System.debug(LoggingLevel.DEBUG, 'Logger - logs to update: ' + logsToUpdate); - update logsToUpdate; + + if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { + Logger.debug('Logger - logs to update: ' + logsToUpdate); + } + + LoggerDataStore.getDatabase().updateRecords(logsToUpdate); + Logger.saveLog(); } // Private class for handling the response from api.status.salesforce.com diff --git a/nebula-logger/core/main/log-management/classes/LogEntryHandler.cls b/nebula-logger/core/main/log-management/classes/LogEntryHandler.cls index 71baae386..d31a8897b 100644 --- a/nebula-logger/core/main/log-management/classes/LogEntryHandler.cls +++ b/nebula-logger/core/main/log-management/classes/LogEntryHandler.cls @@ -9,6 +9,8 @@ */ @SuppressWarnings('PMD.ApexCrudViolation, PMD.CognitiveComplexity, PMD.CyclomaticComplexity, PMD.NcssMethodCount, PMD.StdCyclomaticComplexity') public without sharing class LogEntryHandler extends LoggerSObjectHandler { + private static final Map SOBJECT_TYPE_TO_DISPLAY_FIELD_NAME = new Map(); + @TestVisible private List logEntries; @@ -94,10 +96,6 @@ public without sharing class LogEntryHandler extends LoggerSObjectHandler { innerApexClassName = innerApexClassName.substringAfter(topLevelApexClassName + '.'); } - // TODO confirm if there any issues with automated users (e.g., PackagePushJob uses a not-quite-a-user) - // logEntry.ApexClassCreatedById__c = topLevelApexClass.CreatedById; - // logEntry.ApexClassLastModifiedById__c = apexClass.LastModifiedById; - logEntry.ApexClassApiVersion__c = 'v' + topLevelApexClass.ApiVersion; logEntry.ApexClassCreatedDate__c = topLevelApexClass.CreatedDate; logEntry.ApexClassId__c = topLevelApexClass.Id; @@ -238,8 +236,9 @@ public without sharing class LogEntryHandler extends LoggerSObjectHandler { for (Schema.SObjectType sobjectType : sobjectTypeToRecords.keySet()) { // Stop if we've used up all the queries if (Limits.getQueries() == Limits.getLimitQueries()) { - return; + break; } + List sobjectTypeRecordIds = sobjectTypeToRecords.get(sobjectType); String sobjectDisplayFieldName = this.getDisplayFieldApiName(sobjectType); @@ -277,9 +276,15 @@ public without sharing class LogEntryHandler extends LoggerSObjectHandler { } private String getDisplayFieldApiName(Schema.SObjectType sobjectType) { + if (SOBJECT_TYPE_TO_DISPLAY_FIELD_NAME.containsKey(sobjectType) == true) { + return SOBJECT_TYPE_TO_DISPLAY_FIELD_NAME.get(sobjectType); + } + // Use username instead of name for user if (sobjectType == Schema.User.SObjectType) { - return Schema.User.Username.getDescribe().getName(); + String userFieldName = Schema.User.Username.getDescribe().getName(); + SOBJECT_TYPE_TO_DISPLAY_FIELD_NAME.put(Schema.User.SObjectType, userFieldName); + return userFieldName; } // There are several commonly used names for the display field name - typically, Name @@ -305,6 +310,7 @@ public without sharing class LogEntryHandler extends LoggerSObjectHandler { }; String displayFieldApiName; + List fallbackFieldApiNames = new List(); for (String fieldName : educatedGuesses) { Schema.SObjectField field = sobjectType.getDescribe().fields.getMap().get(fieldName); @@ -314,19 +320,23 @@ public without sharing class LogEntryHandler extends LoggerSObjectHandler { Schema.DescribeFieldResult fieldDescribe = field.getDescribe(); - if (fieldDescribe.isNameField()) { + if (fieldDescribe.isNameField() == true) { displayFieldApiName = fieldDescribe.getName(); break; + } else { + fallbackFieldApiNames.add(fieldDescribe.getName()); } } - return displayFieldApiName; - } - - private static String getNamespacePrefix() { - String className = LogEntryHandler.class.getName(); - String namespacePrefix = className.contains('.') ? className.substringBefore('.') : ''; + // Some objects don't have a proper 'display field', but they do have a reasonable alternative field to use instead. + // For example, EmailMessage doesn't have a true display field, but it has a 'Subject' field. If one (and only one) + // of the educated guess-fields exists on the object - and the object does not have a display field - then use the + // educated guess-field as the fallback for the display field. + if (String.isBlank(displayFieldApiName) == true && fallbackFieldApiNames.size() == 1) { + displayFieldApiName = fallbackFieldApiNames.get(0); + } - return namespacePrefix; + SOBJECT_TYPE_TO_DISPLAY_FIELD_NAME.put(sobjectType, displayFieldApiName); + return displayFieldApiName; } } diff --git a/nebula-logger/core/main/log-management/classes/LogHandler.cls b/nebula-logger/core/main/log-management/classes/LogHandler.cls index 3f0361185..bd7b7ab2e 100644 --- a/nebula-logger/core/main/log-management/classes/LogHandler.cls +++ b/nebula-logger/core/main/log-management/classes/LogHandler.cls @@ -9,10 +9,8 @@ */ @SuppressWarnings('PMD.ApexCrudViolation, PMD.CognitiveComplexity, PMD.CyclomaticComplexity') public without sharing class LogHandler extends LoggerSObjectHandler { - @TestVisible - private static final Map LOG_STATUS_NAME_TO_STATUS = loadActiveLogStatuses(); - @TestVisible - private static final Map SCENARIO_TO_MOCK_SCENARIO_RULE = new Map(); + private static final Map MOCK_LOG_STATUS_TO_STATUS = new Map(); + private static final Map MOCK_SCENARIO_TO_SCENARIO_RULE = new Map(); @TestVisible private List logs; @@ -34,7 +32,7 @@ public without sharing class LogHandler extends LoggerSObjectHandler { // The log OwnerId field should support being manually changed, so only auto-set it on insert this.setOwnerId(); // The log retention date field should support being manually changed, so only auto-set it on insert - this.setLogRetentionDate(); + this.setLogRetentionDetails(); } protected override void executeBeforeUpdate(Map triggerNewMap, Map triggerOldMap) { @@ -53,9 +51,10 @@ public without sharing class LogHandler extends LoggerSObjectHandler { } private void setClosedStatusFields() { + Map logStatusNameToStatus = loadActiveLogStatuses(); for (Log__c log : this.logs) { // Determine if the status is considered closed (based on `LogStatus__mdt` custom metadata) - LogStatus__mdt logStatus = LOG_STATUS_NAME_TO_STATUS.get(log.Status__c); + LogStatus__mdt logStatus = logStatusNameToStatus.get(log.Status__c); if (logStatus != null) { log.IsClosed__c = logStatus.IsClosed__c; log.IsResolved__c = logStatus.IsResolved__c; @@ -106,7 +105,7 @@ public without sharing class LogHandler extends LoggerSObjectHandler { } } - private void setLogRetentionDate() { + private void setLogRetentionDetails() { Map scenarioToScenarioRule = queryScenarioRules(this.logs); for (Log__c log : this.logs) { // If the retention date has already been populated, leave it as-is @@ -119,17 +118,16 @@ public without sharing class LogHandler extends LoggerSObjectHandler { // Load the configured scenario rule (if one exists) LogScenarioRule__mdt matchingScenarioRule = scenarioToScenarioRule.get(log.Scenario__c); - if (System.Test.isRunningTest() == true) { - matchingScenarioRule = SCENARIO_TO_MOCK_SCENARIO_RULE.get(log.Scenario__c); - } Integer daysToRetainLog = Integer.valueOf( matchingScenarioRule != null ? matchingScenarioRule.NumberOfDaysToRetainLogs__c : loggingUserSettings.DefaultNumberOfDaysToRetainLogs__c ); + // TODO Add new field to LogScenarioRule__mdt for setting the default log purge action (same concept as matchingScenarioRule.NumberOfDaysToRetainLogs__c above) // When daysToRetainLog is null, assume that the log should be kept forever, // and set the retention date to null so that LogBatchPurger filters out/ignores the record log.LogRetentionDate__c = daysToRetainLog == null ? null : System.today().addDays(daysToRetainLog); + log.LogPurgeAction__c = loggingUserSettings.DefaultLogPurgeAction__c; } } @@ -179,7 +177,7 @@ public without sharing class LogHandler extends LoggerSObjectHandler { ); logShares.add(logShare); } - Database.insert(logShares, false); + LoggerDataStore.getDatabase().insertRecords(logShares, false); } private static LoggerSettings__c getLoggingUserSettings(Log__c log) { @@ -194,6 +192,12 @@ public without sharing class LogHandler extends LoggerSObjectHandler { logStatusNameToStatus.put(logStatus.MasterLabel, logStatus); } } + + if (System.Test.isRunningTest() == true) { + logStatusNameToStatus.clear(); + logStatusNameToStatus.putAll(MOCK_LOG_STATUS_TO_STATUS); + } + return logStatusNameToStatus; } @@ -229,11 +233,22 @@ public without sharing class LogHandler extends LoggerSObjectHandler { ]) { scenarioToScenarioRule.put(scenarioRule.Scenario__c, scenarioRule); } + + if (System.Test.isRunningTest() == true) { + scenarioToScenarioRule.clear(); + scenarioToScenarioRule.putAll(MOCK_SCENARIO_TO_SCENARIO_RULE); + } + return scenarioToScenarioRule; } + @TestVisible + private static void setMockLogStatus(LogStatus__mdt logStatus) { + MOCK_LOG_STATUS_TO_STATUS.put(logStatus.MasterLabel, logStatus); + } + @TestVisible private static void setMockScenarioRule(LogScenarioRule__mdt scenarioRule) { - SCENARIO_TO_MOCK_SCENARIO_RULE.put(scenarioRule.Scenario__c, scenarioRule); + MOCK_SCENARIO_TO_SCENARIO_RULE.put(scenarioRule.Scenario__c, scenarioRule); } } diff --git a/nebula-logger/core/main/log-management/classes/LogMassDeleteExtension.cls b/nebula-logger/core/main/log-management/classes/LogMassDeleteExtension.cls index 8bc7b50d9..feecb13c4 100644 --- a/nebula-logger/core/main/log-management/classes/LogMassDeleteExtension.cls +++ b/nebula-logger/core/main/log-management/classes/LogMassDeleteExtension.cls @@ -55,7 +55,7 @@ public with sharing class LogMassDeleteExtension { * @return The PageReference of the previous page (based on `controller.cancel()`) */ public PageReference deleteSelectedLogs() { - delete getDeletableLogs(); + LoggerDataStore.getDatabase().deleteRecords(getDeletableLogs()); // The controller's method cancel() just returns the user to the previous page - it doesn't rollback any DML statements (like the delete above) return this.controller.cancel(); diff --git a/nebula-logger/core/main/log-management/classes/LoggerBatchableContext.cls b/nebula-logger/core/main/log-management/classes/LoggerBatchableContext.cls new file mode 100644 index 000000000..14815b66d --- /dev/null +++ b/nebula-logger/core/main/log-management/classes/LoggerBatchableContext.cls @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @group Log Management + * @description Class used by the logging system for batch contextual details + * @see LogBatchPurger + * @see LoggerPlugin + */ +@SuppressWarnings('PMD.ApexDoc') +public without sharing class LoggerBatchableContext { + @AuraEnabled + public Database.BatchableContext batchableContext; + public transient Schema.SObjectType sobjectType; + @AuraEnabled + public String sobjectTypeName; + + /** + * @description Constructor used to set the 2 properties + * @param batchableContext The instance of `Database.BatchableContextbatchableContext`, provided by the platform at run-time + * @param sobjectType The `SObjectType` that will be queried & purged + */ + public LoggerBatchableContext(Database.BatchableContext batchableContext, Schema.SObjectType sobjectType) { + this.batchableContext = batchableContext; + this.sobjectType = sobjectType; + this.sobjectTypeName = sobjectType?.getDescribe().getName(); + } +} diff --git a/nebula-logger/core/main/log-management/classes/LoggerSObjectHandler.cls-meta.xml b/nebula-logger/core/main/log-management/classes/LoggerBatchableContext.cls-meta.xml similarity index 100% rename from nebula-logger/core/main/log-management/classes/LoggerSObjectHandler.cls-meta.xml rename to nebula-logger/core/main/log-management/classes/LoggerBatchableContext.cls-meta.xml diff --git a/nebula-logger/core/main/configuration/classes/LoggerEmailUtils.cls b/nebula-logger/core/main/log-management/classes/LoggerEmailSender.cls similarity index 83% rename from nebula-logger/core/main/configuration/classes/LoggerEmailUtils.cls rename to nebula-logger/core/main/log-management/classes/LoggerEmailSender.cls index 7770cab70..916e11692 100644 --- a/nebula-logger/core/main/configuration/classes/LoggerEmailUtils.cls +++ b/nebula-logger/core/main/log-management/classes/LoggerEmailSender.cls @@ -4,11 +4,16 @@ //------------------------------------------------------------------------------------------------// /** - * @group Configuration + * @group Log Management * @description Builds and sends email notifications when internal exceptions occur within the logging system */ @SuppressWarnings('PMD.PropertyNamingConventions') -public without sharing class LoggerEmailUtils { +public without sharing class LoggerEmailSender { + @TestVisible + private static final List MOCK_NOTIFICATIONS = new List(); + @TestVisible + private static final List SENT_EMAILS = new List(); + @TestVisible private static final List CACHED_APEX_ERROR_RECIPIENTS { get { @@ -20,17 +25,16 @@ public without sharing class LoggerEmailUtils { set; } + @TestVisible private static Boolean IS_EMAIL_DELIVERABILITY_ENABLED { get { if (IS_EMAIL_DELIVERABILITY_ENABLED == null) { try { - Messaging.reserveSingleEmailCapacity(1); - Messaging.reserveMassEmailCapacity(1); + System.Messaging.reserveSingleEmailCapacity(1); + System.Messaging.reserveMassEmailCapacity(1); IS_EMAIL_DELIVERABILITY_ENABLED = true; - return IS_EMAIL_DELIVERABILITY_ENABLED; } catch (System.NoAccessException e) { IS_EMAIL_DELIVERABILITY_ENABLED = false; - return IS_EMAIL_DELIVERABILITY_ENABLED; } } return IS_EMAIL_DELIVERABILITY_ENABLED; @@ -38,17 +42,6 @@ public without sharing class LoggerEmailUtils { set; } - @TestVisible - private static final List SENT_EMAILS { - get { - if (SENT_EMAILS == null) { - SENT_EMAILS = new List(); - } - return SENT_EMAILS; - } - set; - } - /** * @description Sends an error email notification to the org's list of Apex Exception Email recipients, * configured under Setup --> Email --> Apex Exception Email @@ -88,7 +81,9 @@ public without sharing class LoggerEmailUtils { } if (CACHED_APEX_ERROR_RECIPIENTS.isEmpty() == true) { - System.debug(LoggingLevel.INFO, 'Logger - no Apex email recipients configured, skipping sending email'); + if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { + Logger.info('Logger - no Apex email recipients configured, skipping sending email'); + } return; } @@ -129,10 +124,13 @@ public without sharing class LoggerEmailUtils { List messages = new List{ message }; List emailResults = Messaging.sendEmail(messages); SENT_EMAILS.add(message); - if (emailResults[0].success == true) { - System.debug(LoggingLevel.INFO, 'Logger - The email was sent successfully'); + + if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == false) { + return; + } else if (emailResults.get(0).success == true) { + Logger.info('Logger - The email was sent successfully'); } else { - System.debug(LoggingLevel.INFO, 'Logger - The email failed to send: ' + emailResults[0].errors[0].message); + Logger.info('Logger - The email failed to send: ' + emailResults.get(0).errors.get(0).message); } } } @@ -159,10 +157,17 @@ public without sharing class LoggerEmailUtils { @SuppressWarnings('PMD.ApexCRUDViolation') private static List queryApexErrrorRecipients() { List apexErrrorRecipients = new List(); - for (ApexEmailNotification notification : [SELECT Email, UserId FROM ApexEmailNotification WHERE Email != NULL OR User.IsActive = TRUE]) { + List notifications = [SELECT Email, UserId FROM ApexEmailNotification WHERE Email != NULL OR User.IsActive = TRUE]; + + if (System.Test.isRunningTest() == true) { + notifications.clear(); + notifications.addAll(MOCK_NOTIFICATIONS); + } + + for (ApexEmailNotification notification : notifications) { if (notification.UserId != null) { apexErrrorRecipients.add(notification.UserId); - } else { + } else if (String.isNotBlank(notification.Email) == true) { apexErrrorRecipients.addAll(notification.Email.split(';')); } } diff --git a/nebula-logger/core/main/plugin-framework/classes/LoggerSObjectHandlerPlugin.cls-meta.xml b/nebula-logger/core/main/log-management/classes/LoggerEmailSender.cls-meta.xml similarity index 100% rename from nebula-logger/core/main/plugin-framework/classes/LoggerSObjectHandlerPlugin.cls-meta.xml rename to nebula-logger/core/main/log-management/classes/LoggerEmailSender.cls-meta.xml diff --git a/nebula-logger/core/main/log-management/classes/LoggerSObjectHandler.cls b/nebula-logger/core/main/log-management/classes/LoggerSObjectHandler.cls deleted file mode 100644 index 28c303715..000000000 --- a/nebula-logger/core/main/log-management/classes/LoggerSObjectHandler.cls +++ /dev/null @@ -1,182 +0,0 @@ -//------------------------------------------------------------------------------------------------// -// This file is part of the Nebula Logger project, released under the MIT License. // -// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // -//------------------------------------------------------------------------------------------------// - -/** - * @group Log Management - * @description Abstract class used by trigger handlers for shared logic - */ -@SuppressWarnings('PMD.ApexCRUDViolation, PMD.EmptyStatementBlock') -public without sharing abstract class LoggerSObjectHandler { - private static Map> pluginsBySObjectType = new Map>(); - - @TestVisible - private TriggerOperation triggerOperationType; - @TestVisible - private List triggerNew; - @TestVisible - private Map triggerNewMap; - @TestVisible - private List triggerOld; - @TestVisible - private Map triggerOldMap; - - private List plugins; - - static { - // Query the LoggerPlugin__mdt CMDT object so the records are sorted correctly - List plugins = [ - SELECT SObjectType__r.QualifiedApiName, PluginType__c, PluginApiName__c - FROM LoggerPlugin__mdt - WHERE IsEnabled__c = TRUE - ORDER BY ExecutionOrder__c NULLS LAST, DeveloperName - ]; - - for (LoggerPlugin__mdt plugin : plugins) { - // CMDT entity-definition relationship fields are weird, so skip some headaches by copying the Qualified API name - plugin.SObjectType__c = plugin.SObjectType__r.QualifiedApiName; - - // Schema.getGlobalDescribe() is the worst, so don't use it - SObjectType sobjectType = ((SObject) Type.forName(plugin.SObjectType__c).newInstance()).getSObjectType(); - - List sobjectTypePlugins = new List(); - if (pluginsBySObjectType.containsKey(sobjectType) == true) { - sobjectTypePlugins = pluginsBySObjectType.get(sobjectType); - } - sobjectTypePlugins.add(plugin); - pluginsBySObjectType.put(sobjectType, sobjectTypePlugins); - } - - if (System.Test.isRunningTest() == true) { - // Tests shouldn't rely on the actual CMDT rules in the org - // Clear the org's loaded records during tests, and mock via setMockConfiguration() - pluginsBySObjectType.clear(); - } - } - - @TestVisible - private static void setMockPlugin(Schema.SObjectType sobjectType, LoggerPlugin__mdt plugin) { - List plugins = pluginsBySObjectType.get(sobjectType); - if (plugins == null) { - plugins = new List(); - } - plugins.add(plugin); - pluginsBySObjectType.put(sobjectType, plugins); - } - - /** - * @description Default constructor - */ - public LoggerSObjectHandler() { - this.triggerOperationType = Trigger.operationType; - this.triggerNew = Trigger.new; - this.triggerNewMap = Trigger.newMap; - this.triggerOld = Trigger.old; - this.triggerOldMap = Trigger.oldMap; - this.plugins = pluginsBySObjectType.get(this.getSObjectType()); - } - - /** - * @description Returns the SObject Type that the handler is responsible for processing - * @return The instance of `SObjectType` - */ - public abstract SObjectType getSObjectType(); - - /** - * @description Runs the handler class's logic - */ - public void execute() { - switch on this.triggerOperationType { - when BEFORE_INSERT { - this.executeBeforeInsert(this.triggerNew); - } - when BEFORE_UPDATE { - this.executeBeforeUpdate(this.triggerNewMap, this.triggerOldMap); - } - when BEFORE_DELETE { - this.executeBeforeDelete(this.triggerNewMap); - } - when AFTER_INSERT { - // Platform Events don't have an ID field, thus Trigger.newMap doesn't work for LogEntryEvent__e - // For custom objects, Map is more convenient since it provides both the keys & values - // 2 AFTER_INSERT methods are used here in the framework, with the expectation that only 1 will be implemented per handler class - this.executeAfterInsert(this.triggerNew); - this.executeAfterInsert(this.triggerNewMap); - } - when AFTER_UPDATE { - this.executeAfterUpdate(this.triggerNewMap, this.triggerOldMap); - } - when AFTER_DELETE { - this.executeAfterDelete(this.triggerNewMap); - } - when AFTER_UNDELETE { - this.executeAfterUndelete(this.triggerNewMap); - } - } - - this.executePlugins(); - } - - protected virtual void executeBeforeInsert(List triggerNew) { - } - - protected virtual void executeBeforeUpdate(Map triggerNewMap, Map triggerOldMap) { - } - - protected virtual void executeBeforeDelete(Map triggerNewMap) { - } - - // executeAfterInsert(List triggerNew) { - } - - protected virtual void executeAfterInsert(Map triggerNewMap) { - } - - protected virtual void executeAfterUpdate(Map triggerNewMap, Map triggerOldMap) { - } - - protected virtual void executeAfterDelete(Map triggerNewMap) { - } - - protected virtual void executeAfterUndelete(Map triggerNewMap) { - } - - private void executePlugins() { - if (this.plugins == null || this.plugins.isEmpty() == true) { - return; - } - - for (LoggerPlugin__mdt pluginConfiguration : this.plugins) { - switch on pluginConfiguration.PluginType__c { - when 'Apex' { - this.executeApexPlugin(pluginConfiguration.PluginApiName__c); - } - when 'Flow' { - this.executeFlowPlugin(pluginConfiguration.PluginApiName__c); - } - } - } - } - - private void executeApexPlugin(String apexClassName) { - LoggerSObjectHandlerPlugin apexPlugin = (LoggerSObjectHandlerPlugin) Type.forName(apexClassName).newInstance(); - apexPlugin.execute(this.triggerOperationType, this.triggerNew, this.triggerNewMap, this.triggerOld, this.triggerOldMap); - } - - private void executeFlowPlugin(String flowApiName) { - Map flowInputs = new Map(); - flowInputs.put('triggerOperationType', this.triggerOperationType?.name()); - flowInputs.put('triggerNew', this.triggerNew); - flowInputs.put('triggerOld', this.triggerOld); - - Flow.Interview flowPlugin = Flow.Interview.createInterview(flowApiName, flowInputs); - flowPlugin.start(); - - List updatedTriggerNew = (List) flowPlugin.getVariableValue('updatedTriggerNew'); - if (updatedTriggerNew != null && updatedTriggerNew.size() == this.triggerNew.size()) { - this.triggerNew = updatedTriggerNew; - } - } -} diff --git a/nebula-logger/core/main/log-management/classes/LoggerSObjectMetadata.cls b/nebula-logger/core/main/log-management/classes/LoggerSObjectMetadata.cls index 26dc92c89..785da5f2b 100644 --- a/nebula-logger/core/main/log-management/classes/LoggerSObjectMetadata.cls +++ b/nebula-logger/core/main/log-management/classes/LoggerSObjectMetadata.cls @@ -9,24 +9,27 @@ */ public without sharing class LoggerSObjectMetadata { /** - * @description Provides schema details about the the platform event object `LogEntryEvent__e` - * @return An instance of `LoggerSObjectMetadata.SObjectSchema` for the platform event `LogEntryEvent__e` + * @description Provides schema details about the specified `SObjectType` + * @param sobjectApiName The API name of the `SObjectType` to convert to an instance of `LoggerSObjectMetadata.SObjectSchema` + * @return An instance of `LoggerSObjectMetadata.SObjectSchema` for the specified `SObjectType` */ @AuraEnabled(cacheable=true) - public static SObjectSchema getLogEntryEventSchema() { - return buildSObjectSchema(Schema.LogEntryEvent__e.SObjectType.getDescribe()); + public static SObjectSchema getSchemaForName(String sobjectApiName) { + String namespacePrefix = getNamespacePrefix(); + String qualifiedApiName = String.isBlank(namespacePrefix) == true ? sobjectApiName : namespacePrefix + '__' + sobjectApiName; + Type apexType = Type.forName(qualifiedApiName) != null ? Type.forName(qualifiedApiName) : Type.forName(sobjectApiName); + Schema.SObjectType sobjectType = ((SObject) apexType.newInstance()).getSObjectType(); + return getSchema(sobjectType); } /** - * @description Provides schema details about the the custom settings object `LoggerSettings__c` - * @return An instance of `LoggerSObjectMetadata.SObjectSchema` for the platform event `LoggerSettings__c` + * @description Provides schema details about the specified `SObjectType` + * @param sobjectType The instance of `SObjectType` to convert to an instance of `LoggerSObjectMetadata.SObjectSchema` + * @return An instance of `LoggerSObjectMetadata.SObjectSchema` for the specified `SObjectType` */ - @AuraEnabled(cacheable=true) - public static SObjectSchema getLoggerSettingsSchema() { - return buildSObjectSchema(Schema.LoggerSettings__c.SObjectType.getDescribe()); - } + public static SObjectSchema getSchema(Schema.SObjectType sobjectType) { + Schema.DescribeSObjectResult describe = sobjectType.getDescribe(); - private static SObjectSchema buildSObjectSchema(Schema.DescribeSObjectResult describe) { SObjectSchema schema = new SObjectSchema(); schema.apiName = describe.getName(); schema.localApiName = describe.getLocalName(); @@ -53,6 +56,13 @@ public without sharing class LoggerSObjectMetadata { return schema; } + private static String getNamespacePrefix() { + String className = LoggerSObjectMetadata.class.getName(); + String namespacePrefix = className.contains('.') ? className.substringBefore('.') : ''; + + return namespacePrefix; + } + /** * @description Inner class for `SObject` details to LWCs, using `@AuraEnabled` properties */ diff --git a/nebula-logger/core/main/log-management/classes/LoggerSettingsController.cls b/nebula-logger/core/main/log-management/classes/LoggerSettingsController.cls index 24ada1915..5f4545a75 100644 --- a/nebula-logger/core/main/log-management/classes/LoggerSettingsController.cls +++ b/nebula-logger/core/main/log-management/classes/LoggerSettingsController.cls @@ -9,6 +9,17 @@ */ @SuppressWarnings('PMD.ApexCRUDViolation, PMD.CyclomaticComplexity, PMD.ExcessivePublicCount') public without sharing class LoggerSettingsController { + @TestVisible + private static final String CUSTOM_SAVE_METHOD_PREFIX = 'CustomSaveMethod'; + @TestVisible + private static final String CUSTOM_OBJECTS_STORAGE_LOCATION = 'CUSTOM_OBJECTS'; + @TestVisible + private static final String CUSTOM_LOG_PURGE_ACTION_PREFIX = 'CustomLogPurgeAction'; + @TestVisible + private static final String CUSTOM_STORAGE_LOCATION_PREFIX = 'CustomStorageLocation'; + @TestVisible + private static final String DELETE_LOG_PURGE_ACTION = 'Delete'; + // Data methods /** * @description Indicates if the current user has access to modify `LoggerSettings__c` records, @@ -29,6 +40,8 @@ public without sharing class LoggerSettingsController { public static LoggerSettingsPicklistOptions getPicklistOptions() { LoggerSettingsPicklistOptions loggerSettingsPicklistOptions = new LoggerSettingsPicklistOptions(); loggerSettingsPicklistOptions.loggingLevelOptions = getLoggingLevelOptions(); + loggerSettingsPicklistOptions.platformEventStorageLocationOptions = getPlatformEventStorageLocationOptions(); + loggerSettingsPicklistOptions.purgeActionOptions = getPurgeActionOptions(); loggerSettingsPicklistOptions.saveMethodOptions = getSaveMethodOptions(); loggerSettingsPicklistOptions.setupOwnerTypeOptions = getSetupOwnerTypeOptions(); loggerSettingsPicklistOptions.shareAccessLevelOptions = getShareAccessLevelOptions(); @@ -83,7 +96,7 @@ public without sharing class LoggerSettingsController { public static void saveRecord(LoggerSettings__c settingsRecord) { try { if (canUserModifyLoggerSettings() == true) { - upsert settingsRecord; + LoggerDataStore.getDatabase().upsertRecord(settingsRecord, Schema.LoggerSettings__c.Id); } } catch (Exception ex) { throw createAuraHandledException(ex); @@ -98,7 +111,7 @@ public without sharing class LoggerSettingsController { public static void deleteRecord(LoggerSettings__c settingsRecord) { try { if (canUserModifyLoggerSettings() == true) { - delete settingsRecord; + LoggerDataStore.getDatabase().deleteRecord(settingsRecord); } } catch (Exception ex) { throw createAuraHandledException(ex); @@ -187,12 +200,57 @@ public without sharing class LoggerSettingsController { return picklistOptions; } - private static List getSaveMethodOptions() { + private static List getPlatformEventStorageLocationOptions() { + List storageLocationNames = new List{ CUSTOM_OBJECTS_STORAGE_LOCATION }; + for (LoggerParameter__mdt matchingAdditionalParameter : LoggerParameter.matchOnPrefix(CUSTOM_STORAGE_LOCATION_PREFIX)) { + storageLocationNames.add(matchingAdditionalParameter.Value__c); + } + storageLocationNames.sort(); + + List picklistOptions = initializePicklistOptions(); + for (String storageLocationName : storageLocationNames) { + PicklistOption picklistOption = new PicklistOption(); + picklistOption.label = storageLocationName; + picklistOption.value = storageLocationName; + + picklistOptions.add(picklistOption); + } + return picklistOptions; + } + + private static List getPurgeActionOptions() { + List logPurgeActionNames = new List{ DELETE_LOG_PURGE_ACTION }; + for (LoggerParameter__mdt matchingAdditionalParameter : LoggerParameter.matchOnPrefix(CUSTOM_LOG_PURGE_ACTION_PREFIX)) { + logPurgeActionNames.add(matchingAdditionalParameter.Value__c); + } + logPurgeActionNames.sort(); + List picklistOptions = initializePicklistOptions(); + for (String logPurgeActionName : logPurgeActionNames) { + PicklistOption picklistOption = new PicklistOption(); + picklistOption.label = logPurgeActionName; + picklistOption.value = logPurgeActionName; + + picklistOptions.add(picklistOption); + } + return picklistOptions; + } + + private static List getSaveMethodOptions() { + List saveMethodNames = new List(); for (Logger.SaveMethod saveMethod : Logger.SaveMethod.values()) { + saveMethodNames.add(saveMethod.name()); + } + for (LoggerParameter__mdt matchingAdditionalParameter : LoggerParameter.matchOnPrefix(CUSTOM_SAVE_METHOD_PREFIX)) { + saveMethodNames.add(matchingAdditionalParameter.Value__c); + } + saveMethodNames.sort(); + + List picklistOptions = initializePicklistOptions(); + for (String saveMethodName : saveMethodNames) { PicklistOption picklistOption = new PicklistOption(); - picklistOption.label = saveMethod.name(); - picklistOption.value = saveMethod.name(); + picklistOption.label = saveMethodName; + picklistOption.value = saveMethodName; picklistOptions.add(picklistOption); } @@ -283,6 +341,10 @@ public without sharing class LoggerSettingsController { @AuraEnabled public List loggingLevelOptions; @AuraEnabled + public List platformEventStorageLocationOptions; + @AuraEnabled + public List purgeActionOptions; + @AuraEnabled public List saveMethodOptions; @AuraEnabled public List setupOwnerTypeOptions; diff --git a/nebula-logger/core/main/configuration/customPermissions/CanModifyLoggerSettings.customPermission-meta.xml b/nebula-logger/core/main/log-management/customPermissions/CanModifyLoggerSettings.customPermission-meta.xml similarity index 100% rename from nebula-logger/core/main/configuration/customPermissions/CanModifyLoggerSettings.customPermission-meta.xml rename to nebula-logger/core/main/log-management/customPermissions/CanModifyLoggerSettings.customPermission-meta.xml diff --git a/nebula-logger/core/main/log-management/flexipages/LogEntryRecordPage.flexipage-meta.xml b/nebula-logger/core/main/log-management/flexipages/LogEntryRecordPage.flexipage-meta.xml index 9b65875f7..fec8cef86 100644 --- a/nebula-logger/core/main/log-management/flexipages/LogEntryRecordPage.flexipage-meta.xml +++ b/nebula-logger/core/main/log-management/flexipages/LogEntryRecordPage.flexipage-meta.xml @@ -293,6 +293,16 @@ RecordDatabaseResultType__cField + + + + uiBehavior + readonly + + Record.DatabaseResultCollectionSize__c + RecordDatabaseResultCollectionSize_cField1 + + @@ -341,6 +351,16 @@ RecordRecordSObjectType__cField + + + + uiBehavior + readonly + + Record.RecordCollectionSize__c + RecordRecordCollectionSize_cField1 + + @@ -439,6 +459,142 @@ Facet-f6d04c17-cbcd-40c6-aa58-c46313ecd8c4 Facet + + + + + uiBehavior + readonly + + Record.HttpRequestEndpoint__c + RecordHttpRequestEndpoint_cField1 + + + + + + uiBehavior + readonly + + Record.HttpRequestMethod__c + RecordHttpRequestMethod_cField1 + + + + + + uiBehavior + readonly + + Record.HttpRequestCompressed__c + RecordHttpRequestCompressed_cField1 + + + + + + uiBehavior + readonly + + Record.HttpRequestBody__c + RecordHttpRequestBody_cField1 + + + + + + uiBehavior + readonly + + Record.HttpRequestBodyMasked__c + RecordHttpRequestBodyMasked_cField1 + + + Facet-4cea44fd-c4f1-41ed-bada-eace6229f158 + Facet + + + + + + body + Facet-4cea44fd-c4f1-41ed-bada-eace6229f158 + + flexipage:column + flexipage_column1 + + + Facet-25eaa065-25af-4efc-9ce5-9d289a0fc3f0 + Facet + + + + + + uiBehavior + readonly + + Record.HttpResponseStatusCode__c + RecordHttpResponseStatusCode_cField1 + + + + + + uiBehavior + readonly + + Record.HttpResponseStatus__c + RecordHttpResponseStatus_cField1 + + + + + + uiBehavior + readonly + + Record.HttpResponseHeaderKeys__c + RecordHttpResponseHeaderKeys_cField1 + + + + + + uiBehavior + readonly + + Record.HttpResponseBody__c + RecordHttpResponseBody_cField1 + + + + + + uiBehavior + readonly + + Record.HttpResponseBodyMasked__c + RecordHttpResponseBodyMasked_cField1 + + + Facet-1f2467a3-2a30-4aad-ace3-80afc0a517d2 + Facet + + + + + + body + Facet-1f2467a3-2a30-4aad-ace3-80afc0a517d2 + + flexipage:column + flexipage_column15 + + + Facet-6395ceae-5694-468a-911f-714456910736 + Facet + @@ -537,6 +693,46 @@ + + + + columns + Facet-25eaa065-25af-4efc-9ce5-9d289a0fc3f0 + + + label + HTTP Request + + flexipage:fieldSection + flexipage_fieldSection1 + + + {!Record.HttpRequestEndpoint__c} + NE + + + + + + + + columns + Facet-6395ceae-5694-468a-911f-714456910736 + + + label + HTTP Response + + flexipage:fieldSection + flexipage_fieldSection10 + + + {!Record.HttpResponseStatus__c} + NE + + + + Facet-7beef2bc-28d3-490f-96b8-7a8f85424802 Facet diff --git a/nebula-logger/core/main/log-management/flexipages/LogRecordPage.flexipage-meta.xml b/nebula-logger/core/main/log-management/flexipages/LogRecordPage.flexipage-meta.xml index 974483a16..f5c97a038 100644 --- a/nebula-logger/core/main/log-management/flexipages/LogRecordPage.flexipage-meta.xml +++ b/nebula-logger/core/main/log-management/flexipages/LogRecordPage.flexipage-meta.xml @@ -324,6 +324,16 @@ RecordLogRetentionDate__cField + + + + uiBehavior + readonly + + Record.LogPurgeAction__c + RecordLogPurgeAction_cField1 + + Facet-0d174e01-17f8-4c93-8f5a-8983346600f8 Facet diff --git a/nebula-logger/core/main/log-management/layouts/LogEntry__c-Log Entry Layout.layout-meta.xml b/nebula-logger/core/main/log-management/layouts/LogEntry__c-Log Entry Layout.layout-meta.xml index 80497e3e1..af7eae2f0 100644 --- a/nebula-logger/core/main/log-management/layouts/LogEntry__c-Log Entry Layout.layout-meta.xml +++ b/nebula-logger/core/main/log-management/layouts/LogEntry__c-Log Entry Layout.layout-meta.xml @@ -235,6 +235,10 @@ Readonly DatabaseResultType__c + + Edit + DatabaseResultCollectionSize__c + Readonly DatabaseResultJson__c @@ -256,6 +260,10 @@ Readonly RecordSObjectType__c + + Readonly + RecordCollectionSize__c + Readonly RecordId__c @@ -283,6 +291,56 @@ + + true + true + true + + + + Readonly + HttpRequestEndpoint__c + + + Readonly + HttpRequestMethod__c + + + Readonly + HttpRequestCompressed__c + + + Readonly + HttpRequestBody__c + + + + + + true + true + true + + + + Readonly + HttpResponseStatusCode__c + + + Readonly + HttpResponseStatus__c + + + Readonly + HttpResponseHeaderKeys__c + + + Readonly + HttpResponseBody__c + + + + true true @@ -397,7 +455,7 @@ false false - 00h1h000002oBf9 + 00h1k000003yap8 4 0 Default diff --git a/nebula-logger/core/main/log-management/layouts/Log__c-Log Layout.layout-meta.xml b/nebula-logger/core/main/log-management/layouts/Log__c-Log Layout.layout-meta.xml index 161423505..47c5814bb 100644 --- a/nebula-logger/core/main/log-management/layouts/Log__c-Log Layout.layout-meta.xml +++ b/nebula-logger/core/main/log-management/layouts/Log__c-Log Layout.layout-meta.xml @@ -100,6 +100,10 @@ Readonly LogRetentionDate__c + + Readonly + LogPurgeAction__c + @@ -385,7 +389,7 @@ false false - 00h1F000005MrCM + 00h1F000006uWJf 4 0 Default diff --git a/nebula-logger/core/main/log-management/lwc/logEntryEventStream/__tests__/data/getLogEntryEventSchema.json b/nebula-logger/core/main/log-management/lwc/logEntryEventStream/__tests__/data/getSchemaForName.json similarity index 100% rename from nebula-logger/core/main/log-management/lwc/logEntryEventStream/__tests__/data/getLogEntryEventSchema.json rename to nebula-logger/core/main/log-management/lwc/logEntryEventStream/__tests__/data/getSchemaForName.json diff --git a/nebula-logger/core/main/log-management/lwc/logEntryEventStream/__tests__/logEntryEventStream.test.js b/nebula-logger/core/main/log-management/lwc/logEntryEventStream/__tests__/logEntryEventStream.test.js index 1dff298ab..7c4369e7d 100644 --- a/nebula-logger/core/main/log-management/lwc/logEntryEventStream/__tests__/logEntryEventStream.test.js +++ b/nebula-logger/core/main/log-management/lwc/logEntryEventStream/__tests__/logEntryEventStream.test.js @@ -1,7 +1,7 @@ import { createElement } from 'lwc'; import LogEntryEventStream from 'c/logEntryEventStream'; import { jestMockPublish } from 'lightning/empApi'; -import getLogEntryEventSchema from '@salesforce/apex/LoggerSObjectMetadata.getLogEntryEventSchema'; +import getSchemaForName from '@salesforce/apex/LoggerSObjectMetadata.getSchemaForName'; const loggingLevels = { FINEST: 2, @@ -25,10 +25,10 @@ const mockLogEntryEventTemplate = { TransactionEntryNumber__c: 1 }; -const mockLogEntryEventSchemaTemplate = require('./data/getLogEntryEventSchema.json'); +const mockLogEntryEventSchemaTemplate = require('./data/getSchemaForName.json'); jest.mock( - '@salesforce/apex/LoggerSObjectMetadata.getLogEntryEventSchema', + '@salesforce/apex/LoggerSObjectMetadata.getSchemaForName', () => { return { default: jest.fn() @@ -39,7 +39,7 @@ jest.mock( async function createStreamElement(namespace) { const mockLogEntryEventSchema = generateLogEntryEventSchema(namespace); - getLogEntryEventSchema.mockResolvedValue(mockLogEntryEventSchema); + getSchemaForName.mockResolvedValue(mockLogEntryEventSchema); const element = createElement('log-entry-event-stream', { is: LogEntryEventStream }); @@ -210,7 +210,7 @@ describe('LogEntryEventStream tests', () => { ); }); it('includes matching log entry event for origin type filter', async () => { - getLogEntryEventSchema.mockResolvedValue(mockLogEntryEventSchemaTemplate); + getSchemaForName.mockResolvedValue(mockLogEntryEventSchemaTemplate); const element = createElement('log-entry-event-stream', { is: LogEntryEventStream @@ -235,7 +235,7 @@ describe('LogEntryEventStream tests', () => { expect(eventStreamDiv.textContent).toBe(expectedStreamText); }); it('excludes non-matching log entry event for origin type filter', async () => { - getLogEntryEventSchema.mockResolvedValue(mockLogEntryEventSchemaTemplate); + getSchemaForName.mockResolvedValue(mockLogEntryEventSchemaTemplate); const element = createElement('log-entry-event-stream', { is: LogEntryEventStream @@ -259,7 +259,7 @@ describe('LogEntryEventStream tests', () => { expect(eventStreamDiv.textContent).toBeFalsy(); }); it('includes matching log entry event for origin location filter', async () => { - getLogEntryEventSchema.mockResolvedValue(mockLogEntryEventSchemaTemplate); + getSchemaForName.mockResolvedValue(mockLogEntryEventSchemaTemplate); const element = createElement('log-entry-event-stream', { is: LogEntryEventStream @@ -284,7 +284,7 @@ describe('LogEntryEventStream tests', () => { expect(eventStreamDiv.textContent).toBe(expectedStreamText); }); it('excludes non-matching log entry event for origin location filter', async () => { - getLogEntryEventSchema.mockResolvedValue(mockLogEntryEventSchemaTemplate); + getSchemaForName.mockResolvedValue(mockLogEntryEventSchemaTemplate); const element = createElement('log-entry-event-stream', { is: LogEntryEventStream @@ -308,7 +308,7 @@ describe('LogEntryEventStream tests', () => { expect(eventStreamDiv.textContent).toBeFalsy(); }); it('includes matching log entry event for logged by filter', async () => { - getLogEntryEventSchema.mockResolvedValue(mockLogEntryEventSchemaTemplate); + getSchemaForName.mockResolvedValue(mockLogEntryEventSchemaTemplate); const element = createElement('log-entry-event-stream', { is: LogEntryEventStream @@ -333,7 +333,7 @@ describe('LogEntryEventStream tests', () => { expect(eventStreamDiv.textContent).toBe(expectedStreamText); }); it('excludes non-matching log entry event for logged by filter', async () => { - getLogEntryEventSchema.mockResolvedValue(mockLogEntryEventSchemaTemplate); + getSchemaForName.mockResolvedValue(mockLogEntryEventSchemaTemplate); const element = createElement('log-entry-event-stream', { is: LogEntryEventStream @@ -357,7 +357,7 @@ describe('LogEntryEventStream tests', () => { expect(eventStreamDiv.textContent).toBeFalsy(); }); it('includes matching log entry event using string for message filter', async () => { - getLogEntryEventSchema.mockResolvedValue(mockLogEntryEventSchemaTemplate); + getSchemaForName.mockResolvedValue(mockLogEntryEventSchemaTemplate); const element = createElement('log-entry-event-stream', { is: LogEntryEventStream @@ -382,7 +382,7 @@ describe('LogEntryEventStream tests', () => { expect(eventStreamDiv.textContent).toBe(expectedStreamText); }); it('excludes non-matching log entry event for message filter', async () => { - getLogEntryEventSchema.mockResolvedValue(mockLogEntryEventSchemaTemplate); + getSchemaForName.mockResolvedValue(mockLogEntryEventSchemaTemplate); const element = createElement('log-entry-event-stream', { is: LogEntryEventStream @@ -407,7 +407,7 @@ describe('LogEntryEventStream tests', () => { }); it('includes matching log entry event using regex for message filter', async () => { - getLogEntryEventSchema.mockResolvedValue(mockLogEntryEventSchemaTemplate); + getSchemaForName.mockResolvedValue(mockLogEntryEventSchemaTemplate); const element = createElement('log-entry-event-stream', { is: LogEntryEventStream diff --git a/nebula-logger/core/main/log-management/lwc/logEntryEventStream/logEntryEventStream.js b/nebula-logger/core/main/log-management/lwc/logEntryEventStream/logEntryEventStream.js index 5ee6adb6e..272b3aa56 100644 --- a/nebula-logger/core/main/log-management/lwc/logEntryEventStream/logEntryEventStream.js +++ b/nebula-logger/core/main/log-management/lwc/logEntryEventStream/logEntryEventStream.js @@ -5,7 +5,7 @@ import { LightningElement } from 'lwc'; import { subscribe, unsubscribe } from 'lightning/empApi'; -import getLogEntryEventSchema from '@salesforce/apex/LoggerSObjectMetadata.getLogEntryEventSchema'; +import getSchemaForName from '@salesforce/apex/LoggerSObjectMetadata.getSchemaForName'; export default class LogEntryEventStream extends LightningElement { unfilteredEvents = []; @@ -29,7 +29,7 @@ export default class LogEntryEventStream extends LightningElement { async connectedCallback() { document.title = 'Log Entry Event Stream'; - getLogEntryEventSchema().then(result => { + getSchemaForName({ sobjectApiName: 'LogEntryEvent__e' }).then(result => { this._logEntryEventSchema = result; this._channel = '/event/' + this._logEntryEventSchema.apiName; diff --git a/nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/data/getObjectInfo.json b/nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/data/getObjectInfo.json deleted file mode 100644 index 864becc9d..000000000 --- a/nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/data/getObjectInfo.json +++ /dev/null @@ -1,822 +0,0 @@ -{ - "apiName": "LoggerSettings__c", - "associateEntityType": null, - "associateParentEntity": null, - "childRelationships": [ - { - "childObjectApiName": "AttachedContentDocument", - "fieldName": "LinkedEntityId", - "junctionIdListNames": [], - "junctionReferenceTo": [], - "relationshipName": "AttachedContentDocuments" - }, - { - "childObjectApiName": "CollaborationGroupRecord", - "fieldName": "RecordId", - "junctionIdListNames": [], - "junctionReferenceTo": [], - "relationshipName": "RecordAssociatedGroups" - }, - { - "childObjectApiName": "CombinedAttachment", - "fieldName": "ParentId", - "junctionIdListNames": [], - "junctionReferenceTo": [], - "relationshipName": "CombinedAttachments" - }, - { - "childObjectApiName": "ContactRequest", - "fieldName": "WhatId", - "junctionIdListNames": [], - "junctionReferenceTo": [], - "relationshipName": "ContactRequests" - }, - { - "childObjectApiName": "ContentDocumentLink", - "fieldName": "LinkedEntityId", - "junctionIdListNames": [], - "junctionReferenceTo": [], - "relationshipName": "ContentDocumentLinks" - }, - { - "childObjectApiName": "DuplicateRecordItem", - "fieldName": "RecordId", - "junctionIdListNames": [], - "junctionReferenceTo": [], - "relationshipName": "DuplicateRecordItems" - }, - { - "childObjectApiName": "EntitySubscription", - "fieldName": "ParentId", - "junctionIdListNames": [], - "junctionReferenceTo": [], - "relationshipName": "FeedSubscriptionsForEntity" - }, - { - "childObjectApiName": "NetworkActivityAudit", - "fieldName": "ParentEntityId", - "junctionIdListNames": [], - "junctionReferenceTo": [], - "relationshipName": "ParentEntities" - }, - { - "childObjectApiName": "NetworkUserHistoryRecent", - "fieldName": "RecordId", - "junctionIdListNames": [], - "junctionReferenceTo": [], - "relationshipName": "NetworkUserHistoryRecentToRecord" - }, - { - "childObjectApiName": "ProcessException", - "fieldName": "AttachedToId", - "junctionIdListNames": [], - "junctionReferenceTo": [], - "relationshipName": "ProcessExceptions" - }, - { - "childObjectApiName": "ProcessInstance", - "fieldName": "TargetObjectId", - "junctionIdListNames": [], - "junctionReferenceTo": [], - "relationshipName": "ProcessInstances" - }, - { - "childObjectApiName": "ProcessInstanceHistory", - "fieldName": "TargetObjectId", - "junctionIdListNames": [], - "junctionReferenceTo": [], - "relationshipName": "ProcessSteps" - }, - { - "childObjectApiName": "RecordAction", - "fieldName": "RecordId", - "junctionIdListNames": [], - "junctionReferenceTo": [], - "relationshipName": "RecordActions" - }, - { - "childObjectApiName": "RecordActionHistory", - "fieldName": "ParentRecordId", - "junctionIdListNames": [], - "junctionReferenceTo": [], - "relationshipName": "RecordActionHistories" - }, - { - "childObjectApiName": "TopicAssignment", - "fieldName": "EntityId", - "junctionIdListNames": [], - "junctionReferenceTo": [], - "relationshipName": "TopicAssignments" - } - ], - "createable": true, - "custom": true, - "defaultRecordTypeId": "012000000000000AAA", - "deletable": true, - "dependentFields": {}, - "feedEnabled": false, - "fields": { - "CloneSourceId": { - "apiName": "CloneSourceId", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": false, - "custom": false, - "dataType": "Reference", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": null, - "label": "Clone Source", - "length": 18, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": true, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": false, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": false - }, - "CreatedById": { - "apiName": "CreatedById", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": false, - "custom": false, - "dataType": "Reference", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": null, - "label": "Created By ID", - "length": 18, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": true, - "referenceTargetField": null, - "referenceToInfos": [ - { - "apiName": "User", - "nameFields": ["FirstName", "LastName", "Name"] - } - ], - "relationshipName": "CreatedBy", - "required": true, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": false - }, - "CreatedDate": { - "apiName": "CreatedDate", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": false, - "custom": false, - "dataType": "DateTime", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": null, - "label": "Created Date", - "length": 0, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": true, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": false - }, - "DefaultLogShareAccessLevel__c": { - "apiName": "DefaultLogShareAccessLevel__c", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": true, - "custom": true, - "dataType": "String", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": "Uses Apex managed sharing to grants users read or edit access to their log records (on insert only). When no access level is specified, no Apex sharing logic is executed. This only gives record-level access - users will still need to be granted access to the Log__c object using permission sets or profiles.\n\nPossible Values:\n(blank)\nRead\nEdit", - "label": "Log Access Level", - "length": 255, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": false, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": true - }, - "DefaultNumberOfDaysToRetainLogs__c": { - "apiName": "DefaultNumberOfDaysToRetainLogs__c", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": true, - "custom": true, - "dataType": "Double", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": "This value is used to set the field Log__c.LogRetentionDate__c, which is then used by LogBatchPurger to delete old logs. To keep logs indefinitely, set this field to blank (null).", - "label": "Days to Retain Logs", - "length": 0, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 4, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": false, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": true - }, - "DefaultSaveMethod__c": { - "apiName": "DefaultSaveMethod__c", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": true, - "custom": true, - "dataType": "String", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": "Defaults to 'EVENT_BUS'. This controls the default save method used by Logger when calling saveLog().\n\nPossible values:\nEVENT_BUS\nQUEUEABLE\nREST\nSYNCHRONOUS_DML", - "label": "Save Method", - "length": 255, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": true, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": true - }, - "Id": { - "apiName": "Id", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": false, - "custom": false, - "dataType": "String", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": null, - "label": "Record ID", - "length": 18, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": true, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": false - }, - "IsAnonymousModeEnabled__c": { - "apiName": "IsAnonymousModeEnabled__c", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": true, - "custom": true, - "dataType": "Boolean", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": "When enabled, any logs generated will not have any user-specific details set - any fields related to the User, Profile, etc. will be null.\n\nNote: this feature only works properly when using the save method EVENT_BUS.", - "label": "Enable Anonymous Mode", - "length": 0, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": true, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": true - }, - "IsApexSystemDebugLoggingEnabled__c": { - "apiName": "IsApexSystemDebugLoggingEnabled__c", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": true, - "custom": true, - "dataType": "Boolean", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": "When enabled, Logger will automatically call Apex's System.debug(). To help with performance, this option should be disabled in production unless you are actively troubleshooting an issue.", - "label": "Enable Apex System.debug()", - "length": 0, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": true, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": true - }, - "IsJavaScriptConsoleLoggingEnabled__c": { - "apiName": "IsJavaScriptConsoleLoggingEnabled__c", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": true, - "custom": true, - "dataType": "Boolean", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": "When enabled, Logger will automatically call the browser's console.log() function when logging via lightning components. To help with performance, this option should be disabled in production unless you are actively troubleshooting an issue.", - "label": "Enable JavaScript console.log()", - "length": 0, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": true, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": true - }, - "IsDataMaskingEnabled__c": { - "apiName": "IsDataMaskingEnabled__c", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": true, - "custom": true, - "dataType": "Boolean", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": "When enabled, any data-mask rules (configured in LogEntryDataMaskRule__mdt) will be automatically applied to log entry messages.", - "label": "Enable Data Masking", - "length": 0, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": true, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": true - }, - "IsDeleted": { - "apiName": "IsDeleted", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": false, - "custom": false, - "dataType": "Boolean", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": null, - "label": "Deleted", - "length": 0, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": true, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": false - }, - "IsEnabled__c": { - "apiName": "IsEnabled__c", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": true, - "custom": true, - "dataType": "Boolean", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": "Controls if Logger is enabled for the specified level (organization, profile, or user)", - "label": "Enabled", - "length": 0, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": true, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": true - }, - "LastModifiedById": { - "apiName": "LastModifiedById", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": false, - "custom": false, - "dataType": "Reference", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": null, - "label": "Last Modified By ID", - "length": 18, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": true, - "referenceTargetField": null, - "referenceToInfos": [ - { - "apiName": "User", - "nameFields": ["FirstName", "LastName", "Name"] - } - ], - "relationshipName": "LastModifiedBy", - "required": true, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": false - }, - "LastModifiedDate": { - "apiName": "LastModifiedDate", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": false, - "custom": false, - "dataType": "DateTime", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": null, - "label": "Last Modified Date", - "length": 0, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": true, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": false - }, - "LoggingLevel__c": { - "apiName": "LoggingLevel__c", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": true, - "custom": true, - "dataType": "String", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": "Possible values:\nERROR\nWARN\nINFO\nDEBUG\nFINE\nFINER\nFINEST", - "label": "Logging Level", - "length": 255, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": true, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": true - }, - "Name": { - "apiName": "Name", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": true, - "custom": false, - "dataType": "String", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": null, - "label": "Name", - "length": 80, - "nameField": true, - "polymorphicForeignKey": false, - "precision": 0, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": false, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": true - }, - "SetupOwnerId": { - "apiName": "SetupOwnerId", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": true, - "custom": false, - "dataType": "Reference", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": null, - "label": "Location", - "length": 18, - "nameField": false, - "polymorphicForeignKey": true, - "precision": 0, - "reference": true, - "referenceTargetField": null, - "referenceToInfos": [ - { - "apiName": "Organization", - "nameFields": ["Name"] - }, - { - "apiName": "Profile", - "nameFields": ["Name"] - }, - { - "apiName": "User", - "nameFields": ["FirstName", "LastName", "Name"] - } - ], - "relationshipName": "SetupOwner", - "required": false, - "scale": 0, - "searchPrefilterable": true, - "sortable": true, - "unique": false, - "updateable": true - }, - "StripInaccessibleRecordFields__c": { - "apiName": "StripInaccessibleRecordFields__c", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": true, - "custom": true, - "dataType": "Boolean", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": "When enabled, any time an SObject record is logged, only fields that the current user can access will be included in the record's JSON.", - "label": "Strip Inaccessible Record Fields", - "length": 0, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": true, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": true - }, - "SystemModstamp": { - "apiName": "SystemModstamp", - "calculated": false, - "compound": false, - "compoundComponentName": null, - "compoundFieldName": null, - "controllerName": null, - "controllingFields": [], - "createable": false, - "custom": false, - "dataType": "DateTime", - "extraTypeInfo": null, - "filterable": true, - "filteredLookupInfo": null, - "highScaleNumber": false, - "htmlFormatted": false, - "inlineHelpText": null, - "label": "System Modstamp", - "length": 0, - "nameField": false, - "polymorphicForeignKey": false, - "precision": 0, - "reference": false, - "referenceTargetField": null, - "referenceToInfos": [], - "relationshipName": null, - "required": true, - "scale": 0, - "searchPrefilterable": false, - "sortable": true, - "unique": false, - "updateable": false - } - }, - "keyPrefix": "a03", - "label": "Logger Settings", - "labelPlural": "Logger Settings", - "layoutable": true, - "mruEnabled": false, - "nameFields": ["Name"], - "queryable": true, - "recordTypeInfos": { - "012000000000000AAA": { - "available": true, - "defaultRecordTypeMapping": true, - "master": true, - "name": "Master", - "recordTypeId": "012000000000000AAA" - } - }, - "searchable": true, - "themeInfo": null, - "updateable": true -} diff --git a/nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/data/getPicklistOptions.json b/nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/data/getPicklistOptions.json index c27a0c97d..3c2608b42 100644 --- a/nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/data/getPicklistOptions.json +++ b/nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/data/getPicklistOptions.json @@ -9,6 +9,14 @@ { "value": "FINER", "label": "FINER" }, { "value": "FINEST", "label": "FINEST" } ], + "platformEventStorageLocationOptions": [ + { "value": "", "label": "--None--" }, + { "value": "CUSTOM_OBJECTS", "label": "CUSTOM_OBJECTS" } + ], + "purgeActionOptions": [ + { "value": "", "label": "--None--" }, + { "value": "Delete", "label": "Delete" } + ], "saveMethodOptions": [ { "value": "", "label": "--None--" }, { "value": "EVENT_BUS", "label": "EVENT_BUS" }, diff --git a/nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/data/getLoggerSettingsSchema.json b/nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/data/getSchemaForName.json similarity index 93% rename from nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/data/getLoggerSettingsSchema.json rename to nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/data/getSchemaForName.json index b6512d296..ef46c0729 100644 --- a/nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/data/getLoggerSettingsSchema.json +++ b/nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/data/getSchemaForName.json @@ -76,6 +76,13 @@ "localApiName": "DefaultNumberOfDaysToRetainLogs__c", "type": "Double" }, + "DefaultPlatformEventStorageLocation__c": { + "apiName": "DefaultPlatformEventStorageLocation__c", + "inlineHelpText": "Defaults to CUSTOM_OBJECTS. This controls the default location where LogEntryEvent__e records are stored - when null, LogEntryEvent__e records will not be stored.", + "label": "Platform Event Storage Location", + "localApiName": "DefaultPlatformEventStorageLocation__c", + "type": "string" + }, "DefaultSaveMethod__c": { "apiName": "DefaultSaveMethod__c", "inlineHelpText": "Defaults to EVENT_BUS. This controls the default save method used by Logger when calling saveLog(). In most situations, EVENT_BUS should be used.", @@ -118,13 +125,6 @@ "localApiName": "IsJavaScriptConsoleLoggingEnabled__c", "type": "Boolean" }, - "IsPlatformEventStorageEnabled__c": { - "apiName": "IsPlatformEventStorageEnabled__c", - "inlineHelpText": "Controls if LogEntryEvent__e platform events are transformed & stored in the custom objects Log__c and LogEntry__c (when IsSavingEnabled__c == true).", - "label": "Store Platform Events", - "localApiName": "IsPlatformEventStorageEnabled__c", - "type": "Boolean" - }, "IsRecordFieldStrippingEnabled__c": { "apiName": "IsRecordFieldStrippingEnabled__c", "inlineHelpText": "When enabled, any time an SObject record is logged, only fields that the current user can access will be included in the record's JSON.", diff --git a/nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/loggerSettings.test.js b/nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/loggerSettings.test.js index ddd4453db..30d0df456 100644 --- a/nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/loggerSettings.test.js +++ b/nebula-logger/core/main/log-management/lwc/loggerSettings/__tests__/loggerSettings.test.js @@ -4,7 +4,7 @@ import LoggerSettings from 'c/loggerSettings'; // LoggerSettings__c metadata import canUserModifyLoggerSettings from '@salesforce/apex/LoggerSettingsController.canUserModifyLoggerSettings'; -import getLoggerSettingsSchema from '@salesforce/apex/LoggerSObjectMetadata.getLoggerSettingsSchema'; +import getSchemaForName from '@salesforce/apex/LoggerSObjectMetadata.getSchemaForName'; import getPicklistOptions from '@salesforce/apex/LoggerSettingsController.getPicklistOptions'; import getOrganization from '@salesforce/apex/LoggerSettingsController.getOrganization'; import searchForSetupOwner from '@salesforce/apex/LoggerSettingsController.searchForSetupOwner'; @@ -16,7 +16,7 @@ import saveRecord from '@salesforce/apex/LoggerSettingsController.saveRecord'; import deleteRecord from '@salesforce/apex/LoggerSettingsController.deleteRecord'; // Mock metadata -const mockLoggerSettingsSchema = require('./data/getLoggerSettingsSchema.json'); +const mockLoggerSettingsSchema = require('./data/getSchemaForName.json'); const mockOrganization = require('./data/getOrganization.json'); const mockPicklistOptions = require('./data/getPicklistOptions.json'); @@ -106,7 +106,7 @@ jest.mock( ); jest.mock( - '@salesforce/apex/LoggerSObjectMetadata.getLoggerSettingsSchema', + '@salesforce/apex/LoggerSObjectMetadata.getSchemaForName', () => { return { default: jest.fn() @@ -118,7 +118,7 @@ jest.mock( async function initializeElement(enableModifyAccess) { // Assign mock values for resolved Apex promises canUserModifyLoggerSettings.mockResolvedValue(enableModifyAccess); - getLoggerSettingsSchema.mockResolvedValue(mockLoggerSettingsSchema); + getSchemaForName.mockResolvedValue(mockLoggerSettingsSchema); getPicklistOptions.mockResolvedValue(mockPicklistOptions); getRecords.mockResolvedValue(mockRecords); @@ -165,7 +165,7 @@ describe('Logger Settings lwc tests', () => { // Verify the expected Apex/framework calls expect(canUserModifyLoggerSettings).toHaveBeenCalledTimes(1); - expect(getLoggerSettingsSchema).toHaveBeenCalledTimes(1); + expect(getSchemaForName).toHaveBeenCalledTimes(1); expect(getPicklistOptions).toHaveBeenCalledTimes(1); expect(getRecords).toHaveBeenCalledTimes(1); expect(createRecord).toHaveBeenCalledTimes(0); diff --git a/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettings.js b/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettings.js index 1d6a48835..0763535a7 100644 --- a/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettings.js +++ b/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettings.js @@ -10,7 +10,7 @@ import { ShowToastEvent } from 'lightning/platformShowToastEvent'; // LoggerSettings__c metadata import { generatePageLayout } from './loggerSettingsPageLayout'; import canUserModifyLoggerSettings from '@salesforce/apex/LoggerSettingsController.canUserModifyLoggerSettings'; -import getLoggerSettingsSchema from '@salesforce/apex/LoggerSObjectMetadata.getLoggerSettingsSchema'; +import getSchemaForName from '@salesforce/apex/LoggerSObjectMetadata.getSchemaForName'; import getPicklistOptions from '@salesforce/apex/LoggerSettingsController.getPicklistOptions'; import getOrganization from '@salesforce/apex/LoggerSettingsController.getOrganization'; import searchForSetupOwner from '@salesforce/apex/LoggerSettingsController.searchForSetupOwner'; @@ -50,7 +50,7 @@ export default class LoggerSettings extends LightningElement { connectedCallback() { document.title = this.title; this.showLoadingSpinner = true; - Promise.all([getOrganization(), getLoggerSettingsSchema(), getPicklistOptions(), canUserModifyLoggerSettings()]) + Promise.all([getOrganization(), getSchemaForName({ sobjectApiName: 'LoggerSettings__c' }), getPicklistOptions(), canUserModifyLoggerSettings()]) .then(([organizationRecordResult, loggerSettingsSchemaResult, apexPicklistOptionsResult, canUserModifyLoggerSettingsResult]) => { this.organization = organizationRecordResult; this._loggerSettingsSchema = loggerSettingsSchemaResult; @@ -118,22 +118,6 @@ export default class LoggerSettings extends LightningElement { ? event.target.checked : event.target.value; this._currentRecord[fieldApiName] = fieldValue; - if (fieldValue && fieldApiName === this._loggerSettingsSchema.fields.IsSavingEnabled__c.localApiName) { - const storageEnabledCheckbox = this.template.querySelector( - `[data-id="${this._loggerSettingsSchema.fields.IsPlatformEventStorageEnabled__c.localApiName}"]` - ); - if (storageEnabledCheckbox) { - storageEnabledCheckbox.checked = true; - } - this.handleFieldChange({ - target: { - type: 'checkbox', - checked: true, - dataset: { id: this._loggerSettingsSchema.fields.IsPlatformEventStorageEnabled__c.localApiName } - } - }); - } - this._setIsNewOrganizationRecord(); this._setShowSetupOwnerLookup(); } @@ -335,7 +319,7 @@ export default class LoggerSettings extends LightningElement { 'LoggingLevel__c', 'IsSavingEnabled__c', 'DefaultSaveMethod__c', - 'IsPlatformEventStorageEnabled__c', + 'DefaultPlatformEventStorageLocation__c', 'DefaultNumberOfDaysToRetainLogs__c', 'DefaultLogOwner__c' ]; diff --git a/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettingsPageLayout.js b/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettingsPageLayout.js index c88baf4da..2675c3e2d 100644 --- a/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettingsPageLayout.js +++ b/nebula-logger/core/main/log-management/lwc/loggerSettings/loggerSettingsPageLayout.js @@ -13,7 +13,7 @@ const PAGE_LAYOUT_CONFIG = { showInEditMode: true, columns: [ { - fieldApiNames: ['IsSavingEnabled__c', 'DefaultSaveMethod__c', 'IsPlatformEventStorageEnabled__c'], + fieldApiNames: ['IsSavingEnabled__c', 'DefaultSaveMethod__c', 'DefaultPlatformEventStorageLocation__c'], size: 6 }, { @@ -41,8 +41,8 @@ const PAGE_LAYOUT_CONFIG = { showInReadOnlyMode: true, showInEditMode: true, columns: [ - { fieldApiNames: ['DefaultNumberOfDaysToRetainLogs__c', 'DefaultLogScenario__c'], size: 6 }, - { fieldApiNames: ['DefaultLogShareAccessLevel__c', 'DefaultLogOwner__c'], size: 6 } + { fieldApiNames: ['DefaultNumberOfDaysToRetainLogs__c', 'DefaultLogPurgeAction__c'], size: 6 }, + { fieldApiNames: ['DefaultLogScenario__c', 'DefaultLogShareAccessLevel__c', 'DefaultLogOwner__c'], size: 6 } ] } ] @@ -59,6 +59,8 @@ const LoggerSettingsPageLayout = class { // TODO - long term, this feels like the wrong place for this mapping to live, but it'll live here for now const picklistOptions = { LoggingLevel__c: apexPicklistOptions.loggingLevelOptions, + DefaultLogPurgeAction__c: apexPicklistOptions.purgeActionOptions, + DefaultPlatformEventStorageLocation__c: apexPicklistOptions.platformEventStorageLocationOptions, DefaultSaveMethod__c: apexPicklistOptions.saveMethodOptions, DefaultLogShareAccessLevel__c: apexPicklistOptions.shareAccessLevelOptions }; diff --git a/nebula-logger/core/main/log-management/lwc/relatedLogEntries/__tests__/relatedLogEntries.test.js b/nebula-logger/core/main/log-management/lwc/relatedLogEntries/__tests__/relatedLogEntries.test.js index be3658acd..bdad494e7 100644 --- a/nebula-logger/core/main/log-management/lwc/relatedLogEntries/__tests__/relatedLogEntries.test.js +++ b/nebula-logger/core/main/log-management/lwc/relatedLogEntries/__tests__/relatedLogEntries.test.js @@ -29,6 +29,7 @@ describe('Related Log Entries lwc tests', () => { while (document.body.firstChild) { document.body.removeChild(document.body.firstChild); } + jest.clearAllMocks(); }); it('sets query result', async () => { diff --git a/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogEntryOrigin__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogEntryOrigin__c.field-meta.xml index 78c2f66c6..98d394fce 100644 --- a/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogEntryOrigin__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogEntryOrigin__c.field-meta.xml @@ -1,11 +1,13 @@ LogEntryOrigin__c + Active false LogEntry__r.Origin__c BlankAsZero false + Confidential false false Text diff --git a/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogEntryTimestamp__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogEntryTimestamp__c.field-meta.xml index 5d0cf619c..e39d27809 100644 --- a/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogEntryTimestamp__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogEntryTimestamp__c.field-meta.xml @@ -1,11 +1,13 @@ LogEntryTimestamp__c + Active false LogEntry__r.Timestamp__c BlankAsZero false + Confidential false false DateTime diff --git a/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogEntry__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogEntry__c.field-meta.xml index 9647cd674..b0f1225e0 100644 --- a/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogEntry__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogEntry__c.field-meta.xml @@ -1,6 +1,7 @@ LogEntry__c + Active false LogEntry__c @@ -8,6 +9,7 @@ LogEntryTags 0 false + Confidential true false false diff --git a/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogLink__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogLink__c.field-meta.xml index 1a8e66b7d..9459bcfe4 100644 --- a/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogLink__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LogLink__c.field-meta.xml @@ -1,6 +1,7 @@ LogLink__c + Active false HYPERLINK( LogEntry__r.Log__c, @@ -10,6 +11,7 @@ BlankAsZero false + Confidential false false Text diff --git a/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LoggedByUsernameLink__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LoggedByUsernameLink__c.field-meta.xml index ca4a91e7a..5ccff53fd 100644 --- a/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LoggedByUsernameLink__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/LoggedByUsernameLink__c.field-meta.xml @@ -1,11 +1,14 @@ LoggedByUsernameLink__c + Active + PII false LogEntry__r.LoggedByUsernameLink__c BlankAsZero false + Confidential false false Text diff --git a/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/Tag__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/Tag__c.field-meta.xml index e497a3092..7cc71acff 100644 --- a/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/Tag__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/Tag__c.field-meta.xml @@ -1,6 +1,7 @@ Tag__c + Active false LoggerTag__c @@ -8,6 +9,7 @@ LogEntryTags 1 false + Confidential true false false diff --git a/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/UniqueId__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/UniqueId__c.field-meta.xml index d1d0d468b..2740832f8 100644 --- a/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/UniqueId__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/LogEntryTag__c/fields/UniqueId__c.field-meta.xml @@ -1,6 +1,7 @@ UniqueId__c + Active false An external ID field used to ensure that Log Entry Tag records are unique true @@ -8,6 +9,7 @@ 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/DatabaseResultCollectionSize__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/DatabaseResultCollectionSize__c.field-meta.xml new file mode 100644 index 000000000..a7e1b78cf --- /dev/null +++ b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/DatabaseResultCollectionSize__c.field-meta.xml @@ -0,0 +1,15 @@ + + + DatabaseResultCollectionSize__c + The number of items contained in the collection of database results + false + The number of items contained in the collection of database results + + 10 + false + 0 + false + false + Number + false + diff --git a/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/EventUuid__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/EventUuid__c.field-meta.xml index 141e35b30..66f4977f2 100644 --- a/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/EventUuid__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/EventUuid__c.field-meta.xml @@ -11,7 +11,7 @@ For more details, refer to https://developer.salesforce.com/docs/atlas.en-us.pla For more details, refer to https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/platform_events_event_uuid.htm 36 - false + false false false Text diff --git a/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpRequestBodyMasked__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpRequestBodyMasked__c.field-meta.xml new file mode 100644 index 000000000..462c7d9e3 --- /dev/null +++ b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpRequestBodyMasked__c.field-meta.xml @@ -0,0 +1,11 @@ + + + HttpRequestBodyMasked__c + false + false + Indicates if sensitive data was removed from the HTTP Request Body, using log entry data mask rules + + false + false + Checkbox + diff --git a/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpRequestBody__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpRequestBody__c.field-meta.xml new file mode 100644 index 000000000..50414a97a --- /dev/null +++ b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpRequestBody__c.field-meta.xml @@ -0,0 +1,11 @@ + + + HttpRequestBody__c + false + + 131072 + false + false + LongTextArea + 5 + diff --git a/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpRequestCompressed__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpRequestCompressed__c.field-meta.xml new file mode 100644 index 000000000..ebf8828f6 --- /dev/null +++ b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpRequestCompressed__c.field-meta.xml @@ -0,0 +1,10 @@ + + + HttpRequestCompressed__c + false + false + + false + false + Checkbox + diff --git a/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpRequestEndpoint__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpRequestEndpoint__c.field-meta.xml new file mode 100644 index 000000000..f50bbbd77 --- /dev/null +++ b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpRequestEndpoint__c.field-meta.xml @@ -0,0 +1,12 @@ + + + HttpRequestEndpoint__c + false + + 255 + false + false + false + Text + false + diff --git a/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpRequestMethod__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpRequestMethod__c.field-meta.xml new file mode 100644 index 000000000..6bfb10c20 --- /dev/null +++ b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpRequestMethod__c.field-meta.xml @@ -0,0 +1,51 @@ + + + HttpRequestMethod__c + false + + false + false + false + Picklist + + false + + false + + DELETE + false + + + + GET + false + + + + HEAD + false + + + + PATCH + false + + + + POST + false + + + + PUT + false + + + + TRACE + false + + + + + diff --git a/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpResponseBodyMasked__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpResponseBodyMasked__c.field-meta.xml new file mode 100644 index 000000000..012766818 --- /dev/null +++ b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpResponseBodyMasked__c.field-meta.xml @@ -0,0 +1,11 @@ + + + HttpResponseBodyMasked__c + false + false + Indicates if sensitive data was removed from the HTTP Response Body, using log entry data mask rules + + false + false + Checkbox + diff --git a/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpResponseBody__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpResponseBody__c.field-meta.xml new file mode 100644 index 000000000..b0f892ac1 --- /dev/null +++ b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpResponseBody__c.field-meta.xml @@ -0,0 +1,11 @@ + + + HttpResponseBody__c + false + + 131072 + false + false + LongTextArea + 5 + diff --git a/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpResponseHeaderKeys__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpResponseHeaderKeys__c.field-meta.xml new file mode 100644 index 000000000..d5ca1263f --- /dev/null +++ b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpResponseHeaderKeys__c.field-meta.xml @@ -0,0 +1,11 @@ + + + HttpResponseHeaderKeys__c + false + + 1000 + false + false + LongTextArea + 5 + diff --git a/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpResponseStatusCode__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpResponseStatusCode__c.field-meta.xml new file mode 100644 index 000000000..d3f8431d7 --- /dev/null +++ b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpResponseStatusCode__c.field-meta.xml @@ -0,0 +1,13 @@ + + + HttpResponseStatusCode__c + false + + 10 + false + 0 + false + false + Number + false + diff --git a/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpResponseStatus__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpResponseStatus__c.field-meta.xml new file mode 100644 index 000000000..a12ff395e --- /dev/null +++ b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/HttpResponseStatus__c.field-meta.xml @@ -0,0 +1,12 @@ + + + HttpResponseStatus__c + false + + 255 + false + false + false + Text + false + diff --git a/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/RecordCollectionSize__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/RecordCollectionSize__c.field-meta.xml new file mode 100644 index 000000000..62cfee8f6 --- /dev/null +++ b/nebula-logger/core/main/log-management/objects/LogEntry__c/fields/RecordCollectionSize__c.field-meta.xml @@ -0,0 +1,15 @@ + + + RecordCollectionSize__c + The number of items contained in the collection of records + false + The number of items contained in the collection of records + + 10 + false + 0 + false + false + Number + false + diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/ApiReleaseNumber__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/ApiReleaseNumber__c.field-meta.xml index 564a48ab6..8ecde6685 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/ApiReleaseNumber__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/ApiReleaseNumber__c.field-meta.xml @@ -1,12 +1,14 @@ ApiReleaseNumber__c + Active The release number for the org's instance - determined by making a callout to status.salesforce.com false The release number for the org's instance - determined by making a callout to status.salesforce.com 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/ApiReleaseVersion__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/ApiReleaseVersion__c.field-meta.xml index e4020ebec..aa6351894 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/ApiReleaseVersion__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/ApiReleaseVersion__c.field-meta.xml @@ -1,12 +1,14 @@ ApiReleaseVersion__c + Active The release version for the org's instance - determined by making a callout to status.salesforce.com false The release version for the org's instance - determined by making a callout to status.salesforce.com 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/ApiVersion__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/ApiVersion__c.field-meta.xml index ece640f1e..070d94666 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/ApiVersion__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/ApiVersion__c.field-meta.xml @@ -1,11 +1,13 @@ ApiVersion__c + Active The Salesforce release (API version) of the environment false The Salesforce release (API version) of the environment false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/ClosedBy__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/ClosedBy__c.field-meta.xml index f94b48d5e..ecaae413d 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/ClosedBy__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/ClosedBy__c.field-meta.xml @@ -1,12 +1,14 @@ ClosedBy__c + Active SetNull false User ClosedLogs false + Confidential true true false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/ClosedDate__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/ClosedDate__c.field-meta.xml index d9322c007..97479330f 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/ClosedDate__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/ClosedDate__c.field-meta.xml @@ -1,9 +1,11 @@ ClosedDate__c + Active false false + Confidential true true false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/Comments__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/Comments__c.field-meta.xml index 332050596..78c68131a 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/Comments__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/Comments__c.field-meta.xml @@ -1,9 +1,11 @@ Comments__c + Active false 4000 + Confidential true true false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/EndTime__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/EndTime__c.field-meta.xml index ad5568429..544ccaed1 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/EndTime__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/EndTime__c.field-meta.xml @@ -1,8 +1,10 @@ EndTime__c + Active false + Confidential LogEntry__c.Timestamp__c LogEntry__c.Log__c max diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/IsClosed__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/IsClosed__c.field-meta.xml index 1521dad6f..6ef326596 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/IsClosed__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/IsClosed__c.field-meta.xml @@ -1,9 +1,11 @@ IsClosed__c + Active false false + Confidential true true false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/IsResolved__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/IsResolved__c.field-meta.xml index 2fe9207bd..d80fd86bf 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/IsResolved__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/IsResolved__c.field-meta.xml @@ -1,9 +1,11 @@ IsResolved__c + Active false false + Confidential true true false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/Issue__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/Issue__c.field-meta.xml index 566c088a7..7175495e0 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/Issue__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/Issue__c.field-meta.xml @@ -1,9 +1,11 @@ Issue__c + Active false false + Confidential true true false @@ -11,7 +13,7 @@ true - true + false Code Issue false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/Locale__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/Locale__c.field-meta.xml index bb71557e3..d53d290f0 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/Locale__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/Locale__c.field-meta.xml @@ -1,10 +1,12 @@ Locale__c + Active false 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/LogEntriesSummary__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/LogEntriesSummary__c.field-meta.xml index 946ebfbc1..50b0e7bde 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/LogEntriesSummary__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/LogEntriesSummary__c.field-meta.xml @@ -1,6 +1,7 @@ LogEntriesSummary__c + Active false TEXT(TotalLogEntries__c) + ' total entries' + IF( @@ -16,6 +17,7 @@ BlankAsZero false + Confidential false false Text diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/LogPurgeAction__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/LogPurgeAction__c.field-meta.xml new file mode 100644 index 000000000..2bdef9af0 --- /dev/null +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/LogPurgeAction__c.field-meta.xml @@ -0,0 +1,25 @@ + + + LogPurgeAction__c + Active + false + Used by the batch job LogBatchPurger, this indicates the action that should be taken for a Log__c record when LogRetentionDate__c < TODAY. Out of the box, only 'Delete' is used by Logger, but plugins can add & use new values. + + false + Confidential + true + true + false + Picklist + + + false + + Delete + false + + + + + diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/LogRetentionDate__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/LogRetentionDate__c.field-meta.xml index 0b900d312..c29cf0550 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/LogRetentionDate__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/LogRetentionDate__c.field-meta.xml @@ -1,6 +1,7 @@ LogRetentionDate__c + Active The date that this log can be automatically deleted by the batch job LogBatchPurger. It defaults to 2 weeks after creation (configurable in Logger Settings), but the date can be set manually or via automation if certain logs need to be kept longer/indefinitely. @@ -8,6 +9,7 @@ It defaults to 2 weeks after creation (configurable in Logger Settings), but the The date that this log can be automatically deleted by the batch job LogBatchPurger. false + Confidential true true false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggedByUsernameLink__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggedByUsernameLink__c.field-meta.xml index c87b7ff13..6ca70ce3e 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggedByUsernameLink__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggedByUsernameLink__c.field-meta.xml @@ -1,6 +1,8 @@ LoggedByUsernameLink__c + Active + PII false IF( ISBLANK(LoggedBy__c), @@ -18,6 +20,7 @@ BlankAsZero false + Confidential false false Text diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggedByUsername__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggedByUsername__c.field-meta.xml index 983c511aa..62c398af8 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggedByUsername__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggedByUsername__c.field-meta.xml @@ -1,10 +1,13 @@ LoggedByUsername__c + Active + PII false 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggedBy__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggedBy__c.field-meta.xml index 4ec369f88..191a8e006 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggedBy__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggedBy__c.field-meta.xml @@ -1,12 +1,14 @@ LoggedBy__c + Active SetNull false User Logs false + Confidential true false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggerVersionNumber__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggerVersionNumber__c.field-meta.xml index c7c2dc9f9..0b7be0a63 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggerVersionNumber__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoggerVersionNumber__c.field-meta.xml @@ -1,11 +1,12 @@ LoggerVersionNumber__c - false + Active true 14 false + Confidential true false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginApplication__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginApplication__c.field-meta.xml index 4bcd663cb..e42e11766 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginApplication__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginApplication__c.field-meta.xml @@ -1,10 +1,12 @@ LoginApplication__c + Active false 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginBrowser__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginBrowser__c.field-meta.xml index 2be71f897..97063d0b7 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginBrowser__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginBrowser__c.field-meta.xml @@ -1,10 +1,12 @@ LoginBrowser__c + Active false 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginDomain__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginDomain__c.field-meta.xml index 0a09ad39b..6329389d4 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginDomain__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginDomain__c.field-meta.xml @@ -1,9 +1,11 @@ LoginDomain__c + DeprecateCandidate false false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginHistoryId__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginHistoryId__c.field-meta.xml index 223808493..add18c405 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginHistoryId__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginHistoryId__c.field-meta.xml @@ -1,10 +1,12 @@ LoginHistoryId__c + Active false 18 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginPlatform__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginPlatform__c.field-meta.xml index fa8e137b4..a9a29ca21 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginPlatform__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginPlatform__c.field-meta.xml @@ -1,10 +1,12 @@ LoginPlatform__c + Active false 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginType__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginType__c.field-meta.xml index a77abc6ed..57cbd20b6 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginType__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/LoginType__c.field-meta.xml @@ -1,16 +1,18 @@ LoginType__c + Active false false + Confidential false false false Picklist - true + false Application false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/LogoutUrl__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/LogoutUrl__c.field-meta.xml index d425158db..f35ff6c5a 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/LogoutUrl__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/LogoutUrl__c.field-meta.xml @@ -1,9 +1,11 @@ LogoutUrl__c + Active false false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/MaxLogEntryLoggingLevelOrdinal__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/MaxLogEntryLoggingLevelOrdinal__c.field-meta.xml index 3b9fd89f8..0fb475547 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/MaxLogEntryLoggingLevelOrdinal__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/MaxLogEntryLoggingLevelOrdinal__c.field-meta.xml @@ -1,10 +1,12 @@ MaxLogEntryLoggingLevelOrdinal__c + Active The highest logging level ordinal of any related log entries false The highest logging level ordinal of any related log entries + Confidential LogEntry__c.LoggingLevelOrdinal__c LogEntry__c.Log__c max diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkId__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkId__c.field-meta.xml index 4dce88d11..1b8b4704e 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkId__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkId__c.field-meta.xml @@ -1,12 +1,15 @@ NetworkId__c + Active + PII The Network ID of the Community user's site. Set with Network.getNetworkId() true The Network ID of the user's Community site. 18 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkLoginUrl__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkLoginUrl__c.field-meta.xml index 8947a42eb..44c7ec30f 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkLoginUrl__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkLoginUrl__c.field-meta.xml @@ -1,9 +1,12 @@ NetworkLoginUrl__c + Active + PII false false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkLogoutUrl__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkLogoutUrl__c.field-meta.xml index 23ccc0c38..77a88f9af 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkLogoutUrl__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkLogoutUrl__c.field-meta.xml @@ -1,9 +1,12 @@ NetworkLogoutUrl__c + Active + PII false false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkName__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkName__c.field-meta.xml index c52ed9bbf..aad5b9d23 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkName__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkName__c.field-meta.xml @@ -1,12 +1,15 @@ NetworkName__c + Active + PII The name of the user's Community site (based on NetworkId). false The name of the user's Community site (based on NetworkId). 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkSelfRegistrationUrl__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkSelfRegistrationUrl__c.field-meta.xml index d5b60fcd4..d9b81b741 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkSelfRegistrationUrl__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkSelfRegistrationUrl__c.field-meta.xml @@ -1,9 +1,12 @@ NetworkSelfRegistrationUrl__c + Active + PII false false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkUrlPathPrefix__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkUrlPathPrefix__c.field-meta.xml index 9cbee92bf..db0b54d42 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkUrlPathPrefix__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/NetworkUrlPathPrefix__c.field-meta.xml @@ -1,6 +1,8 @@ NetworkUrlPathPrefix__c + Active + PII The UrlPathPrefix is a unique string at the end of the URL for this community. For example, in the community URL CommunitiesSubdomainName.force.com/customers, customers is the UrlPathPrefix. false @@ -9,6 +11,7 @@ 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationDomainUrl__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationDomainUrl__c.field-meta.xml index cb516caf2..90353792c 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationDomainUrl__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationDomainUrl__c.field-meta.xml @@ -1,11 +1,13 @@ OrganizationDomainUrl__c + Active The value returned from Url..getOrgDomainUrl() false The value returned from Url..getOrgDomainUrl() false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationEnvironmentType__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationEnvironmentType__c.field-meta.xml index c97b39abf..e3161535d 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationEnvironmentType__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationEnvironmentType__c.field-meta.xml @@ -1,9 +1,11 @@ OrganizationEnvironmentType__c + Active false false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationId__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationId__c.field-meta.xml index e4d6e4a80..2a96add22 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationId__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationId__c.field-meta.xml @@ -1,10 +1,12 @@ OrganizationId__c + Active false 18 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationInstanceName__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationInstanceName__c.field-meta.xml index c189ad52d..907db2c48 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationInstanceName__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationInstanceName__c.field-meta.xml @@ -1,10 +1,12 @@ OrganizationInstanceName__c + Active false 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationInstanceReleaseCycle__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationInstanceReleaseCycle__c.field-meta.xml index b48a16f08..9d4fbd0ae 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationInstanceReleaseCycle__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationInstanceReleaseCycle__c.field-meta.xml @@ -1,9 +1,11 @@ OrganizationInstanceReleaseCycle__c + DeprecateCandidate false false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationName__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationName__c.field-meta.xml index ba640028b..c39b0f25a 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationName__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationName__c.field-meta.xml @@ -1,10 +1,12 @@ OrganizationName__c + Active false 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationNamespacePrefix__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationNamespacePrefix__c.field-meta.xml index 4ae2ead4c..9d2894868 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationNamespacePrefix__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationNamespacePrefix__c.field-meta.xml @@ -1,10 +1,12 @@ OrganizationNamespacePrefix__c + Active false 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationType__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationType__c.field-meta.xml index 7a01a4aa3..1d31de9c0 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationType__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/OrganizationType__c.field-meta.xml @@ -1,9 +1,11 @@ OrganizationType__c + Active false false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/ParentLog__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/ParentLog__c.field-meta.xml index bb157f66a..60ac85829 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/ParentLog__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/ParentLog__c.field-meta.xml @@ -1,6 +1,7 @@ ParentLog__c + Active SetNull The log from the original transaction that initiated a child log - for example, batch jobs have start, execute and finish methods. All 3 are considered separate transactions. By using the parent log, logs from all 3 transactions can be linked together. @@ -12,6 +13,7 @@ Related Logs ChildLogs false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/Priority__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/Priority__c.field-meta.xml index ca1c247ce..ca874c767 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/Priority__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/Priority__c.field-meta.xml @@ -1,9 +1,11 @@ Priority__c + Active false false + Confidential true true false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/ProfileId__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/ProfileId__c.field-meta.xml index 1d26d7edb..edf5eccc1 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/ProfileId__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/ProfileId__c.field-meta.xml @@ -1,10 +1,13 @@ ProfileId__c + Active + PII false 18 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/ProfileLink__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/ProfileLink__c.field-meta.xml index b8ad1b45e..4f8d1b680 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/ProfileLink__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/ProfileLink__c.field-meta.xml @@ -1,11 +1,14 @@ ProfileLink__c + Active + PII false HYPERLINK('/' + ProfileId__c, ProfileName__c, '_top') BlankAsZero false + Confidential false false Text diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/ProfileName__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/ProfileName__c.field-meta.xml index e1b6d776a..cbeac9be7 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/ProfileName__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/ProfileName__c.field-meta.xml @@ -1,10 +1,13 @@ ProfileName__c + Active + PII false 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/Scenario__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/Scenario__c.field-meta.xml index b405391b0..cd2b5f618 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/Scenario__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/Scenario__c.field-meta.xml @@ -1,11 +1,12 @@ Scenario__c - false + Active true 255 false + Confidential true true false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/SessionId__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/SessionId__c.field-meta.xml index 6af2db111..359321471 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/SessionId__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/SessionId__c.field-meta.xml @@ -1,10 +1,13 @@ SessionId__c + Active + PII false 120 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/SessionSecurityLevel__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/SessionSecurityLevel__c.field-meta.xml index d4ec41751..49e4c7a4d 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/SessionSecurityLevel__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/SessionSecurityLevel__c.field-meta.xml @@ -1,9 +1,12 @@ SessionSecurityLevel__c + Active + PII false false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/SessionType__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/SessionType__c.field-meta.xml index e41afb24a..cdbb77849 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/SessionType__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/SessionType__c.field-meta.xml @@ -1,16 +1,19 @@ SessionType__c + Active + PII false false + Confidential false false false Picklist - true + false Aura false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/SourceIp__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/SourceIp__c.field-meta.xml index f177ca234..a67bae0be 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/SourceIp__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/SourceIp__c.field-meta.xml @@ -1,10 +1,13 @@ SourceIp__c + Active + PII false 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/StartTime__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/StartTime__c.field-meta.xml index 409ff58f2..616da84b8 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/StartTime__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/StartTime__c.field-meta.xml @@ -1,8 +1,10 @@ StartTime__c + Active false + Confidential LogEntry__c.Timestamp__c LogEntry__c.Log__c min diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/Status__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/Status__c.field-meta.xml index bf1cae059..eb11b8566 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/Status__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/Status__c.field-meta.xml @@ -1,9 +1,11 @@ Status__c + Active false false + Confidential true true false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/SystemModeSummary__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/SystemModeSummary__c.field-meta.xml index 3b18e2fc0..d6a066814 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/SystemModeSummary__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/SystemModeSummary__c.field-meta.xml @@ -1,11 +1,13 @@ SystemModeSummary__c + Active false 'API.' + TEXT(ApiVersion__c) + '.' + TEXT(SystemMode__c) BlankAsZero false + Confidential false false Text diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/SystemMode__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/SystemMode__c.field-meta.xml index 9146f17f2..34f5cdfb5 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/SystemMode__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/SystemMode__c.field-meta.xml @@ -1,16 +1,18 @@ SystemMode__c + Active false false + Confidential false false false Picklist - true + false ANONYMOUS false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/ThemeDisplayed__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/ThemeDisplayed__c.field-meta.xml index 69b64bc4c..f3fe03b69 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/ThemeDisplayed__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/ThemeDisplayed__c.field-meta.xml @@ -1,9 +1,11 @@ ThemeDisplayed__c + Active false false + Confidential true false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/TimeZoneId__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/TimeZoneId__c.field-meta.xml index ecb5aac42..eff2f6e20 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/TimeZoneId__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/TimeZoneId__c.field-meta.xml @@ -1,10 +1,13 @@ TimeZoneId__c + Active + PII false 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/TimeZoneName__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/TimeZoneName__c.field-meta.xml index b8c9a602c..e1ed26fe0 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/TimeZoneName__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/TimeZoneName__c.field-meta.xml @@ -1,10 +1,12 @@ TimeZoneName__c + Active false 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalDEBUGLogEntries__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalDEBUGLogEntries__c.field-meta.xml index f42654084..14f5cd9e6 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalDEBUGLogEntries__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalDEBUGLogEntries__c.field-meta.xml @@ -1,10 +1,12 @@ TotalDEBUGLogEntries__c + Active The total number of log entries with logging level == 'DEBUG' false The total number of log entries with logging level == 'DEBUG' + Confidential LogEntry__c.LoggingLevel__c equals diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalERRORLogEntries__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalERRORLogEntries__c.field-meta.xml index 09cd4ac86..464682efe 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalERRORLogEntries__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalERRORLogEntries__c.field-meta.xml @@ -1,10 +1,12 @@ TotalERRORLogEntries__c + Active The total number of log entries with logging level == 'ERROR' false The total number of log entries with logging level == 'ERROR' + Confidential LogEntry__c.LoggingLevel__c equals diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalFINELogEntries__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalFINELogEntries__c.field-meta.xml index 0a4f026cf..e12c52688 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalFINELogEntries__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalFINELogEntries__c.field-meta.xml @@ -1,10 +1,12 @@ TotalFINELogEntries__c + Active The total number of log entries with logging level == 'FINE' false The total number of log entries with logging level == 'FINE' + Confidential LogEntry__c.LoggingLevel__c equals diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalFINERLogEntries__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalFINERLogEntries__c.field-meta.xml index 91eedeb0d..1cbf43179 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalFINERLogEntries__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalFINERLogEntries__c.field-meta.xml @@ -1,10 +1,12 @@ TotalFINERLogEntries__c + Active The total number of log entries with logging level == 'FINER' false The total number of log entries with logging level == 'FINER' + Confidential LogEntry__c.LoggingLevel__c equals diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalFINESTLogEntries__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalFINESTLogEntries__c.field-meta.xml index 779b45b6e..164fffdb0 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalFINESTLogEntries__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalFINESTLogEntries__c.field-meta.xml @@ -1,10 +1,12 @@ TotalFINESTLogEntries__c + Active The total number of log entries with logging level == 'FINEST' false The total number of log entries with logging level == 'FINEST' + Confidential LogEntry__c.LoggingLevel__c equals diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalINFOLogEntries__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalINFOLogEntries__c.field-meta.xml index 02d97d7b6..80ed537f2 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalINFOLogEntries__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalINFOLogEntries__c.field-meta.xml @@ -1,10 +1,12 @@ TotalINFOLogEntries__c + Active The total number of log entries with logging level == 'INFO' false The total number of log entries with logging level == 'INFO' + Confidential LogEntry__c.LoggingLevel__c equals diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalLimitsCpuTimeUsed__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalLimitsCpuTimeUsed__c.field-meta.xml index 972db8fee..9fca72780 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalLimitsCpuTimeUsed__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalLimitsCpuTimeUsed__c.field-meta.xml @@ -1,8 +1,10 @@ TotalLimitsCpuTimeUsed__c + Active false + Confidential LogEntry__c.LimitsCpuTimeUsed__c LogEntry__c.Log__c max diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalLogEntries__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalLogEntries__c.field-meta.xml index ceca12d64..36d9deff2 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalLogEntries__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalLogEntries__c.field-meta.xml @@ -1,6 +1,7 @@ TotalLogEntries__c + Active false TotalERRORLogEntries__c + TotalWARNLogEntries__c @@ -14,6 +15,7 @@ 18 false 0 + Confidential false false Number diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalWARNLogEntries__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalWARNLogEntries__c.field-meta.xml index 7666dd0b8..08bed31a2 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalWARNLogEntries__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/TotalWARNLogEntries__c.field-meta.xml @@ -1,10 +1,12 @@ TotalWARNLogEntries__c + Active The total number of log entries with logging level == 'WARN' false The total number of log entries with logging level == 'WARN' + Confidential LogEntry__c.LoggingLevel__c equals diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/TransactionId__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/TransactionId__c.field-meta.xml index 7136a2d2a..662f4844c 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/TransactionId__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/TransactionId__c.field-meta.xml @@ -1,11 +1,13 @@ TransactionId__c + Active false true 36 false + Confidential true false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLicenseDefinitionKey__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLicenseDefinitionKey__c.field-meta.xml index c54766a66..c2ae56674 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLicenseDefinitionKey__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLicenseDefinitionKey__c.field-meta.xml @@ -1,10 +1,13 @@ UserLicenseDefinitionKey__c + Active + PII https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_userlicense.htm false false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLicenseId__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLicenseId__c.field-meta.xml index 9e92f3071..28a5ae14c 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLicenseId__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLicenseId__c.field-meta.xml @@ -1,10 +1,13 @@ UserLicenseId__c + Active + PII false 18 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLicenseName__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLicenseName__c.field-meta.xml index 7cf97606e..8f340098d 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLicenseName__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLicenseName__c.field-meta.xml @@ -1,16 +1,19 @@ UserLicenseName__c + Active + PII false false + Confidential false false false Picklist - true + false Analytics Cloud Integration User false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLoggingLevelOrdinal__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLoggingLevelOrdinal__c.field-meta.xml index f1bcfd2ee..02ce36afd 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLoggingLevelOrdinal__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLoggingLevelOrdinal__c.field-meta.xml @@ -1,11 +1,14 @@ UserLoggingLevelOrdinal__c + Active + PII false 2 false 0 + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLoggingLevel__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLoggingLevel__c.field-meta.xml index 1dfe76c41..f8913eb9f 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLoggingLevel__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserLoggingLevel__c.field-meta.xml @@ -1,9 +1,12 @@ UserLoggingLevel__c + Active + PII false false + Confidential true false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserRoleId__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserRoleId__c.field-meta.xml index 63c2ca897..f4756a88a 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserRoleId__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserRoleId__c.field-meta.xml @@ -1,10 +1,13 @@ UserRoleId__c + Active + PII false 18 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserRoleLink__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserRoleLink__c.field-meta.xml index 343de48a7..e0c23ebd7 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserRoleLink__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserRoleLink__c.field-meta.xml @@ -1,11 +1,14 @@ UserRoleLink__c + Active + PII false HYPERLINK('/' + UserRoleId__c, UserRoleName__c, '_top') BlankAsZero false + Confidential false false Text diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserRoleName__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserRoleName__c.field-meta.xml index aa92901ab..3c12f6f96 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserRoleName__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserRoleName__c.field-meta.xml @@ -1,10 +1,13 @@ UserRoleName__c + Active + PII false 255 false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserType__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserType__c.field-meta.xml index ffa8936f1..0e257bf66 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/UserType__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/UserType__c.field-meta.xml @@ -1,9 +1,12 @@ UserType__c + Active + PII false false + Confidential false false false diff --git a/nebula-logger/core/main/log-management/objects/Log__c/fields/WasLoggedByCurrentUser__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/fields/WasLoggedByCurrentUser__c.field-meta.xml index 23ac754cf..7ce6d64de 100644 --- a/nebula-logger/core/main/log-management/objects/Log__c/fields/WasLoggedByCurrentUser__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/Log__c/fields/WasLoggedByCurrentUser__c.field-meta.xml @@ -1,10 +1,13 @@ WasLoggedByCurrentUser__c + Active + PII false $User.Id == LoggedBy__c BlankAsZero + Confidential false false Checkbox diff --git a/nebula-logger/core/main/log-management/objects/Log__c/listViews/LogsToPurgeSoon.listView-meta.xml b/nebula-logger/core/main/log-management/objects/Log__c/listViews/LogsToPurgeSoon.listView-meta.xml new file mode 100644 index 000000000..4b1e004ac --- /dev/null +++ b/nebula-logger/core/main/log-management/objects/Log__c/listViews/LogsToPurgeSoon.listView-meta.xml @@ -0,0 +1,25 @@ + + + LogsToPurgeSoon + NAME + LoggedByUsernameLink__c + TransactionId__c + OWNER.ALIAS + Priority__c + Status__c + Scenario__c + StartTime__c + LogPurgeAction__c + LogRetentionDate__c + Everything + + LogRetentionDate__c + notEqual + + + LogRetentionDate__c + lessOrEqual + NEXT_N_DAYS:10 + + + diff --git a/nebula-logger/core/main/log-management/objects/LoggerTag__c/fields/TotalLogEntries__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LoggerTag__c/fields/TotalLogEntries__c.field-meta.xml index 57bdb6bc4..78325805e 100644 --- a/nebula-logger/core/main/log-management/objects/LoggerTag__c/fields/TotalLogEntries__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/LoggerTag__c/fields/TotalLogEntries__c.field-meta.xml @@ -1,8 +1,10 @@ TotalLogEntries__c + Active false + Confidential LogEntryTag__c.Tag__c count false diff --git a/nebula-logger/core/main/log-management/objects/LoggerTag__c/fields/UniqueId__c.field-meta.xml b/nebula-logger/core/main/log-management/objects/LoggerTag__c/fields/UniqueId__c.field-meta.xml index 426eb9778..af3b61747 100644 --- a/nebula-logger/core/main/log-management/objects/LoggerTag__c/fields/UniqueId__c.field-meta.xml +++ b/nebula-logger/core/main/log-management/objects/LoggerTag__c/fields/UniqueId__c.field-meta.xml @@ -1,6 +1,7 @@ UniqueId__c + Active false An external ID field used to ensure that Logger Tag records are unique true @@ -8,6 +9,7 @@ 255 false + Confidential false false false diff --git a/nebula-logger/core/main/configuration/permissionsets/LoggerAdmin.permissionset-meta.xml b/nebula-logger/core/main/log-management/permissionsets/LoggerAdmin.permissionset-meta.xml similarity index 94% rename from nebula-logger/core/main/configuration/permissionsets/LoggerAdmin.permissionset-meta.xml rename to nebula-logger/core/main/log-management/permissionsets/LoggerAdmin.permissionset-meta.xml index 994fb5e48..6cf000c60 100644 --- a/nebula-logger/core/main/configuration/permissionsets/LoggerAdmin.permissionset-meta.xml +++ b/nebula-logger/core/main/log-management/permissionsets/LoggerAdmin.permissionset-meta.xml @@ -164,6 +164,11 @@ LogEntry__c.ComponentType__c true + + false + LogEntry__c.DatabaseResultCollectionSize__c + true + false LogEntry__c.DatabaseResultCollectionType__c @@ -289,6 +294,51 @@ LogEntry__c.HasStackTrace__c true + + false + LogEntry__c.HttpRequestBody__c + true + + + false + LogEntry__c.HttpRequestBodyMasked__c + true + + + false + LogEntry__c.HttpRequestEndpoint__c + true + + + false + LogEntry__c.HttpRequestMethod__c + true + + + false + LogEntry__c.HttpResponseBody__c + true + + + false + LogEntry__c.HttpResponseBodyMasked__c + true + + + false + LogEntry__c.HttpResponseHeaderKeys__c + true + + + false + LogEntry__c.HttpResponseStatusCode__c + true + + + false + LogEntry__c.HttpResponseStatus__c + true + false LogEntry__c.LimitsAggregateQueriesMax__c @@ -584,6 +634,11 @@ LogEntry__c.Origin__c true + + false + LogEntry__c.RecordCollectionSize__c + true + false LogEntry__c.RecordCollectionType__c @@ -729,6 +784,11 @@ Log__c.LogEntriesSummary__c true + + true + Log__c.LogPurgeAction__c + true + true Log__c.LogRetentionDate__c diff --git a/nebula-logger/core/main/configuration/permissionsets/LoggerEndUser.permissionset-meta.xml b/nebula-logger/core/main/log-management/permissionsets/LoggerEndUser.permissionset-meta.xml similarity index 98% rename from nebula-logger/core/main/configuration/permissionsets/LoggerEndUser.permissionset-meta.xml rename to nebula-logger/core/main/log-management/permissionsets/LoggerEndUser.permissionset-meta.xml index e5e391d44..6ba95179a 100644 --- a/nebula-logger/core/main/configuration/permissionsets/LoggerEndUser.permissionset-meta.xml +++ b/nebula-logger/core/main/log-management/permissionsets/LoggerEndUser.permissionset-meta.xml @@ -54,6 +54,11 @@ LogEntry__c.ComponentType__c true + + false + LogEntry__c.DatabaseResultCollectionSize__c + true + false LogEntry__c.DatabaseResultCollectionType__c @@ -464,6 +469,11 @@ LogEntry__c.Origin__c true + + false + LogEntry__c.RecordCollectionSize__c + true + false LogEntry__c.RecordCollectionType__c @@ -481,12 +491,12 @@ false - LogEntry__c.RecordJson__c + LogEntry__c.RecordJsonMasked__c true false - LogEntry__c.RecordJsonMasked__c + LogEntry__c.RecordJson__c true @@ -574,6 +584,11 @@ Log__c.LogEntriesSummary__c true + + false + Log__c.LogPurgeAction__c + true + false Log__c.LogRetentionDate__c diff --git a/nebula-logger/core/main/configuration/permissionsets/LoggerLogCreator.permissionset-meta.xml b/nebula-logger/core/main/log-management/permissionsets/LoggerLogCreator.permissionset-meta.xml similarity index 100% rename from nebula-logger/core/main/configuration/permissionsets/LoggerLogCreator.permissionset-meta.xml rename to nebula-logger/core/main/log-management/permissionsets/LoggerLogCreator.permissionset-meta.xml diff --git a/nebula-logger/core/main/configuration/permissionsets/LoggerLogViewer.permissionset-meta.xml b/nebula-logger/core/main/log-management/permissionsets/LoggerLogViewer.permissionset-meta.xml similarity index 94% rename from nebula-logger/core/main/configuration/permissionsets/LoggerLogViewer.permissionset-meta.xml rename to nebula-logger/core/main/log-management/permissionsets/LoggerLogViewer.permissionset-meta.xml index d538daa7a..02a039642 100644 --- a/nebula-logger/core/main/configuration/permissionsets/LoggerLogViewer.permissionset-meta.xml +++ b/nebula-logger/core/main/log-management/permissionsets/LoggerLogViewer.permissionset-meta.xml @@ -92,6 +92,11 @@ LogEntry__c.ComponentType__c true + + false + LogEntry__c.DatabaseResultCollectionSize__c + true + false LogEntry__c.DatabaseResultCollectionType__c @@ -217,6 +222,51 @@ LogEntry__c.HasStackTrace__c true + + false + LogEntry__c.HttpRequestBody__c + true + + + false + LogEntry__c.HttpRequestBodyMasked__c + true + + + false + LogEntry__c.HttpRequestEndpoint__c + true + + + false + LogEntry__c.HttpRequestMethod__c + true + + + false + LogEntry__c.HttpResponseBody__c + true + + + false + LogEntry__c.HttpResponseBodyMasked__c + true + + + false + LogEntry__c.HttpResponseHeaderKeys__c + true + + + false + LogEntry__c.HttpResponseStatusCode__c + true + + + false + LogEntry__c.HttpResponseStatus__c + true + false LogEntry__c.LimitsAggregateQueriesMax__c @@ -512,6 +562,11 @@ LogEntry__c.Origin__c true + + false + LogEntry__c.RecordCollectionSize__c + true + false LogEntry__c.RecordCollectionType__c @@ -529,12 +584,12 @@ false - LogEntry__c.RecordJson__c + LogEntry__c.RecordJsonMasked__c true false - LogEntry__c.RecordJsonMasked__c + LogEntry__c.RecordJson__c true @@ -657,6 +712,11 @@ Log__c.LogEntriesSummary__c true + + false + Log__c.LogPurgeAction__c + true + false Log__c.LogRetentionDate__c diff --git a/nebula-logger/core/main/log-management/quickActions/Log__c.Manage.quickAction-meta.xml b/nebula-logger/core/main/log-management/quickActions/Log__c.Manage.quickAction-meta.xml index cab796550..35958bec4 100644 --- a/nebula-logger/core/main/log-management/quickActions/Log__c.Manage.quickAction-meta.xml +++ b/nebula-logger/core/main/log-management/quickActions/Log__c.Manage.quickAction-meta.xml @@ -35,6 +35,11 @@ LogRetentionDate__c Edit + + false + LogPurgeAction__c + Edit + diff --git a/nebula-logger/core/main/log-management/triggers/Log.trigger b/nebula-logger/core/main/log-management/triggers/Log.trigger index e7bfb5ad4..f0f150e19 100644 --- a/nebula-logger/core/main/log-management/triggers/Log.trigger +++ b/nebula-logger/core/main/log-management/triggers/Log.trigger @@ -3,5 +3,5 @@ // See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // //------------------------------------------------------------------------------------------------// trigger Log on Log__c(before insert, before update, before delete, after insert, after update, after delete, after undelete) { - new LogHandler().execute(); + LoggerSObjectHandler.getHandler(Schema.Log__c.SObjectType, new LogHandler()).execute(); } diff --git a/nebula-logger/core/main/log-management/triggers/LogEntry.trigger b/nebula-logger/core/main/log-management/triggers/LogEntry.trigger index 07009e45a..9399171e3 100644 --- a/nebula-logger/core/main/log-management/triggers/LogEntry.trigger +++ b/nebula-logger/core/main/log-management/triggers/LogEntry.trigger @@ -3,5 +3,5 @@ // See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // //------------------------------------------------------------------------------------------------// trigger LogEntry on LogEntry__c(before insert, before update, before delete, after insert, after update, after delete, after undelete) { - new LogEntryHandler().execute(); + LoggerSObjectHandler.getHandler(Schema.LogEntry__c.SObjectType, new LogEntryHandler()).execute(); } diff --git a/nebula-logger/core/main/log-management/triggers/LogEntryEvent.trigger b/nebula-logger/core/main/log-management/triggers/LogEntryEvent.trigger index b3dbb6d23..9c35ec4d6 100644 --- a/nebula-logger/core/main/log-management/triggers/LogEntryEvent.trigger +++ b/nebula-logger/core/main/log-management/triggers/LogEntryEvent.trigger @@ -3,5 +3,5 @@ // See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // //------------------------------------------------------------------------------------------------// trigger LogEntryEvent on LogEntryEvent__e(after insert) { - new LogEntryEventHandler().execute(); + LoggerSObjectHandler.getHandler(Schema.LogEntryEvent__e.SObjectType, new LogEntryEventHandler()).execute(); } diff --git a/nebula-logger/core/main/log-management/triggers/LogEntryTag.trigger b/nebula-logger/core/main/log-management/triggers/LogEntryTag.trigger index ef2855e3e..a1fd400ab 100644 --- a/nebula-logger/core/main/log-management/triggers/LogEntryTag.trigger +++ b/nebula-logger/core/main/log-management/triggers/LogEntryTag.trigger @@ -3,5 +3,5 @@ // See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // //------------------------------------------------------------------------------------------------// trigger LogEntryTag on LogEntryTag__c(before insert, before update, before delete, after insert, after update, after delete, after undelete) { - new LogEntryTagHandler().execute(); + LoggerSObjectHandler.getHandler(Schema.LogEntryTag__c.SObjectType, new LogEntryTagHandler()).execute(); } diff --git a/nebula-logger/core/main/log-management/triggers/LoggerTag.trigger b/nebula-logger/core/main/log-management/triggers/LoggerTag.trigger index 150848217..44427188a 100644 --- a/nebula-logger/core/main/log-management/triggers/LoggerTag.trigger +++ b/nebula-logger/core/main/log-management/triggers/LoggerTag.trigger @@ -3,5 +3,5 @@ // See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // //------------------------------------------------------------------------------------------------// trigger LoggerTag on LoggerTag__c(before insert, before update, before delete, after insert, after update, after delete, after undelete) { - new LoggerTagHandler().execute(); + LoggerSObjectHandler.getHandler(Schema.LoggerTag__c.SObjectType, new LoggerTagHandler()).execute(); } diff --git a/nebula-logger/core/main/logger-engine/classes/ComponentLogger.cls b/nebula-logger/core/main/logger-engine/classes/ComponentLogger.cls index bf84cb5de..6e6623317 100644 --- a/nebula-logger/core/main/logger-engine/classes/ComponentLogger.cls +++ b/nebula-logger/core/main/logger-engine/classes/ComponentLogger.cls @@ -52,7 +52,10 @@ public inherited sharing class ComponentLogger { Logger.saveLog(saveMethod); return Logger.getTransactionId(); } catch (Exception apexException) { - throw new AuraHandledException(apexException.getMessage()); + String errorMessage = apexException.getMessage() + '\n' + apexException.getStackTraceString(); + AuraHandledException auraException = new AuraHandledException(errorMessage); + auraException.setMessage(errorMessage); + throw auraException; } } diff --git a/nebula-logger/core/main/logger-engine/classes/FlowCollectionLogEntry.cls b/nebula-logger/core/main/logger-engine/classes/FlowCollectionLogEntry.cls index f0219cbba..b0111382b 100644 --- a/nebula-logger/core/main/logger-engine/classes/FlowCollectionLogEntry.cls +++ b/nebula-logger/core/main/logger-engine/classes/FlowCollectionLogEntry.cls @@ -88,13 +88,16 @@ global inherited sharing class FlowCollectionLogEntry { @InvocableMethod( category='Logging' label='Add Log Entry for an SObject Record Collection' - description='Creates a log entry for a flow or process builder and stores the record as JSON' + description='Creates a log entry for a flow or process builder and stores the record list as JSON' ) global static List addFlowCollectionEntries(List flowCollectionLogEntries) { List shadowLogEntries = new List(); for (FlowCollectionLogEntry flowCollectionLogEntry : flowCollectionLogEntries) { FlowLogger.LogEntry shadowLogEntry = (FlowLogger.LogEntry) JSON.deserialize(JSON.serialize(flowCollectionLogEntry), FlowLogger.LogEntry.class); - shadowLogEntry.addToLoggerBuffer()?.setRecord(flowCollectionLogEntry.records); + LogEntryEventBuilder builder = shadowLogEntry.addToLoggerBuffer()?.setRecord(flowCollectionLogEntry.records); + if (builder.shouldSave() == true && flowCollectionLogEntry.records?.size() > 0) { + builder.getLogEntryEvent().RecordSObjectType__c = flowCollectionLogEntry.records.get(0).getSObjectType().getDescribe().getName(); + } shadowLogEntries.add(shadowLogEntry); } diff --git a/nebula-logger/core/main/logger-engine/classes/LogEntryEventBuilder.cls b/nebula-logger/core/main/logger-engine/classes/LogEntryEventBuilder.cls index ae8f8cc06..efeb9b18e 100644 --- a/nebula-logger/core/main/logger-engine/classes/LogEntryEventBuilder.cls +++ b/nebula-logger/core/main/logger-engine/classes/LogEntryEventBuilder.cls @@ -9,7 +9,7 @@ * @see Logger */ @SuppressWarnings( - 'PMD.NcssTypeCount, PMD.ApexCRUDViolation, PMD.AvoidGlobalModifier, PMD.PropertyNamingConventions, PMD.CognitiveComplexity, PMD.StdCyclomaticComplexity, PMD.CyclomaticComplexity' + 'PMD.ApexCRUDViolation, PMD.AvoidGlobalModifier, PMD.CognitiveComplexity, PMD.CyclomaticComplexity, PMD.ExcessiveClassLength, PMD.NcssTypeCount, PMD.PropertyNamingConventions, PMD.StdCyclomaticComplexity' ) global with sharing class LogEntryEventBuilder { private static final String API_VERSION = getApiVersion(); @@ -71,7 +71,7 @@ global with sharing class LogEntryEventBuilder { set; } - private static final List CACHED_DATA_MASK_RULES { + private static final Map CACHED_DATA_MASK_RULES { get { if (CACHED_DATA_MASK_RULES == null) { CACHED_DATA_MASK_RULES = loadDataMaskRules(); @@ -167,7 +167,7 @@ global with sharing class LogEntryEventBuilder { global LogEntryEventBuilder setMessage(String message) { // To help with debugging unit tests, always run System.debug statement in a test context if ((this.shouldSave == true || System.Test.isRunningTest() == true) && this.logEntryEvent != null) { - String cleanedMessage = applyDataMaskRules(message, true, false); + String cleanedMessage = applyDataMaskRules(message); Boolean messageMasked = cleanedMessage != message; String truncatedMessage = truncateFieldValue(Schema.LogEntryEvent__e.Message__c, cleanedMessage); Boolean messageTruncated = @@ -210,15 +210,16 @@ global with sharing class LogEntryEventBuilder { * @return The same instance of `LogEntryEventBuilder`, useful for chaining methods */ global LogEntryEventBuilder setDatabaseResult(Database.DeleteResult deleteResult) { - if (this.shouldSave == false || deleteResult == null) { + if (this.shouldSave == false) { return this; } + this.logEntryEvent.DatabaseResultCollectionSize__c = 1; this.logEntryEvent.DatabaseResultCollectionType__c = 'Single'; this.logEntryEvent.DatabaseResultJson__c = truncateFieldValue(Schema.LogEntryEvent__e.DatabaseResultJson__c, JSON.serializePretty(deleteResult)); this.logEntryEvent.DatabaseResultType__c = Database.DeleteResult.class.getName(); - return this.setRecordId(deleteResult.getId()); + return this.setRecordId(deleteResult?.getId()); } /** @@ -227,15 +228,16 @@ global with sharing class LogEntryEventBuilder { * @return The same instance of `LogEntryEventBuilder`, useful for chaining methods */ global LogEntryEventBuilder setDatabaseResult(Database.MergeResult mergeResult) { - if (this.shouldSave == false || mergeResult == null) { + if (this.shouldSave == false) { return this; } + this.logEntryEvent.DatabaseResultCollectionSize__c = 1; this.logEntryEvent.DatabaseResultCollectionType__c = 'Single'; this.logEntryEvent.DatabaseResultJson__c = truncateFieldValue(Schema.LogEntryEvent__e.DatabaseResultJson__c, JSON.serializePretty(mergeResult)); this.logEntryEvent.DatabaseResultType__c = Database.MergeResult.class.getName(); - return this.setRecordId(mergeResult.getId()); + return this.setRecordId(mergeResult?.getId()); } /** @@ -244,15 +246,16 @@ global with sharing class LogEntryEventBuilder { * @return The same instance of `LogEntryEventBuilder`, useful for chaining methods */ global LogEntryEventBuilder setDatabaseResult(Database.SaveResult saveResult) { - if (this.shouldSave == false || saveResult == null) { + if (this.shouldSave == false) { return this; } + this.logEntryEvent.DatabaseResultCollectionSize__c = 1; this.logEntryEvent.DatabaseResultCollectionType__c = 'Single'; this.logEntryEvent.DatabaseResultJson__c = truncateFieldValue(Schema.LogEntryEvent__e.DatabaseResultJson__c, JSON.serializePretty(saveResult)); this.logEntryEvent.DatabaseResultType__c = Database.SaveResult.class.getName(); - return this.setRecordId(saveResult.getId()); + return this.setRecordId(saveResult?.getId()); } /** @@ -261,18 +264,19 @@ global with sharing class LogEntryEventBuilder { * @return The same instance of `LogEntryEventBuilder`, useful for chaining methods */ global LogEntryEventBuilder setDatabaseResult(Database.UpsertResult upsertResult) { - if (this.shouldSave == false || upsertResult == null) { + if (this.shouldSave == false) { return this; } // Upsert has 2 subtypes (surprise!) - insert and update - so, UpsertResult has an extra method to take into account String subtype = upsertResult.isCreated() ? 'Insert' : 'Update'; + this.logEntryEvent.DatabaseResultCollectionSize__c = 1; this.logEntryEvent.DatabaseResultCollectionType__c = 'Single'; this.logEntryEvent.DatabaseResultJson__c = truncateFieldValue(Schema.LogEntryEvent__e.DatabaseResultJson__c, JSON.serializePretty(upsertResult)); this.logEntryEvent.DatabaseResultType__c = Database.UpsertResult.class.getName() + '.' + subtype; - return this.setRecordId(upsertResult.getId()); + return this.setRecordId(upsertResult?.getId()); } /** @@ -281,15 +285,16 @@ global with sharing class LogEntryEventBuilder { * @return The same instance of `LogEntryEventBuilder`, useful for chaining methods */ global LogEntryEventBuilder setDatabaseResult(Database.UndeleteResult undeleteResult) { - if (this.shouldSave == false || undeleteResult == null) { + if (this.shouldSave == false) { return this; } + this.logEntryEvent.DatabaseResultCollectionSize__c = 1; this.logEntryEvent.DatabaseResultCollectionType__c = 'Single'; this.logEntryEvent.DatabaseResultJson__c = truncateFieldValue(Schema.LogEntryEvent__e.DatabaseResultJson__c, JSON.serializePretty(undeleteResult)); this.logEntryEvent.DatabaseResultType__c = Database.UndeleteResult.class.getName(); - return this.setRecordId(undeleteResult.getId()); + return this.setRecordId(undeleteResult?.getId()); } /** @@ -298,10 +303,11 @@ global with sharing class LogEntryEventBuilder { * @return The same instance of `LogEntryEventBuilder`, useful for chaining methods */ global LogEntryEventBuilder setDatabaseResult(List deleteResults) { - if (this.shouldSave == false || deleteResults == null) { + if (this.shouldSave == false) { return this; } + this.logEntryEvent.DatabaseResultCollectionSize__c = deleteResults?.size(); this.logEntryEvent.DatabaseResultCollectionType__c = 'List'; this.logEntryEvent.DatabaseResultJson__c = truncateFieldValue(Schema.LogEntryEvent__e.DatabaseResultJson__c, JSON.serializePretty(deleteResults)); this.logEntryEvent.DatabaseResultType__c = Database.DeleteResult.class.getName(); @@ -315,10 +321,11 @@ global with sharing class LogEntryEventBuilder { * @return The same instance of `LogEntryEventBuilder`, useful for chaining methods */ global LogEntryEventBuilder setDatabaseResult(List mergeResults) { - if (this.shouldSave == false || mergeResults == null) { + if (this.shouldSave == false) { return this; } + this.logEntryEvent.DatabaseResultCollectionSize__c = mergeResults?.size(); this.logEntryEvent.DatabaseResultCollectionType__c = 'List'; this.logEntryEvent.DatabaseResultJson__c = truncateFieldValue(Schema.LogEntryEvent__e.DatabaseResultJson__c, JSON.serializePretty(mergeResults)); this.logEntryEvent.DatabaseResultType__c = Database.MergeResult.class.getName(); @@ -332,10 +339,11 @@ global with sharing class LogEntryEventBuilder { * @return The same instance of `LogEntryEventBuilder`, useful for chaining methods */ global LogEntryEventBuilder setDatabaseResult(List saveResults) { - if (this.shouldSave == false || saveResults == null) { + if (this.shouldSave == false) { return this; } + this.logEntryEvent.DatabaseResultCollectionSize__c = saveResults?.size(); this.logEntryEvent.DatabaseResultCollectionType__c = 'List'; this.logEntryEvent.DatabaseResultJson__c = truncateFieldValue(Schema.LogEntryEvent__e.DatabaseResultJson__c, JSON.serializePretty(saveResults)); this.logEntryEvent.DatabaseResultType__c = Database.SaveResult.class.getName(); @@ -349,10 +357,11 @@ global with sharing class LogEntryEventBuilder { * @return The same instance of `LogEntryEventBuilder`, useful for chaining methods */ global LogEntryEventBuilder setDatabaseResult(List upsertResults) { - if (this.shouldSave == false || upsertResults == null) { + if (this.shouldSave == false) { return this; } + this.logEntryEvent.DatabaseResultCollectionSize__c = upsertResults?.size(); this.logEntryEvent.DatabaseResultCollectionType__c = 'List'; this.logEntryEvent.DatabaseResultJson__c = truncateFieldValue(Schema.LogEntryEvent__e.DatabaseResultJson__c, JSON.serializePretty(upsertResults)); this.logEntryEvent.DatabaseResultType__c = Database.UpsertResult.class.getName(); @@ -366,10 +375,11 @@ global with sharing class LogEntryEventBuilder { * @return The same instance of `LogEntryEventBuilder`, useful for chaining methods */ global LogEntryEventBuilder setDatabaseResult(List undeleteResults) { - if (this.shouldSave == false || undeleteResults == null) { + if (this.shouldSave == false) { return this; } + this.logEntryEvent.DatabaseResultCollectionSize__c = undeleteResults?.size(); this.logEntryEvent.DatabaseResultCollectionType__c = 'List'; this.logEntryEvent.DatabaseResultJson__c = truncateFieldValue(Schema.LogEntryEvent__e.DatabaseResultJson__c, JSON.serializePretty(undeleteResults)); this.logEntryEvent.DatabaseResultType__c = Database.UndeleteResult.class.getName(); @@ -405,6 +415,7 @@ global with sharing class LogEntryEventBuilder { return this; } + this.logEntryEvent.RecordCollectionSize__c = 1; this.logEntryEvent.RecordCollectionType__c = 'Single'; this.logEntryEvent.RecordId__c = recordId; this.logEntryEvent.RecordSObjectClassification__c = getSObjectClassification(recordId.getSObjectType()); @@ -422,6 +433,7 @@ global with sharing class LogEntryEventBuilder { return this; } + this.logEntryEvent.RecordCollectionSize__c = 1; this.logEntryEvent.RecordCollectionType__c = 'Single'; String recordJson = getJson(record); @@ -430,7 +442,7 @@ global with sharing class LogEntryEventBuilder { this.logEntryEvent.RecordSObjectClassification__c = 'Unknown'; this.logEntryEvent.RecordSObjectType__c = 'Unknown'; } else { - String cleanedRecordJson = applyDataMaskRules(recordJson, false, true); + String cleanedRecordJson = applyDataMaskRules(recordJson); Boolean recordJsonMasked = cleanedRecordJson != recordJson; this.logEntryEvent.RecordId__c = record.Id; @@ -454,23 +466,17 @@ global with sharing class LogEntryEventBuilder { return this; } + this.logEntryEvent.RecordCollectionSize__c = records?.size(); this.logEntryEvent.RecordCollectionType__c = 'List'; - // First, try to use the list's SObject Type - if the list is null or an instance of List, it won't have an SObject Type - // If using the list doesn't work, and there are 1+ records in the list, then try to use the first record's SObject Type - if it's null, it won't have an SObject Type - // If the first object doesn't work, then just log as is a generic SObject - no need to waste additional CPU time on it Schema.SObjectType sobjectType = records?.getSObjectType(); - if (sobjectType == null && records != null && records.size() >= 1) { - sobjectType = records.get(0)?.getSObjectType(); - } - String recordJson = getJson(records); if (sobjectType == null) { this.logEntryEvent.RecordJson__c = recordJson; this.logEntryEvent.RecordSObjectClassification__c = 'Unknown'; this.logEntryEvent.RecordSObjectType__c = 'Unknown'; } else { - String cleanedRecordJson = applyDataMaskRules(recordJson, false, true); + String cleanedRecordJson = applyDataMaskRules(recordJson); Boolean recordJsonMasked = cleanedRecordJson != recordJson; this.logEntryEvent.RecordJson__c = cleanedRecordJson; @@ -483,6 +489,48 @@ global with sharing class LogEntryEventBuilder { return this; } + /** + * @description Sets the log entry event's HTTP Request fields + * @param request The instance of `HttpRequest` to log + * @return The same instance of `LogEntryEventBuilder`, useful for chaining methods + */ + global LogEntryEventBuilder setHttpRequestDetails(HttpRequest request) { + if (this.shouldSave == false || request == null) { + return this; + } + + String cleanedRequestBody = applyDataMaskRules(request.getBody()); + Boolean requestBodyMasked = cleanedRequestBody != request.getBody(); + + this.logEntryEvent.HttpRequestBody__c = cleanedRequestBody; + this.logEntryEvent.HttpRequestBodyMasked__c = requestBodyMasked; + this.logEntryEvent.HttpRequestCompressed__c = request.getCompressed(); + this.logEntryEvent.HttpRequestEndpoint__c = request.getEndpoint(); + this.logEntryEvent.HttpRequestMethod__c = request.getMethod(); + return this; + } + + /** + * @description Sets the log entry event's HTTP Response fields + * @param response The instance of `HttpResponse` to log + * @return The same instance of `LogEntryEventBuilder`, useful for chaining methods + */ + global LogEntryEventBuilder setHttpResponseDetails(HttpResponse response) { + if (this.shouldSave == false || response == null) { + return this; + } + + String cleanedResponseBody = applyDataMaskRules(response.getBody()); + Boolean responseBodyMasked = cleanedResponseBody != response.getBody(); + + this.logEntryEvent.HttpResponseBody__c = cleanedResponseBody; + this.logEntryEvent.HttpResponseBodyMasked__c = responseBodyMasked; + this.logEntryEvent.HttpResponseHeaderKeys__c = String.join(response.getHeaderKeys(), '\n'); + this.logEntryEvent.HttpResponseStatus__c = response.getStatus(); + this.logEntryEvent.HttpResponseStatusCode__c = response.getStatusCode(); + return this; + } + /** * @description Appends the tag to the existing list of tags * @param tag The string to use as a tag for the current entry @@ -541,9 +589,14 @@ global with sharing class LogEntryEventBuilder { } List stackTraceLines = new List(); + String previousStackTraceLine; for (String currentStackTraceLine : stackTraceString.split('\n')) { - // Don't include the logging system's classes in the stack trace + // Duplicate lines are sometimes introduced, so skip the current line if it's the same as the previous line + if (currentStackTraceLine == previousStackTraceLine) { + continue; + } + // Don't include the logging system's classes in the stack trace Boolean ignoreLine = false; for (String ignoredClass : IGNORED_CLASSES) { if (currentStackTraceLine.contains('.' + ignoredClass + '.')) { @@ -557,6 +610,7 @@ global with sharing class LogEntryEventBuilder { } if (ignoreLine == false) { + previousStackTraceLine = currentStackTraceLine; stackTraceLines.add(currentStackTraceLine); } } @@ -669,7 +723,9 @@ global with sharing class LogEntryEventBuilder { return; } - this.logEntryEvent.Tags__c = String.escapeSingleQuotes(String.join(new List(this.tags), '\n')); + List sortedTags = new List(this.tags); + sortedTags.sort(); + this.logEntryEvent.Tags__c = String.escapeSingleQuotes(String.join(sortedTags, '\n')); } private void setTransactionDetails() { @@ -739,17 +795,17 @@ global with sharing class LogEntryEventBuilder { // Private static helper methods @TestVisible - private static void addMockDataMaskRule(LogEntryDataMaskRule__mdt dataMaskRule) { - CACHED_DATA_MASK_RULES.add(dataMaskRule); + private static void setMockDataMaskRule(LogEntryDataMaskRule__mdt dataMaskRule) { + CACHED_DATA_MASK_RULES.put(dataMaskRule.DeveloperName, dataMaskRule); } - private static String applyDataMaskRules(String dataInput, Boolean applyToMessage, Boolean applyToRecordJson) { + private static String applyDataMaskRules(String dataInput) { if (Logger.getUserSettings().IsDataMaskingEnabled__c == false || String.isBlank(dataInput) == true) { return dataInput; } - for (LogEntryDataMaskRule__mdt dataMaskRule : CACHED_DATA_MASK_RULES) { - if ((applyToMessage && dataMaskRule.ApplyToMessage__c) == true || (applyToRecordJson && dataMaskRule.ApplyToRecordJson__c) == true) { + for (LogEntryDataMaskRule__mdt dataMaskRule : CACHED_DATA_MASK_RULES.values()) { + if (dataMaskRule.IsEnabled__c == true) { dataInput = dataInput.replaceAll(dataMaskRule.SensitiveDataRegEx__c, dataMaskRule.ReplacementRegEx__c); } } @@ -766,16 +822,16 @@ global with sharing class LogEntryEventBuilder { return userJson.substringAfter('/data/').substringBefore('/sobjects/User'); } - private static List loadDataMaskRules() { - List activeDataMaskRules = new List(); + private static Map loadDataMaskRules() { + Map activeDataMaskRules = new Map(); for (LogEntryDataMaskRule__mdt dataMaskRule : LogEntryDataMaskRule__mdt.getAll().values()) { if (dataMaskRule.IsEnabled__c == true) { - activeDataMaskRules.add(dataMaskRule); + activeDataMaskRules.put(dataMaskRule.DeveloperName, dataMaskRule); } } if (System.Test.isRunningTest() == true) { // Tests shouldn't rely on the actual CMDT rules in the org - // Clear the org's loaded records during tests, and mock via addMockDataMaskRule() + // Clear the org's loaded records during tests, and mock via setMockDataMaskRule() activeDataMaskRules.clear(); } return activeDataMaskRules; @@ -938,7 +994,7 @@ global with sharing class LogEntryEventBuilder { private static SObject queryNetwork() { Id networkId = Network.getNetworkId(); - if (networkId == null || Schema.getGlobalDescribe().containsKey('Network') == false) { + if (networkId == null || Type.forName('Network') == null) { return null; } diff --git a/nebula-logger/core/main/logger-engine/classes/Logger.cls b/nebula-logger/core/main/logger-engine/classes/Logger.cls index 8781cc8bc..c602a5566 100644 --- a/nebula-logger/core/main/logger-engine/classes/Logger.cls +++ b/nebula-logger/core/main/logger-engine/classes/Logger.cls @@ -15,27 +15,29 @@ global with sharing class Logger { // There's no reliable way to get the version number dynamically in Apex @TestVisible - private static final String CURRENT_VERSION_NUMBER = 'v4.7.0'; + private static final String CURRENT_VERSION_NUMBER = 'v4.7.1'; private static final LoggingLevel DEFAULT_LOGGING_LEVEL = LoggingLevel.DEBUG; private static final List LOG_ENTRIES_BUFFER = new List(); - @TestVisible - private static final Map SCENARIO_TO_MOCK_SCENARIO_RULE = new Map(); + private static final Map MOCK_SCENARIO_TO_SCENARIO_RULE = new Map(); private static final String TRANSACTION_ID = setTransactionId(); private static final Quiddity TRANSACTION_QUIDDITY = setTransactionQuiddity(); private static Integer currentTransactionEntryNumber = 1; + @TestVisible + private static String lastSaveMethodNameUsed; private static String parentLogTransactionId; - private static String transactionScenario = getUserSettings().DefaultLogScenario__c; + @TestVisible + private static Integer saveLogCallCount = 0; private static Boolean suspendSaving = false; + private static String transactionScenario = getUserSettings().DefaultLogScenario__c; private static LoggerSettings__c userSettings; - @TestVisible - private static SaveMethod transactionSaveMethod { + private static String transactionSaveMethodName { get { - if (transactionSaveMethod == null) { - transactionSaveMethod = getDefaultSaveMethod(); + if (transactionSaveMethodName == null) { + transactionSaveMethodName = getUserSettings().DefaultSaveMethod__c; } - return transactionSaveMethod; + return transactionSaveMethodName; } set; } @@ -51,7 +53,7 @@ global with sharing class Logger { } static { - System.debug(LoggingLevel.INFO, 'Logger - Version Number: ' + CURRENT_VERSION_NUMBER); + System.debug(LoggingLevel.INFO, 'Logger - Version Number: ' + getVersionNumber()); System.debug(LoggingLevel.INFO, 'Logger - Transaction ID: ' + getTransactionId()); } @@ -65,6 +67,25 @@ global with sharing class Logger { SYNCHRONOUS_DML } + // System info methods + + /** + * @description Returns the current version number of Nebula Logger + * @return The current version number, in the format `v0.0.0` + */ + public static String getVersionNumber() { + return CURRENT_VERSION_NUMBER; + } + + /** + * @description Returns the current namespace of Nebula Logger + * @return The current namespace prefix, or an empty string when no namespace is being used + */ + public static String getNamespacePrefix() { + String className = Logger.class.getName(); + return className.contains('.') ? className.substringBefore('.') : ''; + } + // Settings management methods /** @@ -2474,7 +2495,7 @@ global with sharing class Logger { } if (System.Test.isRunningTest() == true) { - matchingScenarioRule = SCENARIO_TO_MOCK_SCENARIO_RULE.get(scenario); + matchingScenarioRule = MOCK_SCENARIO_TO_SCENARIO_RULE.get(scenario); } if (matchingScenarioRule != null) { @@ -2484,7 +2505,7 @@ global with sharing class Logger { @TestVisible private static void setMockScenarioRule(LogScenarioRule__mdt scenarioRule) { - SCENARIO_TO_MOCK_SCENARIO_RULE.put(scenarioRule.Scenario__c, scenarioRule); + MOCK_SCENARIO_TO_SCENARIO_RULE.put(scenarioRule.Scenario__c, scenarioRule); } /** @@ -2492,7 +2513,7 @@ global with sharing class Logger { * @return The enum value of Logger.SaveMethod to use for any calls to saveLog() in the current transaction */ global static SaveMethod getSaveMethod() { - return transactionSaveMethod; + return getSaveMethod(transactionSaveMethodName); } /** @@ -2500,7 +2521,7 @@ global with sharing class Logger { * @param saveMethod The enum value of Logger.SaveMethod to use for any other calls to saveLog() in the current transaction */ global static void setSaveMethod(SaveMethod saveMethod) { - transactionSaveMethod = saveMethod; + transactionSaveMethodName = saveMethod.name(); } /** @@ -2508,7 +2529,7 @@ global with sharing class Logger { */ @InvocableMethod(category='Logging' label='Save Log' description='Saves any log entries that have been generated') global static void saveLog() { - saveLog(transactionSaveMethod); + saveLog(transactionSaveMethodName); } /** @@ -2516,8 +2537,19 @@ global with sharing class Logger { * All subsequent calls to saveLog() will use the transaction save method. * @param saveMethod The enum value of Logger.SaveMethod to use for this specific save action. */ - @SuppressWarnings('PMD.NcssMethodCount') global static void saveLog(SaveMethod saveMethod) { + saveLog(saveMethod.name()); + } + + /** + * @description Saves any entries in Logger's buffer, using the specified save method for only this call. + * All subsequent calls to saveLog() will use the transaction save method. + * @param saveMethodName The String value of the save method to use for this specific save action. + */ + @SuppressWarnings('PMD.NcssMethodCount') + public static void saveLog(String saveMethodName) { + saveLogCallCount++; + lastSaveMethodNameUsed = saveMethodName; if (LOG_ENTRIES_BUFFER.isEmpty() || getUserSettings().IsSavingEnabled__c == false) { return; } @@ -2531,7 +2563,7 @@ global with sharing class Logger { } if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { - finest(getSavingLogSystemMessage(saveMethod)); + finest(getSavingLogSystemMessage(saveMethodName)); } List logEntryEvents = new List(); @@ -2553,20 +2585,25 @@ global with sharing class Logger { // This gives us a chance to run the handler class & handler plugins before insert, // allowing the plugins to make further changes to the `LogEntryEvent__e` records // So, execute the handler, which internally then executes any plugins - new LogEntryEventHandler().executeBeforeInsert(logEntryEvents); + LoggerTriggerableContext logEntryEventsBeforeContext = new LoggerTriggerableContext( + Schema.LogEntryEvent__e.SObjectType, + TriggerOperation.BEFORE_INSERT, + logEntryEvents + ); + LoggerSObjectHandler.getHandler(Schema.LogEntryEvent__e.SObjectType)?.overrideTriggerableContext(logEntryEventsBeforeContext).execute(); // Now that the plugins have run, double check to make sure that saving should still happen if (getBufferSize() == 0) { return; } - switch on saveMethod { + switch on getSaveMethod(saveMethodName) { when EVENT_BUS { - List saveResults = EventBus.publish(logEntryEvents); - LoggerEmailUtils.sendErrorEmail(Schema.LogEntryEvent__e.SObjectType, saveResults); + List saveResults = LoggerDataStore.getEventBus().publishRecords(logEntryEvents); + LoggerEmailSender.sendErrorEmail(Schema.LogEntryEvent__e.SObjectType, saveResults); } when QUEUEABLE { - System.enqueueJob(new QueueableSaver(logEntryEvents)); + LoggerDataStore.getJobQueue().enqueueJob(new QueueableSaver(logEntryEvents)); } when REST { // If the user doesn't have a session ID (e.g., site guest user), the REST API call will fail @@ -2578,7 +2615,12 @@ global with sharing class Logger { } } when SYNCHRONOUS_DML { - new LogEntryEventHandler().executeAfterInsert(logEntryEvents); + LoggerTriggerableContext logEntryEventsAfterContext = new LoggerTriggerableContext( + Schema.LogEntryEvent__e.SObjectType, + TriggerOperation.AFTER_INSERT, + logEntryEvents + ); + LoggerSObjectHandler.getHandler(Schema.LogEntryEvent__e.SObjectType)?.overrideTriggerableContext(logEntryEventsAfterContext).execute(); } } @@ -2593,42 +2635,18 @@ global with sharing class Logger { * @return The matching instance of LoggingLevel (or a default value if a match is not found) */ global static LoggingLevel getLoggingLevel(String loggingLevelName) { - if (loggingLevelName != null) { - loggingLevelName = loggingLevelName.trim().toUpperCase(); - } - - switch on loggingLevelName { - when 'NONE' { - return LoggingLevel.NONE; - } - when 'ERROR' { - return LoggingLevel.ERROR; - } - when 'WARN' { - return LoggingLevel.WARN; - } - when 'INFO' { - return LoggingLevel.INFO; - } - when 'DEBUG' { - return LoggingLevel.DEBUG; - } - when 'FINE' { - return LoggingLevel.FINE; - } - when 'FINER' { - return LoggingLevel.FINER; - } - when 'FINEST' { - return LoggingLevel.FINEST; - } - when else { - if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { - String message = 'Logger - Unknown logging level ' + loggingLevelName + 'specified, using ' + DEFAULT_LOGGING_LEVEL.name(); - finest(message); - } - return DEFAULT_LOGGING_LEVEL; + try { + return System.LoggingLevel.valueOf(loggingLevelName?.trim().toUpperCase()); + } catch (NoSuchElementException ex) { + if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { + LogMessage logMessage = new LogMessage( + 'Logger - Unknown logging level {0} specified, using {1}', + loggingLevelName, + DEFAULT_LOGGING_LEVEL.name() + ); + finest(logMessage); } + return DEFAULT_LOGGING_LEVEL; } } @@ -2728,33 +2746,19 @@ global with sharing class Logger { } } - private static SaveMethod getDefaultSaveMethod() { - SaveMethod defaultSaveMethod; - - String saveMethodName = getUserSettings().DefaultSaveMethod__c?.toUpperCase(); - switch on saveMethodName { - when 'QUEUEABLE' { - defaultSaveMethod = SaveMethod.QUEUEABLE; - } - when 'REST' { - defaultSaveMethod = SaveMethod.REST; - } - when 'SYNCHRONOUS_DML' { - defaultSaveMethod = SaveMethod.SYNCHRONOUS_DML; - } - when else { - defaultSaveMethod = SaveMethod.EVENT_BUS; - } + private static SaveMethod getSaveMethod(String saveMethodName) { + try { + return SaveMethod.valueOf(saveMethodName); + } catch (NoSuchElementException ex) { + return null; } - - return defaultSaveMethod; } private static String getSuspendSavingLogSystemMessage() { return 'Logger - Logging suspended, ignoring call to saveLog()'; } - private static String getSavingLogSystemMessage(SaveMethod saveMethod) { + private static String getSavingLogSystemMessage(String saveMethodName) { String savingLogMessage = 'Logger - Saving ' + LOG_ENTRIES_BUFFER.size() + ' log entries via '; switch on getCurrentQuiddity() { when ANONYMOUS { @@ -2788,7 +2792,12 @@ global with sharing class Logger { savingLogMessage += getCurrentQuiddity()?.name(); } } - savingLogMessage += ', save method is ' + saveMethod.name(); + savingLogMessage += ', save method is ' + saveMethodName; + savingLogMessage += + '. Logger.saveLog() has been called ' + + saveLogCallCount + + (saveLogCallCount == 1 ? ' time' : ' times') + + ' in the current transaction.'; return savingLogMessage; } @@ -2805,12 +2814,11 @@ global with sharing class Logger { } /** - * @description Required by the Queueable interface, this method contains the logic executed when - * the current instance of the queue runs. - * @param queueableContext The context of the current queue. + * @description Asynchronoulsy publishes the list of `LogEntryEvent__e` records + * @param queueableContext The context of the current queue, provided by the platform */ global void execute(System.QueueableContext queueableContext) { - EventBus.publish(this.logEntryEvents); + LoggerDataStore.getEventBus().publishRecords(this.logEntryEvents); } } diff --git a/nebula-logger/core/main/logger-engine/classes/LoggerDataStore.cls b/nebula-logger/core/main/logger-engine/classes/LoggerDataStore.cls new file mode 100644 index 000000000..623230546 --- /dev/null +++ b/nebula-logger/core/main/logger-engine/classes/LoggerDataStore.cls @@ -0,0 +1,295 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @group Logger Engine + * @description Class used to manage any data-related operations, including database DML statements, + * publishing platform events via the event bus, and enqueueing queueable jobs + */ +@SuppressWarnings('PMD.ApexCRUDViolation, PMD.CyclomaticComplexity, PMD.EmptyStatementBlock, PMD.ExcessivePublicCount, PMD.FieldDeclarationsShouldBeAtStart') +public without sharing class LoggerDataStore { + private static Database databaseInstance = new Database(); + private static EventBus eventBusInstance = new EventBus(); + private static JobQueue jobQueueInstance = new JobQueue(); + /** + * @description The instance `LoggerDataStore.Database` used for any DML + * operations in the current transaction. + * @return The singleton instance of `LoggerDataStore.Database` + */ + public static Database getDatabase() { + return databaseInstance; + } + + /** + * @description The instance `LoggerDataStore.EventBus` used for publishing + * platform events in the current transaction. + * @return The singleton instance of `LoggerDataStore.EventBus` + */ + public static EventBus getEventBus() { + return eventBusInstance; + } + + /** + * @description The instance `LoggerDataStore.JobQueue` used for enqueuing + * any queueable jobs in the current transaction. + * @return The singleton instance of `LoggerDataStore.JobQueue` + */ + public static JobQueue getJobQueue() { + return jobQueueInstance; + } + + @TestVisible + private static void setMock(Database mockDatabase) { + databaseInstance = mockDatabase; + } + + @TestVisible + private static void setMock(EventBus mockEventBus) { + eventBusInstance = mockEventBus; + } + + @TestVisible + private static void setMock(JobQueue mockJobQueue) { + jobQueueInstance = mockJobQueue; + } + + /** + * @description Class used to centralize the handling of any DML operations + */ + public virtual class Database { + protected Database() { + } + + /** + * @description Executes a `delete` DML operation for the `SObject` record + * @param record The `SObject` record to delete + * @return The instance of `Database.DeleteResult`, generated by the platform when deleting the record + */ + public virtual Database.DeleteResult deleteRecord(SObject record) { + return System.Database.delete(record); + } + + /** + * @description Executes a `delete` DML operation on the provided list of `SObject` records + * @param records The list of `SObject` records to delete + * @return The instance of `List`, generated by the platform when deleting the records + */ + public virtual List deleteRecords(List records) { + return System.Database.delete(records); + } + + /** + * @description Executes a `delete` DML operation on the provided list of `SObject` records + * @param records The list of `SObject` records to delete + * @param allOrNone Controls if all records must be deleted (`true`), or if partial deletion should be used (`false`) + * @return The instance of `List`, generated by the platform when deleting the records + */ + public virtual List deleteRecords(List records, Boolean allOrNone) { + return System.Database.delete(records, allOrNone); + } + + /** + * @description Executes a `delete` DML operation for the `SObject` record, followed by hard deleting the + * record using `Database.emptyRecycleBin(record)` + * @param record The `SObject` record to delete + * @return The instance of `Database.DeleteResult`, generated by the platform when deleting the record + */ + public virtual Database.DeleteResult hardDeleteRecord(SObject record) { + return this.hardDeleteRecords(new List{ record }).get(0); + } + + /** + * @description Executes a `delete` DML operation on the provided list of `SObject` records, followed by hard deleting the + * records using `Database.emptyRecycleBin(records)` + * @param records The list of `SObject` records to delete + * @return The instance of `List`, generated by the platform when deleting the records + */ + public virtual List hardDeleteRecords(List records) { + List results = this.deleteRecords(records); + if (records.isEmpty() == false) { + System.Database.emptyRecycleBin(records); + } + return results; + } + + /** + * @description Executes an `insert` DML operation on the provided `SObject` record + * @param record The `SObject` record to insert + * @return The instance of `Database.SaveResult`, generated by the platform when creating the record + */ + public virtual Database.SaveResult insertRecord(SObject record) { + return System.Database.insert(record); + } + + /** + * @description Executes an `insert` DML operation on the provided list of `SObject` records + * @param records The list of `SObject` records to insert + * @return The instance of `List`, generated by the platform when creating the records + */ + public virtual List insertRecords(List records) { + return System.Database.insert(records); + } + + /** + * @description Executes an `insert` DML operation on the provided list of `SObject` records + * @param records The list of `SObject` records to insert + * @param allOrNone Controls if all records must be created (`true`), or if partial creation should be used (`false`) + * @return The instance of `List`, generated by the platform when creating the records + */ + public virtual List insertRecords(List records, Boolean allOrNone) { + return System.Database.insert(records, allOrNone); + } + + /** + * @description Executes an `insert` DML operation on the provided list of `SObject` records + * @param records The list of `SObject` records to insert + * @param dmlOptions Controls additional DML options, using the provided instance of `Database.DmlOptions` + * @return The instance of `List`, generated by the platform when creating the records + */ + public virtual List insertRecords(List records, Database.DmlOptions dmlOptions) { + return System.Database.insert(records, dmlOptions); + } + + /** + * @description Executes an `undelete` DML operation on the provided `SObject` record + * @param record The `SObject` record to undelete + * @return The instance of `Database.UndeleteResult`, generated by the platform when undeleting the record + */ + public virtual Database.UndeleteResult undeleteRecord(SObject record) { + return System.Database.undelete(record); + } + + /** + * @description Executes an `undelete` DML operation on the provided list of `SObject` records + * @param records The list of `SObject` records to undelete + * @return The instance of `List`, generated by the platform when deleting the records + */ + public virtual List undeleteRecords(List records) { + return System.Database.undelete(records); + } + + /** + * @description Executes an `undelete` DML operation on the provided list of `SObject` records + * @param records The list of `SObject` records to undelete + * @param allOrNone Controls if all records must be undeleted (`true`), or if partial undeletion should be used (`false`) + * @return The instance of `List`, generated by the platform when undeleting the records + */ + public virtual List undeleteRecords(List records, Boolean allOrNone) { + return System.Database.undelete(records, allOrNone); + } + + /** + * @description Executes an `update` DML operation on the provided `SObject` record + * @param record The `SObject` record to update + * @return The instance of `Database.SaveResult`, generated by the platform when updating the record + */ + public virtual Database.SaveResult updateRecord(SObject record) { + return System.Database.update(record); + } + + /** + * @description Executes an `update` DML operation on the provided list of `SObject` records + * @param records The list of `SObject` records to update + * @return The instance of `List`, generated by the platform when updating the records + */ + public virtual List updateRecords(List records) { + return System.Database.update(records); + } + + /** + * @description Executes an `update` DML operation on the provided list of `SObject` records + * @param records The list of `SObject` records to update + * @param allOrNone Controls if all records must be updated (`true`), or if partial updates should be used (`false`) + * @return The instance of `List`, generated by the platform when updating the records + */ + public virtual List updateRecords(List records, Boolean allOrNone) { + return System.Database.update(records, allOrNone); + } + + /** + * @description Executes an `update` DML operation on the provided list of `SObject` records + * @param records The list of `SObject` records to update + * @param dmlOptions Controls additional DML options, using the provided instance of `Database.DmlOptions` + * @return The instance of `List`, generated by the platform when updating the records + */ + public virtual List updateRecords(List records, Database.DmlOptions dmlOptions) { + return System.Database.update(records, dmlOptions); + } + + /** + * @description Executes an `upsert` DML operation on the provided list of `SObject` records + * @param record The `SObject` record to update + * @param externalIdField The `SObjectField` of the external ID field on the target `SObject` to use for upserting + * @return The instance of `Database.UpsertResult`, generated by the platform when upserting the record + */ + public virtual Database.UpsertResult upsertRecord(SObject record, Schema.SObjectField externalIdField) { + return System.Database.upsert(record, externalIdField); + } + + /** + * @description Executes an `upsert` DML operation on the provided list of `SObject` records + * @param records The list of `SObject` records to upsert + * @param externalIdField The `SObjectField` of the external ID field on the target `SObject` to use for upserting + * @return The instance of `List`, generated by the platform when Upserting the records + */ + public virtual List upsertRecords(List records, Schema.SObjectField externalIdField) { + return System.Database.upsert(records, externalIdField); + } + + /** + * @description Executes an `upsert` DML operation on the provided list of `SObject` records + * @param records The list of `SObject` records to upsert + * @param externalIdField The `SObjectField` of the external ID field on the target `SObject` to use for upserting + * @param allOrNone Controls if all records must be updated (`true`), or if partial updates should be used (`false`) + * @return The instance of `List`, generated by the platform when Upserting the records + */ + public virtual List upsertRecords(List records, Schema.SObjectField externalIdField, Boolean allOrNone) { + return System.Database.upsert(records, externalIdField, allOrNone); + } + } + + /** + * @description Class used to centralize the handling of any platform event publishing operations + */ + public virtual class EventBus { + protected EventBus() { + } + + /** + * @description Publishes a single platform event record, using `EventBus.publish(SObject record); + * @param platformEvent The platform event record to publish + * @return The instance of `Database.SaveResult`, generated by the platform when publishing the platform event record + */ + public virtual Database.SaveResult publishRecord(SObject platformEvent) { + return System.EventBus.publish(platformEvent); + } + + /** + * @description Publishes a list of platform event records, using `EventBus.publish(List records); + * @param platformEvents The list of platform event records to publish + * @return The instance of `List`, generated by the platform when publishing the platform event records + */ + public virtual List publishRecords(List platformEvents) { + return System.EventBus.publish(platformEvents); + } + } + + /** + * @description Class used to centralize the handling of enqueueing any queueable jobs + */ + public virtual class JobQueue { + protected JobQueue() { + } + + /** + * @description Enqueues a queueable job to execute asynchronously, using `System.enqueueJob(Queueable queueableJob)` + * @param queueableJob An instance of a `Queueable` class that should be enqueued + * @return The `Id` of the queueable job + */ + public virtual Id enqueueJob(Queueable queueableJob) { + return System.enqueueJob(queueableJob); + } + } +} diff --git a/nebula-logger/core/tests/common/classes/LoggerTestUtils.cls-meta.xml b/nebula-logger/core/main/logger-engine/classes/LoggerDataStore.cls-meta.xml similarity index 100% rename from nebula-logger/core/tests/common/classes/LoggerTestUtils.cls-meta.xml rename to nebula-logger/core/main/logger-engine/classes/LoggerDataStore.cls-meta.xml diff --git a/nebula-logger/core/main/logger-engine/classes/LoggerSObjectHandler.cls b/nebula-logger/core/main/logger-engine/classes/LoggerSObjectHandler.cls new file mode 100644 index 000000000..878ac6d6e --- /dev/null +++ b/nebula-logger/core/main/logger-engine/classes/LoggerSObjectHandler.cls @@ -0,0 +1,287 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @group Logger Engine + * @description Abstract class used by trigger handlers for shared logic + */ +@SuppressWarnings('PMD.ApexCRUDViolation, PMD.CyclomaticComplexity, PMD.EmptyStatementBlock, PMD.FieldDeclarationsShouldBeAtStart') +public without sharing abstract class LoggerSObjectHandler { + private static Boolean isEnabled = true; + private static final Map> SOBJECT_TYPE_TO_EXECUTED_HANDLERS = new Map>(); + private static final Map SOBJECT_TYPE_TO_HANDLER_CONFIGURATIONS = queryHandlerConfigurations(); + + // Instance variables for top-level class + @TestVisible + protected LoggerTriggerableContext input { + get { + if (input == null) { + input = new LoggerTriggerableContext(this.getSObjectType(), this.triggerOperationType, this.triggerNew, this.triggerNewMap, this.triggerOldMap); + } + return input; + } + set; + } + + @TestVisible + private TriggerOperation triggerOperationType; + @TestVisible + private List triggerNew; + @TestVisible + private Map triggerNewMap; + @TestVisible + private Map triggerOldMap; + @TestVisible + private LoggerSObjectHandler__mdt handlerConfiguration; + private List pluginConfigurations = new List(); + private List executedApexPlugins = new List(); + private List executedFlowPlugins = new List(); + + /** + * @description Returns an instance of `LoggerSObjectHandler` that has been built & configured for the specified `SObjectType` + * @param sobjectType The instance `SObjectType` to check for a configured instance of `LoggerSObjectHandler` + * @return The Apex class that extends `LoggerSObjectHandler` and has been configured for the specified `SObjectType` + */ + public static LoggerSObjectHandler getHandler(Schema.SObjectType sobjectType) { + return getHandler(sobjectType, null); + } + + /** + * @description Returns an instance of `LoggerSObjectHandler` that has been built & configured for the specified `SObjectType` + * @param sobjectType The instance `SObjectType` to check for a configured instance of `LoggerSObjectHandler` + * @param defaultImplementation A default implementation of `LoggerSObjectHandler` that should be used, if a configuration cannot be found `LoggerSObjectHandler__mdt` + * @return The Apex class that extends `LoggerSObjectHandler` and has been configured for the specified `SObjectType` + */ + public static LoggerSObjectHandler getHandler(Schema.SObjectType sobjectType, LoggerSObjectHandler defaultImplementation) { + String handlerApexClassName = getHandlerConfiguration(sobjectType)?.SObjectHandlerApexClass__c; + // TODO need to handle namespace prefix for Apex classes + return handlerApexClassName == null ? defaultImplementation : (LoggerSObjectHandler) Type.forName(handlerApexClassName)?.newInstance(); + } + + /** + * @description Default constructor + */ + public LoggerSObjectHandler() { + this.triggerOperationType = Trigger.operationType; + this.triggerNew = Trigger.new; + this.triggerNewMap = Trigger.newMap; + this.triggerOldMap = Trigger.oldMap; + this.handlerConfiguration = SOBJECT_TYPE_TO_HANDLER_CONFIGURATIONS.get(this.getSObjectType()); + this.pluginConfigurations = LoggerPlugin.getFilteredPluginConfigurations( + new List{ Schema.LoggerPlugin__mdt.SObjectHandlerApexClass__c, Schema.LoggerPlugin__mdt.SObjectHandlerFlowName__c }, + Schema.LoggerPlugin__mdt.SObjectHandlerExecutionOrder__c + ); + } + + /** + * @description Returns the SObject Type that the handler is responsible for processing + * @return The instance of `SObjectType` + */ + public abstract Schema.SObjectType getSObjectType(); + + /** + * @description Provides the ability to override the instance `LoggerTriggerableContext` that is normally + * provided internally by `LoggerSObjectHandler` + * @param input The instance of `LoggerTriggerableContext` to use within the trigger handler class + * @return The same instance of `LoggerSObjectHandler`, useful for chaining methods + */ + public LoggerSObjectHandler overrideTriggerableContext(LoggerTriggerableContext input) { + this.input = input; + return this; + } + + /** + * @description Runs the handler class's logic, as well as any configured plugins + */ + public void execute() { + if (System.Test.isRunningTest() == true && SOBJECT_TYPE_TO_EXECUTED_HANDLERS.containsKey(this.getSObjectType()) == false) { + SOBJECT_TYPE_TO_EXECUTED_HANDLERS.put(this.getSObjectType(), new List()); + } + + Boolean shouldExecute = isEnabled && (this.handlerConfiguration == null || this.handlerConfiguration.IsEnabled__c == true); + if (shouldExecute == false) { + return; + } + + switch on this.input.triggerOperationType { + when BEFORE_INSERT { + this.executeBeforeInsert(this.input.triggerNew); + } + when BEFORE_UPDATE { + this.executeBeforeUpdate(this.input.triggerNewMap, this.input.triggerOldMap); + } + when BEFORE_DELETE { + this.executeBeforeDelete(this.input.triggerNewMap); + } + when AFTER_INSERT { + // Platform Events don't have an ID field, thus Trigger.newMap doesn't work for LogEntryEvent__e + // For custom objects, Map is more convenient since it provides both the keys & values + // 2 AFTER_INSERT methods are used here in the framework, with the expectation that only 1 will be implemented per handler class + this.executeAfterInsert(this.input.triggerNew); + this.executeAfterInsert(this.input.triggerNewMap); + } + when AFTER_UPDATE { + this.executeAfterUpdate(this.input.triggerNewMap, this.input.triggerOldMap); + } + when AFTER_DELETE { + this.executeAfterDelete(this.input.triggerNewMap); + } + when AFTER_UNDELETE { + this.executeAfterUndelete(this.input.triggerNewMap); + } + } + + this.executePlugins(); + + if (System.Test.isRunningTest() == true) { + SOBJECT_TYPE_TO_EXECUTED_HANDLERS.get(this.getSObjectType()).add(this); + } + } + + protected virtual void executeBeforeInsert(List triggerNew) { + } + + protected virtual void executeBeforeUpdate(Map triggerNewMap, Map triggerOldMap) { + } + + protected virtual void executeBeforeDelete(Map triggerNewMap) { + } + + // executeAfterInsert(List triggerNew) { + } + + protected virtual void executeAfterInsert(Map triggerNewMap) { + } + + protected virtual void executeAfterUpdate(Map triggerNewMap, Map triggerOldMap) { + } + + protected virtual void executeAfterDelete(Map triggerNewMap) { + } + + protected virtual void executeAfterUndelete(Map triggerNewMap) { + } + + private void executePlugins() { + if (this.pluginConfigurations == null || this.pluginConfigurations.isEmpty() == true) { + return; + } + + for (LoggerPlugin__mdt pluginConfiguration : this.pluginConfigurations) { + if (String.isNotBlank(pluginConfiguration.SObjectHandlerApexClass__c)) { + this.executeApexPlugin(pluginConfiguration); + } + if (String.isNotBlank(pluginConfiguration.SObjectHandlerFlowName__c)) { + this.executeFlowPlugin(pluginConfiguration); + } + } + } + + @SuppressWarnings('PMD.AvoidDebugStatements') + private void executeApexPlugin(LoggerPlugin__mdt configuration) { + try { + LoggerPlugin.Triggerable apexPlugin = LoggerPlugin.newTriggerableInstance(configuration.SObjectHandlerApexClass__c); + apexPlugin?.execute(configuration, this.input); + + if (System.Test.isRunningTest() == true && apexPlugin != null) { + this.executedApexPlugins.add(apexPlugin); + } + } catch (TypeException ex) { + if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { + Logger.warn('Unknown Apex class ' + configuration.SObjectHandlerApexClass__c + ', skipping plugin execution', configuration, ex); + } + } + } + + @SuppressWarnings('PMD.AvoidDebugStatements') + private void executeFlowPlugin(LoggerPlugin__mdt configuration) { + try { + Map flowInputs = new Map(); + flowInputs.put('pluginConfiguration', configuration); + flowInputs.put('pluginInput', this.input); + + Flow.Interview flowPlugin = Flow.Interview.createInterview(configuration.SObjectHandlerFlowName__c, flowInputs); + flowPlugin.start(); + + List updatedTriggerNew = (List) flowPlugin.getVariableValue('updatedTriggerNew'); + if (updatedTriggerNew != null && updatedTriggerNew.size() == this.input.triggerNew.size()) { + this.input.triggerNew.clear(); + this.input.triggerNew.addAll(updatedTriggerNew); + if (this.input.triggerNewMap != null) { + this.input.triggerNewMap.clear(); + this.input.triggerNewMap.putAll(new Map(updatedTriggerNew)); + } + } + if (System.Test.isRunningTest() == true && flowPlugin != null) { + this.executedFlowPlugins.add(flowPlugin); + } + } catch (TypeException ex) { + if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { + Logger.warn('Unknown Flow ' + configuration.SObjectHandlerFlowName__c + ', skipping plugin execution', configuration, ex); + } + } + } + + // Instance test helper methods, used for unit tests + @TestVisible + private List getPluginConfigurations() { + return this.pluginConfigurations; + } + + @TestVisible + private List getExecutedApexPlugins() { + return this.executedApexPlugins; + } + + @TestVisible + private List getExecutedFlowPlugins() { + return this.executedFlowPlugins; + } + + // Static test helper methods, used for integration tests + @TestVisible + private static Map> getExecutedHandlers() { + return SOBJECT_TYPE_TO_EXECUTED_HANDLERS; + } + + private static Map queryHandlerConfigurations() { + Map sobjectTypeToHandlerConfiguration = new Map(); + for (LoggerSObjectHandler__mdt handlerConfiguration : [ + SELECT IsEnabled__c, SObjectHandlerApexClass__c, SObjectType__r.QualifiedApiName + FROM LoggerSObjectHandler__mdt + WHERE IsEnabled__c = TRUE + ]) { + handlerConfiguration.SObjectType__c = handlerConfiguration.SObjectType__r.QualifiedApiName; + Schema.SObjectType sobjectType = ((SObject) Type.forName(handlerConfiguration.SObjectType__c).newInstance()).getSObjectType(); + sobjectTypeToHandlerConfiguration.put(sobjectType, handlerConfiguration); + } + + if (System.Test.isRunningTest() == true) { + sobjectTypeToHandlerConfiguration.clear(); + } + + return sobjectTypeToHandlerConfiguration; + } + + @TestVisible + private static LoggerSObjectHandler__mdt getHandlerConfiguration(Schema.SObjectType sobjectType) { + return SOBJECT_TYPE_TO_HANDLER_CONFIGURATIONS.get(sobjectType); + } + + @TestVisible + private static void setMock(LoggerSObjectHandler__mdt handlerConfiguration) { + //TODO cleanup code duplication + Schema.SObjectType sobjectType = ((SObject) Type.forName(handlerConfiguration.SObjectType__c).newInstance()).getSObjectType(); + SOBJECT_TYPE_TO_HANDLER_CONFIGURATIONS.put(sobjectType, handlerConfiguration); + } + + @TestVisible + private static void shouldExecute(Boolean shouldExecute) { + // Only used for testing purposes so tests can disable triggers to speed up + // DML statements that don't rely on trigger logic to run + isEnabled = shouldExecute; + } +} diff --git a/nebula-logger/core/tests/configuration/classes/LoggerEmailUtils_Tests.cls-meta.xml b/nebula-logger/core/main/logger-engine/classes/LoggerSObjectHandler.cls-meta.xml similarity index 100% rename from nebula-logger/core/tests/configuration/classes/LoggerEmailUtils_Tests.cls-meta.xml rename to nebula-logger/core/main/logger-engine/classes/LoggerSObjectHandler.cls-meta.xml diff --git a/nebula-logger/core/main/logger-engine/classes/LoggerTriggerableContext.cls b/nebula-logger/core/main/logger-engine/classes/LoggerTriggerableContext.cls new file mode 100644 index 000000000..da870609f --- /dev/null +++ b/nebula-logger/core/main/logger-engine/classes/LoggerTriggerableContext.cls @@ -0,0 +1,87 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @group Logger Engine + * @description Class used by the logging system for trigger contextual details + * @see LoggerSObjectHandler + * @see LoggerPlugin + */ +@SuppressWarnings('PMD.ApexDoc, PMD.ExcessiveParameterList') +public without sharing class LoggerTriggerableContext { + public Schema.SObjectType sobjectType { get; private set; } + public TriggerOperation triggerOperationType { get; private set; } + public List triggerNew { get; private set; } + public Map triggerNewMap { get; private set; } + public Map triggerOldMap { get; private set; } + + @AuraEnabled + public String sobjectTypeName { get; private set; } + + @AuraEnabled + public String triggerOperationTypeName { get; private set; } + + @AuraEnabled + public List triggerRecords { get; private set; } + + public LoggerTriggerableContext(Schema.SObjectType sobjectType, TriggerOperation triggerOperationType, List triggerNew) { + this(sobjectType, triggerOperationType, triggerNew, null, null); + } + + public LoggerTriggerableContext( + Schema.SObjectType sobjectType, + TriggerOperation triggerOperationType, + List triggerNew, + Map triggerNewMap, + Map triggerOldMap + ) { + // Trigger variables for Apex Developers + this.sobjectType = sobjectType; + this.triggerOperationType = triggerOperationType; + this.triggerNew = triggerNew; + this.triggerNewMap = triggerNewMap; + this.triggerOldMap = triggerOldMap; + + this.setupAdditionalProperties(); + } + + private void setupAdditionalProperties() { + // Additional invocable variables for Flow Builders (and Apex Developers too, if they want to use them) + this.sobjectTypeName = this.sobjectType.getDescribe().getName(); + this.triggerOperationTypeName = this.triggerOperationType?.name(); + this.triggerRecords = new List(); + if (this.triggerNew != null) { + for (SObject record : this.triggerNew) { + LoggerTriggerableContext.RecordInput recordInput = new LoggerTriggerableContext.RecordInput(); + recordInput.triggerRecordNew = record; + if (this.triggerOldMap != null && record.Id != null) { + recordInput.triggerRecordOld = this.triggerOldMap.get(record.Id); + } + + this.triggerRecords.add(recordInput); + } + } else if (this.triggerOldMap != null) { + for (SObject record : this.triggerOldMap.values()) { + LoggerTriggerableContext.RecordInput recordInput = new LoggerTriggerableContext.RecordInput(); + recordInput.triggerRecordOld = record; + + this.triggerRecords.add(recordInput); + } + } + } + + /** + * @description Class used by the logging system to provide trigger record details to Flow + */ + public class RecordInput { + @AuraEnabled + public SObject triggerRecordNew { get; private set; } + + @AuraEnabled + public SObject triggerRecordOld { get; private set; } + } + + // TODO add a constructor & move logic from LoggerSObjectHandler --> no longer a DTO? +} diff --git a/nebula-logger/core/tests/plugin-framework/classes/LoggerSObjectHandlerPlugin_Tests.cls-meta.xml b/nebula-logger/core/main/logger-engine/classes/LoggerTriggerableContext.cls-meta.xml similarity index 100% rename from nebula-logger/core/tests/plugin-framework/classes/LoggerSObjectHandlerPlugin_Tests.cls-meta.xml rename to nebula-logger/core/main/logger-engine/classes/LoggerTriggerableContext.cls-meta.xml diff --git a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/DatabaseResultCollectionSize__c.field-meta.xml b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/DatabaseResultCollectionSize__c.field-meta.xml new file mode 100644 index 000000000..3198c288d --- /dev/null +++ b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/DatabaseResultCollectionSize__c.field-meta.xml @@ -0,0 +1,15 @@ + + + DatabaseResultCollectionSize__c + The number of items contained in the collection of database results + false + false + false + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpRequestBodyMasked__c.field-meta.xml b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpRequestBodyMasked__c.field-meta.xml new file mode 100644 index 000000000..7e5541ea5 --- /dev/null +++ b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpRequestBodyMasked__c.field-meta.xml @@ -0,0 +1,11 @@ + + + HttpRequestBodyMasked__c + false + false + false + false + false + + Checkbox + diff --git a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpRequestBody__c.field-meta.xml b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpRequestBody__c.field-meta.xml new file mode 100644 index 000000000..50414a97a --- /dev/null +++ b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpRequestBody__c.field-meta.xml @@ -0,0 +1,11 @@ + + + HttpRequestBody__c + false + + 131072 + false + false + LongTextArea + 5 + diff --git a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpRequestCompressed__c.field-meta.xml b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpRequestCompressed__c.field-meta.xml new file mode 100644 index 000000000..ebf8828f6 --- /dev/null +++ b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpRequestCompressed__c.field-meta.xml @@ -0,0 +1,10 @@ + + + HttpRequestCompressed__c + false + false + + false + false + Checkbox + diff --git a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpRequestEndpoint__c.field-meta.xml b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpRequestEndpoint__c.field-meta.xml new file mode 100644 index 000000000..f50bbbd77 --- /dev/null +++ b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpRequestEndpoint__c.field-meta.xml @@ -0,0 +1,12 @@ + + + HttpRequestEndpoint__c + false + + 255 + false + false + false + Text + false + diff --git a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpRequestMethod__c.field-meta.xml b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpRequestMethod__c.field-meta.xml new file mode 100644 index 000000000..2523f3b51 --- /dev/null +++ b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpRequestMethod__c.field-meta.xml @@ -0,0 +1,12 @@ + + + HttpRequestMethod__c + false + + 255 + false + false + false + Text + false + diff --git a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpResponseBodyMasked__c.field-meta.xml b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpResponseBodyMasked__c.field-meta.xml new file mode 100644 index 000000000..b4d22a354 --- /dev/null +++ b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpResponseBodyMasked__c.field-meta.xml @@ -0,0 +1,11 @@ + + + HttpResponseBodyMasked__c + false + false + false + false + false + + Checkbox + diff --git a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpResponseBody__c.field-meta.xml b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpResponseBody__c.field-meta.xml new file mode 100644 index 000000000..b0f892ac1 --- /dev/null +++ b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpResponseBody__c.field-meta.xml @@ -0,0 +1,11 @@ + + + HttpResponseBody__c + false + + 131072 + false + false + LongTextArea + 5 + diff --git a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpResponseHeaderKeys__c.field-meta.xml b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpResponseHeaderKeys__c.field-meta.xml new file mode 100644 index 000000000..d5ca1263f --- /dev/null +++ b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpResponseHeaderKeys__c.field-meta.xml @@ -0,0 +1,11 @@ + + + HttpResponseHeaderKeys__c + false + + 1000 + false + false + LongTextArea + 5 + diff --git a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpResponseStatusCode__c.field-meta.xml b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpResponseStatusCode__c.field-meta.xml new file mode 100644 index 000000000..d3f8431d7 --- /dev/null +++ b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpResponseStatusCode__c.field-meta.xml @@ -0,0 +1,13 @@ + + + HttpResponseStatusCode__c + false + + 10 + false + 0 + false + false + Number + false + diff --git a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpResponseStatus__c.field-meta.xml b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpResponseStatus__c.field-meta.xml new file mode 100644 index 000000000..a12ff395e --- /dev/null +++ b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/HttpResponseStatus__c.field-meta.xml @@ -0,0 +1,12 @@ + + + HttpResponseStatus__c + false + + 255 + false + false + false + Text + false + diff --git a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/LoginDomain__c.field-meta.xml b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/LoginDomain__c.field-meta.xml index 29706601a..50ba6cd74 100644 --- a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/LoginDomain__c.field-meta.xml +++ b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/LoginDomain__c.field-meta.xml @@ -1,6 +1,7 @@ LoginDomain__c + DeprecateCandidate false false false diff --git a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/RecordCollectionSize__c.field-meta.xml b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/RecordCollectionSize__c.field-meta.xml new file mode 100644 index 000000000..1440e138d --- /dev/null +++ b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/RecordCollectionSize__c.field-meta.xml @@ -0,0 +1,15 @@ + + + RecordCollectionSize__c + The number of items contained in the collection of database results + false + false + false + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/Topics__c.field-meta.xml b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/Topics__c.field-meta.xml index b83ece151..bea48807e 100644 --- a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/Topics__c.field-meta.xml +++ b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/Topics__c.field-meta.xml @@ -1,6 +1,7 @@ Topics__c + DeprecateCandidate false false false diff --git a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/TransactionEntryNumber__c.field-meta.xml b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/TransactionEntryNumber__c.field-meta.xml index 1a57a3a12..c2e58be1b 100644 --- a/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/TransactionEntryNumber__c.field-meta.xml +++ b/nebula-logger/core/main/logger-engine/objects/LogEntryEvent__e/fields/TransactionEntryNumber__c.field-meta.xml @@ -6,7 +6,7 @@ false false false - + 10 true 0 diff --git a/nebula-logger/core/main/plugin-framework/classes/LoggerSObjectHandlerPlugin.cls b/nebula-logger/core/main/plugin-framework/classes/LoggerSObjectHandlerPlugin.cls deleted file mode 100644 index 6be6df44a..000000000 --- a/nebula-logger/core/main/plugin-framework/classes/LoggerSObjectHandlerPlugin.cls +++ /dev/null @@ -1,41 +0,0 @@ -//------------------------------------------------------------------------------------------------// -// This file is part of the Nebula Logger project, released under the MIT License. // -// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // -//------------------------------------------------------------------------------------------------// - -/** - * @group Plugin Framework - * @description Abstract class used to create custom Apex plugins to execute for all trigger operations on `Log__c` or `LogEntry__c` - */ -// TODO: If possible, convert to `global` for the managed package - there are some additional platform limitations -// and restrictions with making future changes to abstract classes & interfaces within managed packages -// which could lead to a lot of problems, so for now/indefinitely, plugins will only work in the unlocked package -public abstract class LoggerSObjectHandlerPlugin { - /** - * @description All instances of `LoggerSObjectHandlerPlugin` are dynamically created, which requires a parameterless constructor - */ - @SuppressWarnings('PMD.EmptyStatementBlock') - public LoggerSObjectHandlerPlugin() { - } - - /** - * @description This method is the entry point for plugins to execute any custom logic. - * It is automatically called by the logging system for any enabled plugins. - * Several trigger-based parameters are provided - these parameters should be used by plugins, - * instead of calling the platform's static variables directly - * (e.g., use the provided `triggerNew` variable instead of using `Trigger.new` directly, and so on). - * @param triggerOperationType The enum instance of `Trigger.operationType` at the time that the handler class is created - * @param triggerNew The value `Trigger.new` at the time that the handler class is created - * @param triggerNewMap The value `Trigger.newMap` at the time that the handler class is created - * @param triggerOld The value `Trigger.old` at the time that the handler class is created - * @param triggerOldMap The value `Trigger.oldMap` at the time that the handler class is created - */ - @SuppressWarnings('PMD.ExcessiveParameterList') - public abstract void execute( - TriggerOperation triggerOperationType, - List triggerNew, - Map triggerNewMap, - List triggerOld, - Map triggerOldMap - ); -} diff --git a/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/PluginApiName__c.field-meta.xml b/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/PluginApiName__c.field-meta.xml deleted file mode 100644 index 32c04aa55..000000000 --- a/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/fields/PluginApiName__c.field-meta.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - PluginApiName__c - The API name of the metadata to run, based on the Plugin Type - -Apex: The name of an Apex class that implements the interface LoggerSObjectHandlerPlugin - -Flow: The API name of a Flow that supports these inputs: - - triggerOperationType: text variable - - triggerNew: record collection variable - - triggerOld: record collection variable - false - DeveloperControlled - The API name of the metadata to run, based on the Plugin Type - -Apex: The name of an Apex class that implements the interface LoggerSObjectHandlerPlugin - -Flow: The API name of a Flow that supports these inputs: - - triggerOperationType: text variable - - triggerNew: record collection variable - - triggerOld: record collection variable - - 255 - true - Text - false - diff --git a/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/validationRules/Plugins_are_not_supported.validationRule-meta.xml b/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/validationRules/Plugins_are_not_supported.validationRule-meta.xml deleted file mode 100644 index 2eef81563..000000000 --- a/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/validationRules/Plugins_are_not_supported.validationRule-meta.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - Plugins_are_not_supported - true - AND( - SObjectType__r.DeveloperName != 'LogEntryEvent', - SObjectType__r.DeveloperName != 'Log', - SObjectType__r.DeveloperName != 'LogEntry', - SObjectType__r.DeveloperName != 'LogEntryTag', - SObjectType__r.DeveloperName != 'LoggerTag' -) - SObjectType__c - Plugins are not supported for this SObject Handler - diff --git a/nebula-logger/core/tests/LoggerCore.testSuite-meta.xml b/nebula-logger/core/tests/LoggerCore.testSuite-meta.xml new file mode 100644 index 000000000..f1e0c16a2 --- /dev/null +++ b/nebula-logger/core/tests/LoggerCore.testSuite-meta.xml @@ -0,0 +1,30 @@ + + + ComponentLogger_Tests + FlowCollectionLogEntry_Tests + FlowLogEntry_Tests + FlowLogger_Tests + FlowRecordLogEntry_Tests + LogBatchPurger_Tests + LogBatchPurgeScheduler_Tests + LogEntryEventBuilder_Tests + LogEntryEventHandler_Tests + LogEntryFieldSetPicklist_Tests + LogEntryHandler_Tests + LogEntryTagHandler_Tests + LoggerBatchableContext_Tests + LoggerDataStore_Tests + LoggerEmailSender_Tests + LoggerParameter_Tests + LoggerPlugin_Tests + LoggerSettingsController_Tests + LoggerSObjectHandler_Tests + LoggerSObjectMetadata_Tests + LoggerTagHandler_Tests + LoggerTriggerableContext_Tests + Logger_Tests + LogHandler_Tests + LogMassDeleteExtension_Tests + LogMessage_Tests + RelatedLogEntriesController_Tests + diff --git a/nebula-logger/core/tests/common/classes/LoggerTestUtils.cls b/nebula-logger/core/tests/common/classes/LoggerTestUtils.cls deleted file mode 100644 index 7f172c947..000000000 --- a/nebula-logger/core/tests/common/classes/LoggerTestUtils.cls +++ /dev/null @@ -1,256 +0,0 @@ -//------------------------------------------------------------------------------------------------// -// This file is part of the Nebula Logger project, released under the MIT License. // -// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // -//------------------------------------------------------------------------------------------------// - -@SuppressWarnings('PMD.MethodNamingConventions, PMD.PropertyNamingConventions') -@IsTest -public class LoggerTestUtils { - private static final Map SOBJECT_TYPE_TO_MOCK_ID_COUNT = new Map(); - - // Lazy-load & cache permission sets & profiles - private static final Map PERMISSION_SETS_BY_NAME { - get { - if (PERMISSION_SETS_BY_NAME == null) { - PERMISSION_SETS_BY_NAME = queryPermissionSets(); - } - return PERMISSION_SETS_BY_NAME; - } - private set; - } - - private static final PermissionSet LOGGER_ADMIN_PERMISSION_SET { - get { - if (LOGGER_ADMIN_PERMISSION_SET == null) { - LOGGER_ADMIN_PERMISSION_SET = PERMISSION_SETS_BY_NAME.get('LoggerAdmin'); - } - return LOGGER_ADMIN_PERMISSION_SET; - } - private set; - } - - private static final PermissionSet LOGGER_LOG_VIEWER_PERMISSION_SET { - get { - if (LOGGER_LOG_VIEWER_PERMISSION_SET == null) { - LOGGER_LOG_VIEWER_PERMISSION_SET = PERMISSION_SETS_BY_NAME.get('LoggerLogViewer'); - } - return LOGGER_LOG_VIEWER_PERMISSION_SET; - } - private set; - } - - private static final PermissionSet LOGGER_END_USER_PERMISSION_SET { - get { - if (LOGGER_END_USER_PERMISSION_SET == null) { - LOGGER_END_USER_PERMISSION_SET = PERMISSION_SETS_BY_NAME.get('LoggerEndUser'); - } - return LOGGER_END_USER_PERMISSION_SET; - } - private set; - } - - private static final PermissionSet LOGGER_LOG_CREATOR_PERMISSION_SET { - get { - if (LOGGER_LOG_CREATOR_PERMISSION_SET == null) { - LOGGER_LOG_CREATOR_PERMISSION_SET = PERMISSION_SETS_BY_NAME.get('LoggerLogCreator'); - } - return LOGGER_LOG_CREATOR_PERMISSION_SET; - } - private set; - } - - /** - * @description Assigns the permission set `LoggerAdmin` to the specified user ID - * @param userId The ID of the user that should be assigned the permission set - */ - public static void assignAdminPermissionSet(Id userId) { - assignPermissionSet(userId, LOGGER_ADMIN_PERMISSION_SET); - } - - /** - * @description Assigns the permission set `LoggerLogViewer` to the specified user ID - * @param userId The ID of the user that should be assigned the permission set - */ - public static void assignLogViewerPermissionSet(Id userId) { - assignPermissionSet(userId, LOGGER_LOG_VIEWER_PERMISSION_SET); - } - - /** - * @description Assigns the permission set `LoggerEndUser` to the specified user ID - * @param userId The ID of the user that should be assigned the permission set - */ - public static void assignEndUserPermissionSet(Id userId) { - assignPermissionSet(userId, LOGGER_END_USER_PERMISSION_SET); - } - - /** - * @description Assigns the permission set `LoggerLogCreator` to the specified user ID - * @param userId The ID of the user that should be assigned the permission set - */ - public static void assignLogCreatorPermissionSet(Id userId) { - assignPermissionSet(userId, LOGGER_LOG_CREATOR_PERMISSION_SET); - } - - /** - * @description Instances of `AggregateResult` can not be created directly in Apex. - * This method uses a workaround to generate a mock. - * @return The mock instance of `AggregateResult` - */ - public static AggregateResult createMockAggregateResult() { - Map defaultMockAggregateKeyValues = new Map{ - 'fieldAvg' => 62.5, - 'fieldMax' => 100, - 'fieldMin' => 25, - 'fieldCount' => 4 - }; - return createMockAggregateResult(defaultMockAggregateKeyValues); - } - - /** - * @description Instances of `AggregateResult` can not be created directly in Apex. - * This method uses a workaround to generate a mock, using the provided map of aliases & aggregate values - * @param mockAggregateKeyValues A map of aliases & aggregate values to use when creating the mock `AggregateResult` - * @return The mock instance of `AggregateResult` - */ - public static AggregateResult createMockAggregateResult(Map mockAggregateKeyValues) { - return (AggregateResult) JSON.deserialize(JSON.serialize(mockAggregateKeyValues), AggregateResult.class); - } - - /** - * @description Generates a mock record ID for the provided SObject Type - * @param sobjectType The SObject Type for the generated mock record ID - * @return The mock record ID for the specified SObject Type - */ - public static String createMockId(Schema.SObjectType sobjectType) { - Integer recordIdNumber = 1; - if (SOBJECT_TYPE_TO_MOCK_ID_COUNT.containsKey(sobjectType)) { - recordIdNumber = SOBJECT_TYPE_TO_MOCK_ID_COUNT.get(sobjectType); - } - String recordIdSuffix = String.valueOf(recordIdNumber++); - SOBJECT_TYPE_TO_MOCK_ID_COUNT.put(sobjectType, recordIdNumber); - - String recordIdKeyPrefix = sobjectType.getDescribe().getKeyPrefix(); - Integer idFieldLength = sobjectType.getDescribe().fields.getMap().get('Id').getDescribe().getLength(); - Integer recordIdCenterLength = idFieldLength - recordIdKeyPrefix.length() - recordIdSuffix.length(); - return recordIdKeyPrefix + '0'.repeat(recordIdCenterLength) + recordIdSuffix; - } - - /** - * @description Creates a `User` record for testing purposes, using the current user's profile - * @return The generated `User` record - it is not automatically inserted into the database. - */ - public static User createUser() { - return createUser(UserInfo.getProfileId()); - } - - /** - * @description Creates a `User` record for testing purposes, using the specified profile ID - * @param profileId The `Profile` ID to use for the created `User` - * @return The generated `User` record - it is not automatically inserted into the database. - */ - public static User createUser(Id profileId) { - return new User( - Alias = 'log_xyz', - Email = 'logger_xyz@test.com.net.org', - EmailEncodingKey = 'ISO-8859-1', - LanguageLocaleKey = 'en_US', - LastName = 'Logger test user', - LocaleSidKey = 'en_US', - ProfileId = profileId, - TimeZoneSidKey = 'America/Los_Angeles', - Username = 'logger_xyz@test.com.net.org' - ); - } - - /** - * @description Queries for the `Organization` record for the current environment. - * @return The matching `Organization` record - */ - public static Organization getOrganization() { - return [SELECT Id, Name, InstanceName, IsSandbox, NamespacePrefix, OrganizationType, TrialExpirationDate FROM Organization]; - } - - /** - * @description Returns the current environment's type - Scratch Org, Sandbox, or Production. - * @return The environment type - */ - public static String getOrganizationEnvironmentType() { - Organization organization = getOrganization(); - - String orgEnvironmentType; - if (organization.IsSandbox == true && organization.TrialExpirationDate != null) { - orgEnvironmentType = 'Scratch Org'; - } else if (organization.IsSandbox == true) { - orgEnvironmentType = 'Sandbox'; - } else { - orgEnvironmentType = 'Production'; - } - return orgEnvironmentType; - } - - /** - * @description Returns the current user's `Network` (Experience Cloud site) - * @return The matching `Network` record - */ - public static SObject getNetwork() { - if (Network.getNetworkId() == null) { - return null; - } - - String networkApiName = 'Network'; - // Networks (communities) may not be enabled in the org (no Network object), so run everything dynamically - Boolean networksEnabled = Schema.getGlobalDescribe().containsKey(networkApiName); - - if (!networksEnabled) { - return null; - } - - String query = 'SELECT Id, Name, UrlPathPrefix FROM Network WHERE Id = :Network.getNetworkId()'; - return Database.query(String.escapeSingleQuotes(query)); - } - - /** - * @description Returns the current user - * @return The matching `User` record - */ - public static User getCurrentUser() { - return [ - SELECT Id, Profile.Name, Profile.UserLicenseId, Profile.UserLicense.LicenseDefinitionKey, Profile.UserLicense.Name, Username, UserRole.Name - FROM User - WHERE Id = :UserInfo.getUserId() - ]; - } - - /** - * @description Creates and inserts a `Group` record for testing queues, using the specified SObject Type - * @param sobjectType The SObjectType that the queue should be able to own (stored in `QueueSObject`) - * @return The inserted `Group` record - it is automatically inserted into the database, as well as 1 child `QueueSObject` record. - */ - public static Group insertQueue(Schema.SObjectType sobjectType) { - Group loggerQueue = new Group(DeveloperName = 'Some_Log_Queue', Name = 'Some Log Queue', Type = 'Queue'); - insert loggerQueue; - - // To avoid a MIXED_DML_OPERATION exception, use System.runs() for inserting the QueueSObject record - System.runAs(new User(Id = UserInfo.getUserId())) { - QueueSObject loggerQueueSObject = new QueueSObject(QueueId = loggerQueue.Id, SObjectType = sobjectType.getDescribe().getName()); - insert loggerQueueSObject; - } - - return loggerQueue; - } - - // Helper methods - private static void assignPermissionSet(Id userId, PermissionSet permissionSet) { - PermissionSetAssignment permissionSetAssignment = new PermissionSetAssignment(AssigneeId = userId, PermissionSetId = permissionSet.Id); - insert permissionSetAssignment; - } - - private static Map queryPermissionSets() { - List permissionSetNames = new List{ 'LoggerAdmin', 'LoggerLogViewer', 'LoggerEndUser', 'LoggerLogCreator' }; - Map results = new Map(); - for (PermissionSet permissionSet : [SELECT Id, Name FROM PermissionSet WHERE Name IN :permissionSetNames]) { - results.put(permissionSet.Name, permissionSet); - } - return results; - } -} diff --git a/nebula-logger/core/tests/configuration/classes/LoggerEmailUtils_Tests.cls b/nebula-logger/core/tests/configuration/classes/LoggerEmailUtils_Tests.cls deleted file mode 100644 index 1c9250291..000000000 --- a/nebula-logger/core/tests/configuration/classes/LoggerEmailUtils_Tests.cls +++ /dev/null @@ -1,102 +0,0 @@ -//------------------------------------------------------------------------------------------------// -// This file is part of the Nebula Logger project, released under the MIT License. // -// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // -//------------------------------------------------------------------------------------------------// - -@SuppressWarnings('PMD.MethodNamingConventions') -@IsTest -private class LoggerEmailUtils_Tests { - @IsTest - static void it_should_send_email_notification_for_saveResult_errors_when_enabled() { - LoggerEmailUtils.CACHED_APEX_ERROR_RECIPIENTS.add(UserInfo.getUserId()); - System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent yet'); - - // LogEntry__c requires a Log__c parent record, so inserting a LogEntry__c with no fields set will (interntionally) fail - List saveResultsWithErrors = Database.insert(new List{ new LogEntry__c() }, false); - LoggerEmailUtils.sendErrorEmail(Schema.LogEntry__c.SObjectType, saveResultsWithErrors); - - System.assertEquals(1, Limits.getEmailInvocations(), 'Email should have been sent'); - System.assertEquals( - true, - LoggerEmailUtils.SENT_EMAILS.get(0).getHtmlBody().contains(saveResultsWithErrors.get(0).errors.get(0).getMessage()), - 'Email message should contain SaveResult error message' - ); - } - - @IsTest - static void it_should_not_send_email_notification_for_saveResult_errors_when_no_recipients_configured() { - LoggerParameter.setMockParameter(new LoggerParameter__mdt(DeveloperName = 'SendErrorEmailNotifications', Value__c = 'true')); - System.assertEquals(true, LoggerParameter.SEND_ERROR_EMAIL_NOTIFICATIONS); - LoggerEmailUtils.CACHED_APEX_ERROR_RECIPIENTS.clear(); - System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent yet'); - - // LogEntry__c requires a Log__c parent record, so inserting a LogEntry__c with no fields set will (interntionally) fail - List saveResultsWithErrors = Database.insert(new List{ new LogEntry__c() }, false); - LoggerEmailUtils.sendErrorEmail(Schema.LogEntry__c.SObjectType, saveResultsWithErrors); - - System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent'); - System.assertEquals(true, LoggerEmailUtils.SENT_EMAILS.isEmpty(), 'No email messages should have been generated'); - } - - @IsTest - static void it_should_not_send_email_notification_for_saveResult_errors_when_disabled() { - LoggerParameter.setMockParameter(new LoggerParameter__mdt(DeveloperName = 'SendErrorEmailNotifications', Value__c = 'false')); - System.assertEquals(false, LoggerParameter.SEND_ERROR_EMAIL_NOTIFICATIONS); - LoggerEmailUtils.CACHED_APEX_ERROR_RECIPIENTS.add(UserInfo.getUserId()); - System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent yet'); - - // LogEntry__c requires a Log__c parent record, so inserting a LogEntry__c with no fields set will (interntionally) fail - List saveResultsWithErrors = Database.insert(new List{ new LogEntry__c() }, false); - LoggerEmailUtils.sendErrorEmail(Schema.LogEntry__c.SObjectType, saveResultsWithErrors); - - System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent'); - System.assertEquals(true, LoggerEmailUtils.SENT_EMAILS.isEmpty(), 'No email messages should have been generated'); - } - - @IsTest - static void it_should_send_email_notification_for_upsertResult_errors_when_enabled() { - LoggerEmailUtils.CACHED_APEX_ERROR_RECIPIENTS.add(UserInfo.getUserId()); - System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent yet'); - - // LogEntry__c requires a Log__c parent record, so inserting a LogEntry__c with no fields set will (interntionally) fail - List upsertResultsWithErrors = Database.upsert(new List{ new LogEntry__c() }, false); - LoggerEmailUtils.sendErrorEmail(Schema.LogEntry__c.SObjectType, upsertResultsWithErrors); - - System.assertEquals(1, Limits.getEmailInvocations(), 'Email should have been sent'); - System.assertEquals( - true, - LoggerEmailUtils.SENT_EMAILS.get(0).getHtmlBody().contains(upsertResultsWithErrors.get(0).errors.get(0).getMessage()), - 'Email message should contain UpsertResult error message' - ); - } - - @IsTest - static void it_should_not_send_email_notification_for_upsertResult_errors_when_no_recipients_configured() { - LoggerParameter.setMockParameter(new LoggerParameter__mdt(DeveloperName = 'SendErrorEmailNotifications', Value__c = 'true')); - System.assertEquals(true, LoggerParameter.SEND_ERROR_EMAIL_NOTIFICATIONS); - LoggerEmailUtils.CACHED_APEX_ERROR_RECIPIENTS.clear(); - System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent yet'); - - // LogEntry__c requires a Log__c parent record, so inserting a LogEntry__c with no fields set will (interntionally) fail - List upsertResultsWithErrors = Database.upsert(new List{ new LogEntry__c() }, false); - LoggerEmailUtils.sendErrorEmail(Schema.LogEntry__c.SObjectType, upsertResultsWithErrors); - - System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent'); - System.assertEquals(true, LoggerEmailUtils.SENT_EMAILS.isEmpty(), 'No email messages should have been generated'); - } - - @IsTest - static void it_should_not_send_email_notification_for_upsertResult_errors_when_disabled() { - LoggerParameter.setMockParameter(new LoggerParameter__mdt(DeveloperName = 'SendErrorEmailNotifications', Value__c = 'false')); - System.assertEquals(false, LoggerParameter.SEND_ERROR_EMAIL_NOTIFICATIONS); - LoggerEmailUtils.CACHED_APEX_ERROR_RECIPIENTS.add(UserInfo.getUserId()); - System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent yet'); - - // LogEntry__c requires a Log__c parent record, so inserting a LogEntry__c with no fields set will (interntionally) fail - List upsertResultsWithErrors = Database.upsert(new List{ new LogEntry__c() }, false); - LoggerEmailUtils.sendErrorEmail(Schema.LogEntry__c.SObjectType, upsertResultsWithErrors); - - System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent'); - System.assertEquals(true, LoggerEmailUtils.SENT_EMAILS.isEmpty(), 'No email messages should have been generated'); - } -} diff --git a/nebula-logger/core/tests/configuration/classes/LoggerParameter_Tests.cls b/nebula-logger/core/tests/configuration/classes/LoggerParameter_Tests.cls index 447915dc3..265c32cf8 100644 --- a/nebula-logger/core/tests/configuration/classes/LoggerParameter_Tests.cls +++ b/nebula-logger/core/tests/configuration/classes/LoggerParameter_Tests.cls @@ -4,19 +4,112 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class LoggerParameter_Tests { private static User getUserRecord() { return new User(Id = UserInfo.getUserId(), Username = UserInfo.getUserName()); } + @IsTest + static void it_should_throw_exception_when_mock_record_developer_name_is_null() { + LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = null); + Exception thrownIllegalArgumentException; + + try { + LoggerParameter.setMock(mockParameter); + } catch (IllegalArgumentException ex) { + thrownIllegalArgumentException = ex; + } + + System.assertNotEquals(null, thrownIllegalArgumentException); + } + + @IsTest + static void it_should_load_mock_record() { + LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MockParameter', Value__c = 'Hello, world!'); + LoggerParameter.setMock(mockParameter); + + String returnedValue = LoggerParameter.getString(mockParameter.DeveloperName, null); + + System.assertNotEquals(null, returnedValue); + System.assertEquals(mockParameter.Value__c, returnedValue); + } + + @IsTest + static void it_should_return_constant_value_for_call_status_api() { + Boolean mockValue = true; + LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'CallStatusApi', Value__c = JSON.serialize(mockValue)); + LoggerParameter.setMock(mockParameter); + + Boolean returnedValue = LoggerParameter.CALL_STATUS_API; + + System.assertEquals(mockValue, returnedValue); + } + + @IsTest + static void it_should_return_constant_value_for_enable_system_messages() { + Boolean mockValue = true; + LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'EnableLoggerSystemMessages', Value__c = JSON.serialize(mockValue)); + LoggerParameter.setMock(mockParameter); + + Boolean returnedValue = LoggerParameter.ENABLE_SYSTEM_MESSAGES; + + System.assertEquals(mockValue, returnedValue); + } + + @IsTest + static void it_should_return_constant_value_for_send_error_email_notifications() { + Boolean mockValue = false; + LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'SendErrorEmailNotifications', Value__c = JSON.serialize(mockValue)); + LoggerParameter.setMock(mockParameter); + + Boolean returnedValue = LoggerParameter.SEND_ERROR_EMAIL_NOTIFICATIONS; + + System.assertEquals(mockValue, returnedValue); + } + + @IsTest + static void it_should_return_constant_value_for_system_debug_message_format() { + // The constant LoggerParameter.SYSTEM_DEBUG_MESSAGE_FORMAT is unique - its value should always be + // loaded from LoggerParameter__mdt, even in a test context so that orgs can control the output of debug + // messages within their own test classes. All other constants use mock configurations + String configuredValue = LoggerParameter__mdt.getInstance('SystemDebugMessageFormat').Value__c; + + String returnedValue = LoggerParameter.SYSTEM_DEBUG_MESSAGE_FORMAT; + + System.assertEquals(configuredValue, returnedValue); + } + + @IsTest + static void it_should_return_constant_value_for_tagging_is_enabled() { + Boolean mockValue = false; + LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'EnableTagging', Value__c = JSON.serialize(mockValue)); + LoggerParameter.setMock(mockParameter); + + Boolean returnedValue = LoggerParameter.TAGGING_IS_ENABLED; + + System.assertEquals(mockValue, returnedValue); + } + + @IsTest + static void it_should_return_constant_value_for_tag_using_topics() { + Boolean mockValue = true; + LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'UseTopicsForTags', Value__c = JSON.serialize(mockValue)); + LoggerParameter.setMock(mockParameter); + + Boolean returnedValue = LoggerParameter.TAG_USING_TOPICS; + + System.assertEquals(mockValue, returnedValue); + } + @IsTest static void it_should_return_boolean_parameter() { Boolean parameterValue = true; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyBoolean', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); Boolean returnedValue = LoggerParameter.getBoolean(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -24,19 +117,35 @@ private class LoggerParameter_Tests { static void it_should_return_boolean_list_parameter() { List parameterValue = new List{ true, false, true, true }; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyBooleanList', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); List returnedValue = LoggerParameter.getBooleanList(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } + @IsTest + static void it_should_return_default_value_when_configured_boolean_list_parameter_is_null() { + List parameterValue = null; + LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyBooleanList', Value__c = JSON.serialize(parameterValue)); + LoggerParameter.setMock(mockParameter); + List defaultParameterValue = new List{ true, false }; + + List returnedValue = LoggerParameter.getBooleanList(mockParameter.DeveloperName, defaultParameterValue); + + System.assertEquals(null, parameterValue); + System.assertNotEquals(parameterValue, returnedValue, 'Returned value should not match configured null parameter value'); + System.assertEquals(defaultParameterValue, returnedValue, 'Returned value does not match expected default parameter value'); + } + @IsTest static void it_should_return_date_parameter() { Date parameterValue = System.today().addDays(-7); LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyDate', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); Date returnedValue = LoggerParameter.getDate(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -44,9 +153,10 @@ private class LoggerParameter_Tests { static void it_should_return_date_list_parameter() { List parameterValue = new List{ System.today(), System.today().addDays(10) }; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyDateList', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); List returnedValue = LoggerParameter.getDateList(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -54,9 +164,10 @@ private class LoggerParameter_Tests { static void it_should_return_datetime_parameter() { Datetime parameterValue = System.now().addDays(-7); LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyDatetime', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); Datetime returnedValue = LoggerParameter.getDatetime(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -64,9 +175,10 @@ private class LoggerParameter_Tests { static void it_should_return_datetime_list_parameter() { List parameterValue = new List{ System.now(), System.now().addDays(10) }; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyDatetimeList', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); List returnedValue = LoggerParameter.getDatetimeList(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -74,9 +186,10 @@ private class LoggerParameter_Tests { static void it_should_return_decimal_parameter() { Decimal parameterValue = 123456.0987; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyDecimal', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); Decimal returnedValue = LoggerParameter.getDecimal(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -84,9 +197,10 @@ private class LoggerParameter_Tests { static void it_should_return_decimal_list_parameter() { List parameterValue = new List{ 123.45, 678.09 }; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyDecimalList', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); List returnedValue = LoggerParameter.getDecimalList(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -94,9 +208,10 @@ private class LoggerParameter_Tests { static void it_should_return_double_parameter() { Double parameterValue = 123456.0987; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyDouble', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); Double returnedValue = LoggerParameter.getDouble(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -104,9 +219,10 @@ private class LoggerParameter_Tests { static void it_should_return_double_list_parameter() { List parameterValue = new List{ 123.45, 678.09 }; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyDoubleList', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); List returnedValue = LoggerParameter.getDoubleList(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -114,9 +230,10 @@ private class LoggerParameter_Tests { static void it_should_return_id_parameter() { Id parameterValue = UserInfo.getUserId(); LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyId', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); Id returnedValue = LoggerParameter.getId(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -124,9 +241,10 @@ private class LoggerParameter_Tests { static void it_should_return_id_list_parameter() { List parameterValue = new List{ UserInfo.getUserId() }; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyIdList', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); List returnedValue = LoggerParameter.getIdList(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -134,9 +252,10 @@ private class LoggerParameter_Tests { static void it_should_return_integer_parameter() { Integer parameterValue = 123456; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyInteger', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); Integer returnedValue = LoggerParameter.getInteger(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -144,9 +263,10 @@ private class LoggerParameter_Tests { static void it_should_return_integer_list_parameter() { List parameterValue = new List{ 12345, 67809 }; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyIntegerList', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); List returnedValue = LoggerParameter.getIntegerList(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -154,9 +274,10 @@ private class LoggerParameter_Tests { static void it_should_return_long_parameter() { Long parameterValue = 123456; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyLong', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); Long returnedValue = LoggerParameter.getLong(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -164,9 +285,10 @@ private class LoggerParameter_Tests { static void it_should_return_long_list_parameter() { List parameterValue = new List{ 12345, 67809 }; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyLongList', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); List returnedValue = LoggerParameter.getLongList(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -174,9 +296,10 @@ private class LoggerParameter_Tests { static void it_should_return_sobject_parameter() { SObject parameterValue = getUserRecord(); LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MySObject', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); SObject returnedValue = LoggerParameter.getSObject(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -184,9 +307,10 @@ private class LoggerParameter_Tests { static void it_should_return_sobject_list_parameter() { List parameterValue = new List{ getUserRecord() }; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MySObjectList', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); List returnedValue = LoggerParameter.getSObjectList(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -194,9 +318,10 @@ private class LoggerParameter_Tests { static void it_should_return_string_parameter() { String parameterValue = 'Hello'; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyString', Value__c = parameterValue); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); String returnedValue = LoggerParameter.getString(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } @@ -204,9 +329,33 @@ private class LoggerParameter_Tests { static void it_should_return_string_list_parameter() { List parameterValue = new List{ 'Hello', 'Goodbye' }; LoggerParameter__mdt mockParameter = new LoggerParameter__mdt(DeveloperName = 'MyStringList', Value__c = JSON.serialize(parameterValue)); - LoggerParameter.setMockParameter(mockParameter); + LoggerParameter.setMock(mockParameter); List returnedValue = LoggerParameter.getStringList(mockParameter.DeveloperName, null); + System.assertEquals(parameterValue, returnedValue, 'Returned value does not match expected parameter value'); } + + @IsTest + static void it_should_match_on_developer_name_prefix() { + String developerNamePrefix = 'SomePrefix'; + LoggerParameter__mdt firstMatchingMockParameter = new LoggerParameter__mdt(DeveloperName = developerNamePrefix + 'SomeExample', Value__c = 'hello'); + LoggerParameter.setMock(firstMatchingMockParameter); + LoggerParameter__mdt secondMatchingMockParameter = new LoggerParameter__mdt(DeveloperName = developerNamePrefix + 'AnotherExample', Value__c = 'world'); + LoggerParameter.setMock(secondMatchingMockParameter); + LoggerParameter__mdt nonMatchingMockParameter = new LoggerParameter__mdt(DeveloperName = 'ThisShouldNotMatch', Value__c = '!'); + LoggerParameter.setMock(nonMatchingMockParameter); + + List matchingParameters = LoggerParameter.matchOnPrefix(developerNamePrefix); + + System.assertEquals(2, matchingParameters.size()); + for (LoggerParameter__mdt matchingParameter : matchingParameters) { + System.assertEquals( + true, + matchingParameter.DeveloperName == firstMatchingMockParameter.DeveloperName || + matchingParameter.DeveloperName == secondMatchingMockParameter.DeveloperName, + 'Returned parameter should be one of the two matching mock parameters' + ); + } + } } diff --git a/nebula-logger/core/tests/configuration/classes/LoggerPlugin_Tests.cls b/nebula-logger/core/tests/configuration/classes/LoggerPlugin_Tests.cls new file mode 100644 index 000000000..a0e95dc76 --- /dev/null +++ b/nebula-logger/core/tests/configuration/classes/LoggerPlugin_Tests.cls @@ -0,0 +1,123 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +@SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') +@IsTest(IsParallel=true) +private class LoggerPlugin_Tests { + private static final String PLUGIN_LOG_STATUS = 'On Hold'; + + @IsTest + static void it_should_returned_filtered_plugin_configurations_in_sorted_order() { + // The mock LoggerPlugin__mdt records are purposeful being added to LoggerPlugin.setMock() + // in an order that's different from the order when sorting on SObjectHandlerExecutionOrder__c. + // This helps ensure that the returned results are truly being sorted, instead of just being returned + // in the same order that they're added via LoggerPlugin.setMock() + LoggerPlugin__mdt secondPluginConfiguration = createMockPluginConfiguration('secondPluginConfiguration'); + secondPluginConfiguration.SObjectHandlerApexClass__c = 'Also_A_Fake_Apex_Class'; + secondPluginConfiguration.SObjectHandlerExecutionOrder__c = 2; + LoggerPlugin.setMock(secondPluginConfiguration); + LoggerPlugin__mdt fifthPluginConfiguration = createMockPluginConfiguration('zzzzz_sort_me_last_alphabetically_fifthPluginConfiguration'); + fifthPluginConfiguration.SObjectHandlerApexClass__c = 'Yeah_This_Is_A_Fake_Apex_Class'; + fifthPluginConfiguration.SObjectHandlerExecutionOrder__c = null; + LoggerPlugin.setMock(fifthPluginConfiguration); + LoggerPlugin__mdt fourthPluginConfiguration = createMockPluginConfiguration('fourthPluginConfiguration'); + fourthPluginConfiguration.SObjectHandlerApexClass__c = 'Yeah_This_Is_A_Fake_Apex_Class'; + fourthPluginConfiguration.SObjectHandlerExecutionOrder__c = null; + LoggerPlugin.setMock(fourthPluginConfiguration); + LoggerPlugin__mdt thirdPluginConfiguration = createMockPluginConfiguration('thirdPluginConfiguration'); + thirdPluginConfiguration.SObjectHandlerApexClass__c = 'Yeah_This_Is_A_Fake_Apex_Class'; + thirdPluginConfiguration.SObjectHandlerExecutionOrder__c = 3; + LoggerPlugin.setMock(thirdPluginConfiguration); + LoggerPlugin__mdt firstPluginConfiguration = createMockPluginConfiguration('firstPluginConfiguration'); + firstPluginConfiguration.SObjectHandlerApexClass__c = 'Some_Fake_Apex_Class'; + firstPluginConfiguration.SObjectHandlerExecutionOrder__c = 1; + LoggerPlugin.setMock(firstPluginConfiguration); + List expectedSortedPluginConfigurations = new List{ + firstPluginConfiguration, + secondPluginConfiguration, + thirdPluginConfiguration, + fourthPluginConfiguration, + fifthPluginConfiguration + }; + LoggerPlugin__mdt disabledPluginConfiguration = createMockPluginConfiguration('disabledPluginConfiguration'); + secondPluginConfiguration.IsEnabled__c = false; + secondPluginConfiguration.SObjectHandlerApexClass__c = 'Also_A_Fake_Apex_Class'; + secondPluginConfiguration.SObjectHandlerExecutionOrder__c = 2; + LoggerPlugin.setMock(disabledPluginConfiguration); + LoggerPlugin__mdt nonMatchingPluginConfiguration = createMockPluginConfiguration('nonMatchingPluginConfiguration'); + nonMatchingPluginConfiguration.SObjectHandlerApexClass__c = null; + nonMatchingPluginConfiguration.SObjectHandlerExecutionOrder__c = 1; + LoggerPlugin.setMock(nonMatchingPluginConfiguration); + + List returnedPluginConfigurations = LoggerPlugin.getFilteredPluginConfigurations( + new List{ Schema.LoggerPlugin__mdt.SObjectHandlerApexClass__c }, + Schema.LoggerPlugin__mdt.SObjectHandlerExecutionOrder__c + ); + + System.assertEquals(expectedSortedPluginConfigurations.size(), returnedPluginConfigurations.size()); + for (Integer i = 0; i < returnedPluginConfigurations.size(); i++) { + LoggerPlugin__mdt expectedSortedPluginConfiguration = expectedSortedPluginConfigurations.get(i); + LoggerPlugin__mdt returnedPluginConfiguration = returnedPluginConfigurations.get(i); + System.assertEquals(expectedSortedPluginConfiguration, returnedPluginConfiguration, 'Records at index ' + i + ' don\'t match'); + } + } + + @IsTest + static void it_should_return_batchable_apex_plugin_instance_for_valid_class() { + LoggerPlugin.Batchable batchableApexPlugin = LoggerPlugin.newBatchableInstance(ExampleBatchPurgerPlugin.class.getName()); + + System.assertNotEquals(null, batchableApexPlugin, ExampleBatchPurgerPlugin.class.getName()); + System.assertEquals(true, batchableApexPlugin instanceof ExampleBatchPurgerPlugin); + } + + @IsTest + static void it_should_return_null_batchable_apex_plugin_instance_for_invalid_class() { + LoggerPlugin.Batchable batchableApexPlugin = LoggerPlugin.newBatchableInstance('Some fake class, this definitely doesn\'t exist'); + + System.assertEquals(null, batchableApexPlugin); + } + + @IsTest + static void it_should_return_triggerable_apex_plugin_instance_for_valid_class() { + LoggerPlugin.Triggerable triggerableApexPlugin = LoggerPlugin.newTriggerableInstance(ExampleTriggerablePlugin.class.getName()); + + System.assertNotEquals(null, triggerableApexPlugin, ExampleTriggerablePlugin.class.getName()); + System.assertEquals(true, triggerableApexPlugin instanceof ExampleTriggerablePlugin); + } + + @IsTest + static void it_should_return_null_triggerable_apex_plugin_instance_for_invalid_class() { + LoggerPlugin.Triggerable triggerableApexPlugin = LoggerPlugin.newTriggerableInstance('Some fake class, this definitely doesn\'t exist'); + + System.assertEquals(null, triggerableApexPlugin); + } + + private static LoggerPlugin__mdt createMockPluginConfiguration(String developerName) { + return new LoggerPlugin__mdt(DeveloperName = developerName, IsEnabled__c = true); + } + + @SuppressWarnings('PMD.ApexDoc, PMD.EmptyStatementBlock') + public class ExampleBatchPurgerPlugin implements LoggerPlugin.Batchable { + public void start(LoggerPlugin__mdt configuration, LoggerBatchableContext input) { + } + public void execute(LoggerPlugin__mdt configuration, LoggerBatchableContext input, List scope) { + } + public void finish(LoggerPlugin__mdt configuration, LoggerBatchableContext input) { + } + } + + @SuppressWarnings('PMD.ApexDoc, PMD.EmptyStatementBlock') + public class ExampleTriggerablePlugin implements LoggerPlugin.Triggerable { + public void execute(LoggerPlugin__mdt configuration, LoggerTriggerableContext input) { + switch on input.triggerOperationType { + when BEFORE_INSERT { + for (Log__c log : (List) input.triggerNew) { + log.Status__c = PLUGIN_LOG_STATUS; + } + } + } + } + } +} diff --git a/nebula-logger/extra-tests/tests/LogHandler_Tests_Flow.cls-meta.xml b/nebula-logger/core/tests/configuration/classes/LoggerPlugin_Tests.cls-meta.xml similarity index 100% rename from nebula-logger/extra-tests/tests/LogHandler_Tests_Flow.cls-meta.xml rename to nebula-logger/core/tests/configuration/classes/LoggerPlugin_Tests.cls-meta.xml diff --git a/nebula-logger/core/tests/configuration/testSuites/LoggerConfiguration.testSuite-meta.xml b/nebula-logger/core/tests/configuration/testSuites/LoggerConfiguration.testSuite-meta.xml index cf5d52783..17a87cb0c 100644 --- a/nebula-logger/core/tests/configuration/testSuites/LoggerConfiguration.testSuite-meta.xml +++ b/nebula-logger/core/tests/configuration/testSuites/LoggerConfiguration.testSuite-meta.xml @@ -1,4 +1,5 @@ LoggerParameter_Tests + LoggerPlugin_Tests diff --git a/nebula-logger/core/tests/configuration/utilities/LoggerMockDataCreator.cls b/nebula-logger/core/tests/configuration/utilities/LoggerMockDataCreator.cls new file mode 100644 index 000000000..a1a6d5de3 --- /dev/null +++ b/nebula-logger/core/tests/configuration/utilities/LoggerMockDataCreator.cls @@ -0,0 +1,678 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @group Test Utilities + * @description Utility class used to help with generating mock data when writing Apex tests for Nebula Logger. + * These methods are generic, and should work in any Salesforce org. + * These methods can be used when writing Apex tests for plugins. + * @see LoggerMockDataStore + * @see LoggerTestConfigurator + */ +@SuppressWarnings('PMD.CyclomaticComplexity, PMD.ExcessivePublicCount, PMD.MethodNamingConventions, PMD.PropertyNamingConventions') +@IsTest +public class LoggerMockDataCreator { + private static final Map> SOBJECT_TYPE_TO_ALL_FIELDS = new Map>(); + private static final Map> SOBJECT_TYPE_TO_REQUIRED_FIELDS = new Map>(); + private static final Map SOBJECT_TYPE_TO_MOCK_ID_COUNT = new Map(); + + private static Integer userMockUsernameCount = 0; + + /** + * @description Instances of `AggregateResult` can not be created directly in Apex. + * This method uses a workaround to generate a mock. + * @return The mock instance of `AggregateResult` + */ + public static AggregateResult createAggregateResult() { + Map defaultMockAggregateKeyValues = new Map{ + 'fieldAvg' => 62.5, + 'fieldMax' => 100, + 'fieldMin' => 25, + 'fieldCount' => 4 + }; + return createAggregateResult(defaultMockAggregateKeyValues); + } + + /** + * @description Instances of `AggregateResult` can not be created directly in Apex. + * This method uses a workaround to generate a mock, using the provided map of aliases & aggregate values + * @param mockAggregateKeyValues A map of aliases & aggregate values to use when creating the mock `AggregateResult` + * @return The mock instance of `AggregateResult` + */ + public static AggregateResult createAggregateResult(Map mockAggregateKeyValues) { + return (AggregateResult) JSON.deserialize(JSON.serialize(mockAggregateKeyValues), AggregateResult.class); + } + + /** + * @description Creates an instance of the class `MockBatchableContext` that implements the interface `Database.BatchableContext`. + * This can be used when testing batch jobs. + * @param jobId A string value to use as the batchable job ID - this can be a true ID, or just a string + * @return The instance of `MockBatchableContext` + */ + public static MockBatchableContext createBatchableContext(String jobId) { + return new MockBatchableContext(jobId); + } + + /** + * @description Creates a mock instance of `Database.DeleteResult` - a mock is used instead of an actual instance + * to help speed up tests, and to support writing unit tests (instead of integration tests). A fake + * record ID is automatically included. + * @param isSuccess Indicates if the generated mock should have `isSuccess` == true + * @return The mock instance of `Database.DeleteResult` + */ + public static Database.DeleteResult createDatabaseDeleteResult(Boolean isSuccess) { + return createDatabaseDeleteResult(isSuccess, createId(Schema.Account.SObjectType)); + } + + /** + * @description Creates a mock instance of `Database.DeleteResult` - a mock is used instead of an actual instance + * to help speed up tests, and to support writing unit tests (instead of integration tests) + * @param isSuccess Indicates if the generated mock should have `isSuccess` == true + * @param recordId The record ID to use within the mock result + * @return The mock instance of `Database.DeleteResult` + */ + public static Database.DeleteResult createDatabaseDeleteResult(Boolean isSuccess, Id recordId) { + if (isSuccess == true) { + return (Database.DeleteResult) JSON.deserialize('{"success": true, "id": "' + recordId + '"}', Database.DeleteResult.class); + } else { + return (Database.DeleteResult) JSON.deserialize( + '{"success":false,"errors":[{"message": "Could not delete...", "statusCode": "DELETE_FAILED"}]}', + Database.DeleteResult.class + ); + } + } + + /** + * @description Creates a mock instance of `Database.MergeResult` - a mock is used instead of an actual instance + * to help speed up tests, and to support writing unit tests (instead of integration tests). A fake + * record ID is automatically included. + * @param isSuccess Indicates if the generated mock should have `isSuccess` == true + * @return The mock instance of `Database.MergeResult` + */ + public static Database.MergeResult createDatabaseMergeResult(Boolean isSuccess) { + return createDatabaseMergeResult(isSuccess, createId(Schema.Account.SObjectType)); + } + + /** + * @description Creates a mock instance of `Database.MergeResult` - a mock is used instead of an actual instance + * to help speed up tests, and to support writing unit tests (instead of integration tests) + * @param isSuccess Indicates if the generated mock should have `isSuccess` == true + * @param recordId The record ID to use within the mock result + * @return The mock instance of `Database.MergeResult` + */ + public static Database.MergeResult createDatabaseMergeResult(Boolean isSuccess, Id recordId) { + if (isSuccess == true) { + return (Database.MergeResult) JSON.deserialize('{"success": true, "id": "' + recordId + '"}', Database.MergeResult.class); + } else { + return (Database.MergeResult) JSON.deserialize( + '{"success":false,"errors":[{"message": "Could not merge...", "statusCode": "MERGE_FAILED"}]}', + Database.MergeResult.class + ); + } + } + + /** + * @description Creates a mock instance of `Database.SaveResult` - a mock is used instead of an actual instance + * to help speed up tests, and to support writing unit tests (instead of integration tests). A fake + * record ID is automatically included. + * @param isSuccess Indicates if the generated mock should have `isSuccess` == true + * @return The mock instance of `Database.SaveResult` + */ + public static Database.SaveResult createDatabaseSaveResult(Boolean isSuccess) { + return createDatabaseSaveResult(isSuccess, createId(Schema.Account.SObjectType)); + } + + /** + * @description Creates a mock instance of `Database.SaveResult` - a mock is used instead of an actual instance + * to help speed up tests, and to support writing unit tests (instead of integration tests) + * @param isSuccess Indicates if the generated mock should have `isSuccess` == true + * @param recordId The record ID to use within the mock result + * @return The mock instance of `Database.SaveResult` + */ + public static Database.SaveResult createDatabaseSaveResult(Boolean isSuccess, Id recordId) { + if (isSuccess == true) { + return (Database.SaveResult) JSON.deserialize('{"success": true, "id": "' + recordId + '"}', Database.SaveResult.class); + } else { + return (Database.SaveResult) JSON.deserialize( + '{"success":false,"errors":[{"message": "Could not save...", "statusCode": "FIELD_CUSTOM_VALIDATION_EXCEPTION"}]}', + Database.SaveResult.class + ); + } + } + + /** + * @description Creates a mock instance of `Database.UndeleteResult` - a mock is used instead of an actual instance + * to help speed up tests, and to support writing unit tests (instead of integration tests). A fake + * record ID is automatically included. + * @param isSuccess Indicates if the generated mock should have `isSuccess` == true + * @return The mock instance of `Database.UndeleteResult` + */ + public static Database.UndeleteResult createDatabaseUndeleteResult(Boolean isSuccess) { + return createDatabaseUndeleteResult(isSuccess, createId(Schema.Account.SObjectType)); + } + + /** + * @description Creates a mock instance of `Database.UndeleteResult` - a mock is used instead of an actual instance + * to help speed up tests, and to support writing unit tests (instead of integration tests) + * @param isSuccess Indicates if the generated mock should have `isSuccess` == true + * @param recordId The record ID to use within the mock result + * @return The mock instance of `Database.UndeleteResult` + */ + public static Database.UndeleteResult createDatabaseUndeleteResult(Boolean isSuccess, Id recordId) { + if (isSuccess == true) { + return (Database.UndeleteResult) JSON.deserialize('{"success": true, "id": "' + recordId + '"}', Database.UndeleteResult.class); + } else { + return (Database.UndeleteResult) JSON.deserialize( + '{"success":false,"errors":[{"message": "Could not undelete...", "statusCode": "FIELD_CUSTOM_VALIDATION_EXCEPTION"}]}', + Database.UndeleteResult.class + ); + } + } + + /** + * @description Creates a mock instance of `Database.UpsertResult` - a mock is used instead of an actual instance + * to help speed up tests, and to support writing unit tests (instead of integration tests). A fake + * record ID is automatically included. + * @param isSuccess Indicates if the generated mock should have `isSuccess` == true + * @param isCreated Indicates if the generated mock should have `isCreated` == true + * @return The mock instance of `Database.UpsertResult` + */ + public static Database.UpsertResult createDatabaseUpsertResult(Boolean isSuccess, Boolean isCreated) { + return createDatabaseUpsertResult(isSuccess, isCreated, createId(Schema.Account.SObjectType)); + } + + /** + * @description Creates a mock instance of `Database.UpsertResult` - a mock is used instead of an actual instance + * to help speed up tests, and to support writing unit tests (instead of integration tests) + * @param isSuccess Indicates if the generated mock should have `isSuccess` == true + * @param isCreated Indicates if the generated mock should have `isCreated` == true + * @param recordId The record ID to use within the mock result + * @return The mock instance of `Database.UpsertResult` + */ + public static Database.UpsertResult createDatabaseUpsertResult(Boolean isSuccess, Boolean isCreated, Id recordId) { + if (isSuccess == true) { + return (Database.UpsertResult) JSON.deserialize( + '{"success": ' + + isSuccess + + ', "created": ' + + isCreated + + ', "id": "' + + recordId + + '"}', + Database.UpsertResult.class + ); + } else { + return (Database.UpsertResult) JSON.deserialize( + '{"success":false, "created":' + + isCreated + + ', "errors":[{"message": "Could not upsert...", "statusCode": "FIELD_CUSTOM_VALIDATION_EXCEPTION"}]}', + Database.UpsertResult.class + ); + } + } + + /** + * @description Generates an instance of the class `MockHttpCallout` that implements the interface `HttpCalloutMock`. + * This can be used when testing batch jobs. + * @return The instance of `MockHttpCallout` + */ + public static MockHttpCallout createHttpCallout() { + return new MockHttpCallout(); + } + + /** + * @description Generates an instance of `HttpRequest`. This can be used when testing logging capabilities for instances of `HttpRequest`. + * @return The instance of `HttpRequest` + */ + public static HttpRequest createHttpRequest() { + HttpRequest request = new HttpRequest(); + request.setBody('Hello, world!'); + request.setCompressed(true); + request.setEndpoint('https://fake.salesforce.com'); + request.setMethod('GET'); + return request; + } + + /** + * @description Generates an instance of `HttpResponse`. This can be used when testing logging capabilities for instances of `HttpResponse`. + * @return The instance of `HttpResponse` + */ + public static HttpResponse createHttpResponse() { + HttpResponse response = new HttpResponse(); + response.setBody('Hello, world!'); + response.setHeader('someKey', 'some string value'); + response.setHeader('anotherKey', 'an amazing example value, wow'); + response.setStatus('STATUS_GOOD_JOB_YOU_DID_IT'); + response.setStatusCode(201); + return response; + } + + /** + * @description Generates a mock record ID for the provided SObject Type + * @param sobjectType The SObject Type for the generated mock record ID + * @return The mock record ID for the specified SObject Type + */ + public static String createId(Schema.SObjectType sobjectType) { + Integer recordIdNumber = 1; + if (SOBJECT_TYPE_TO_MOCK_ID_COUNT.containsKey(sobjectType)) { + recordIdNumber = SOBJECT_TYPE_TO_MOCK_ID_COUNT.get(sobjectType); + } + String recordIdSuffix = String.valueOf(recordIdNumber++); + SOBJECT_TYPE_TO_MOCK_ID_COUNT.put(sobjectType, recordIdNumber); + + String recordIdKeyPrefix = sobjectType.getDescribe().getKeyPrefix(); + Integer idFieldLength = sobjectType.getDescribe().fields.getMap().get('Id').getDescribe().getLength(); + Integer recordIdCenterLength = idFieldLength - recordIdKeyPrefix.length() - recordIdSuffix.length(); + return recordIdKeyPrefix + '0'.repeat(recordIdCenterLength) + recordIdSuffix; + } + + /** + * @description Creates a new builder instance for the specified `SObjectType`, including creating a + * new `SObject` record. The new `SObject` record is created with any default field values that + * have been configured on the `SObjectType`. + * @param sobjectType The `SObjectType` to use for generating a new test `SObject` record + * @return A new instance of `SObjectTestDataBuilder` for the specified `SObjectType` + */ + public static SObjectTestDataBuilder createDataBuilder(Schema.SObjectType sobjectType) { + return new SObjectTestDataBuilder(sobjectType); + } + + /** + * @description Creates a new builder instance for the specified `SObject` record + * @param record The existing test `SObject` record to populate with sample data + * @return A new instance of `SObjectTestDataBuilder` for the specified `SObject` + */ + public static SObjectTestDataBuilder createDataBuilder(SObject record) { + return new SObjectTestDataBuilder(record); + } + + /** + * @description Creates a `User` record for testing purposes, using the current user's profile + * @return The generated `User` record - it is not automatically inserted into the database. + */ + public static User createUser() { + return createUser(UserInfo.getProfileId()); + } + + /** + * @description Creates a `User` record for testing purposes, using the specified profile ID + * @param profileId The `Profile` ID to use for the created `User` + * @return The generated `User` record - it is not automatically inserted into the database. + */ + public static User createUser(Id profileId) { + return new User( + Alias = 'user_xyz', + Email = 'user_xyz@test.com.net.org', + EmailEncodingKey = 'ISO-8859-1', + LanguageLocaleKey = 'en_US', + LastName = 'Test Userson', + LocaleSidKey = 'en_US', + ProfileId = profileId, + TimeZoneSidKey = 'America/Los_Angeles', + Username = 'user_xyz' + (userMockUsernameCount++) + '@test.com.net.org' + ); + } + + /** + * @description Queries for the `Organization` record for the current environment. + * @return The matching `Organization` record + */ + public static Organization getOrganization() { + return [SELECT Id, Name, InstanceName, IsSandbox, NamespacePrefix, OrganizationType, TrialExpirationDate FROM Organization]; + } + + /** + * @description Returns the current environment's type - Scratch Org, Sandbox, or Production. + * @return The environment type + */ + public static String getOrganizationEnvironmentType() { + Organization organization = getOrganization(); + + String orgEnvironmentType; + if (organization.IsSandbox == true && organization.TrialExpirationDate != null) { + orgEnvironmentType = 'Scratch Org'; + } else if (organization.IsSandbox == true) { + orgEnvironmentType = 'Sandbox'; + } else { + orgEnvironmentType = 'Production'; + } + return orgEnvironmentType; + } + + /** + * @description Returns the current user's `Network` (Experience Cloud site) + * @return The matching `Network` record + */ + public static SObject getNetwork() { + if (Network.getNetworkId() == null || Type.forName('Network') == null) { + return null; + } + + String query = 'SELECT Id, Name, UrlPathPrefix FROM Network WHERE Id = :Network.getNetworkId()'; + return Database.query(String.escapeSingleQuotes(query)); + } + + /** + * @description Returns the current user + * @return The matching `User` record + */ + public static User getUser() { + return getUser(UserInfo.getUserId()); + } + + /** + * @description Returns the specified user + * @param userId The ID of the `User` record to query + * @return The matching `User` record + */ + public static User getUser(Id userId) { + return [ + SELECT Id, Profile.Name, Profile.UserLicenseId, Profile.UserLicense.LicenseDefinitionKey, Profile.UserLicense.Name, Username, UserRole.Name + FROM User + WHERE Id = :userId + ]; + } + + /** + * @description Creates and inserts a `Group` record for testing queues, using the specified SObject Type + * @param queueDeveloperName The developer name to use for the new queue (stored in `Group.DeveloperName`) + * @param sobjectType The `SObjectType` that the queue should be able to own (stored in `QueueSObject.SObjectType`) + * @return The inserted `Group` record - it is automatically inserted into the database, as well as 1 child `QueueSObject` record. + */ + public static Group insertQueue(String queueDeveloperName, Schema.SObjectType sobjectType) { + Group queue = new Group(DeveloperName = queueDeveloperName, Name = queueDeveloperName, Type = 'Queue'); + insert queue; + + // To avoid a MIXED_DML_OPERATION exception, use System.runs() for inserting the QueueSObject record + System.runAs(new User(Id = UserInfo.getUserId())) { + QueueSObject queueSObject = new QueueSObject(QueueId = queue.Id, SObjectType = sobjectType.getDescribe().getName()); + insert queueSObject; + } + + return queue; + } + + /** + * @description Sets a value for read-only fields that typically cannot be directly set on some SObjects + * @param record The `SObject` record to update + * @param field The `Schema.SObjectField` for the field to update + * @param value The field value to populate on the provied `SObject` record + * @return A new copy of the original `SObject` record that has the specified read-only field populated + */ + public static SObject setReadOnlyField(SObject record, Schema.SObjectField field, Object value) { + return setReadOnlyField(record, new Map{ field => value }); + } + + /** + * @description Sets values for read-only fields that typically cannot be directly set on some SObjects + * @param record record description + * @param changesToFields An instance of `Map containing the read-only fields and corresponding + * field values to populate on the provied `SObject` record + * @return A new copy of the original `SObject` record that has the specified read-only fields populated + */ + public static SObject setReadOnlyField(SObject record, Map changesToFields) { + String serializedRecord = JSON.serialize(record); + Map deserializedRecordMap = (Map) JSON.deserializeUntyped(serializedRecord); + + // Loop through the deserialized record map and put the field & value + // Since it's a map, if the field already exists on the SObject, it's updated (or added if it wasn't there already) + for (Schema.SObjectField sobjectField : changesToFields.keySet()) { + String fieldName = sobjectField.getDescribe().getName(); + deserializedRecordMap.put(fieldName, changesToFields.get(sobjectField)); + } + + serializedRecord = JSON.serialize(deserializedRecordMap); + return (SObject) JSON.deserialize(serializedRecord, SObject.class); + } + + @SuppressWarnings('PMD.ApexDoc') + public class MockBatchableContext implements Database.BatchableContext { + private String childJobId; + private String jobId; + + public MockBatchableContext(String jobId) { + this(jobId, null); + } + + public MockBatchableContext(String jobId, Id childJobId) { + this.jobId = jobId; + this.childJobId = childJobId; + } + + public String getChildJobId() { + return childJobId; + } + + public String getJobId() { + return jobId; + } + } + + @SuppressWarnings('PMD.ApexDoc, PMD.EmptyStatementBlock') + public class MockHttpCallout implements HttpCalloutMock { + public HttpRequest request { get; private set; } + public HttpResponse response { get; private set; } + public String responseBody { get; private set; } + public Integer statusCode { get; private set; } + + public MockHttpCallout() { + } + + public MockHttpCallout setResponseBody(String responseBody) { + this.responseBody = responseBody; + return this; + } + + public MockHttpCallout setStatusCode(Integer statusCode) { + this.statusCode = statusCode; + return this; + } + + public HttpResponse respond(HttpRequest request) { + this.request = request; + + this.response = new HttpResponse(); + if (String.isNotBlank(this.responseBody) == true) { + response.setBody(this.responseBody); + } + response.setStatusCode(this.statusCode); + return response; + } + } + + /** + * @description Class used to create or update an `SObject` record with static fake data. + * This is useful in situations where you need to have fields populated, but the specific + * values used are not relevant to a particular test. + * This class can be used when Apex writing tests for plugins. + */ + public without sharing class SObjectTestDataBuilder { + private final Schema.SObjectType sobjectType; + private final SObject record; + + /** + * @description Creates a new builder instance for the specified `SObjectType`, including creating a + * new `SObject` record. The new `SObject` record is created with any default field values that + * have been configured on the `SObjectType`. + * @param sobjectType The `SObjectType` to use for generating a new test `SObject` record + */ + private SObjectTestDataBuilder(Schema.SObjectType sobjectType) { + this(sobjectType.newSObject(null, true)); + } + + /** + * @description Creates a new builder instance for the specified `SObject` record + * @param record The existing test `SObject` record to populate with sample data + */ + private SObjectTestDataBuilder(SObject record) { + this.record = record; + this.sobjectType = record.getSObjectType(); + + this.loadFields(); + } + + /** + * @description Generates a mock record ID for the builder's `SObject` record + * @return The same instance of `SObjectTestDataBuilder`, useful for chaining methods + */ + public SObjectTestDataBuilder populateMockId() { + this.record.Id = createId(this.sobjectType); + return this; + } + + /** + * @description Sets a value on all editable fields, unless the `SObject` record already had a value specified for a field (including `null`) + * @return The `SObject` record, with all editable fields populated + */ + public SObjectTestDataBuilder populateAllFields() { + this.setUnpopulatedFieldsOnRecord(SOBJECT_TYPE_TO_ALL_FIELDS.get(this.sobjectType)); + return this; + } + + /** + * @description Sets a value on all editable required fields, unless the `SObject` record already had a value specified for a field (including `null`) + * @return The `SObject` record, with all editable required fields populated + */ + public SObjectTestDataBuilder populateRequiredFields() { + this.setUnpopulatedFieldsOnRecord(SOBJECT_TYPE_TO_REQUIRED_FIELDS.get(this.sobjectType)); + return this; + } + + /** + * @description Returns the builder's `SObject` record with fields populated based on + * which builder methods have been called + * @return The builder's `SObject` record that was either provided by the calling code, or generated + * by the builder (depending on which constructor was used for `SObjectTestDataBuilder`) + */ + public SObject getRecord() { + return this.record; + } + + private void loadFields() { + if (SOBJECT_TYPE_TO_ALL_FIELDS.containsKey(this.sobjectType) == true && SOBJECT_TYPE_TO_REQUIRED_FIELDS.containsKey(this.sobjectType) == true) { + return; + } + + SOBJECT_TYPE_TO_ALL_FIELDS.put(this.sobjectType, new List()); + SOBJECT_TYPE_TO_REQUIRED_FIELDS.put(this.sobjectType, new List()); + for (Schema.SObjectField field : this.sobjectType.getDescribe().fields.getMap().values()) { + if (field.getDescribe().isCreateable() == false) { + continue; + } + + SOBJECT_TYPE_TO_ALL_FIELDS.get(this.sobjectType).add(field); + if (field.getDescribe().isNillable() == false) { + // If a field is not nillable & it is createable, then it's required + SOBJECT_TYPE_TO_REQUIRED_FIELDS.get(this.sobjectType).add(field); + } + } + } + + private void setUnpopulatedFieldsOnRecord(List fields) { + Map populatedFields = this.record.getPopulatedFieldsAsMap(); + for (Schema.SObjectField field : fields) { + Schema.DescribeFieldResult fieldDescribe = field.getDescribe(); + // If a field was already populated by using the constructor 'TestDataFactory(SObject record)', then don't change it + if (populatedFields.containsKey(fieldDescribe.getName())) { + continue; + } + + Object fieldValue; + if (fieldDescribe.getDefaultValue() != null) { + // If there is a default value setup for the field, use it + fieldValue = fieldDescribe.getDefaultValue(); + } else { + // Otherwise, we'll generate our own test value to use, based on the field's metadata + fieldValue = this.getTestValue(fieldDescribe); + } + + // If we now have a value to use, set it on the record + if (fieldValue != null) { + this.record.put(field, fieldValue); + } + } + } + + private Object getTestValue(Schema.DescribeFieldResult fieldDescribe) { + // Since Apex does not support case statements, we use several ugly IF-ELSE statements + // Some more complex data types, like ID & Reference, require other objects to be created + // This implementation delegates that responsibility to the test classes since DML is required to get a valid ID, + // but the logic below could be updated to support creating parent objects if needed + + // Unsupported display types have been commented-out below + /* + Schema.DisplayType.Address, Schema.DisplayType.AnyType, Schema.DisplayType.Base64, + Schema.DisplayType.DataCategoryGroupReference, Schema.DisplayType.Id, Schema.DisplayType.Reference + */ + switch on fieldDescribe.getType() { + when Boolean { + return false; + } + when Combobox { + return this.getStringValue(fieldDescribe); + } + when Currency { + return (19.85).setScale(fieldDescribe.getScale()); + } + when Date { + return System.today(); + } + when Datetime { + return System.now(); + } + when Double { + return (3.14).setScale(fieldDescribe.getScale()); + } + when Email { + return 'test@example.com'; + } + when EncryptedString { + return this.getStringValue(fieldDescribe); + } + when Integer { + return 1; + } + when Long { + return 1234567890L; + } + when MultiPicklist { + return fieldDescribe.getPicklistValues().get(0).getValue(); + } + when Percent { + return (0.42).setScale(fieldDescribe.getScale()); + } + when Phone { + return '+34 999 11 22 33'; + } + when Picklist { + return fieldDescribe.getPicklistValues().get(0).getValue(); + } + when String { + return this.getStringValue(fieldDescribe); + } + when TextArea { + return this.getStringValue(fieldDescribe); + } + when Time { + return Time.newInstance(13, 30, 6, 20); + } + when Url { + return 'https://salesforce.com'; + } + when else { + // Any non-supported display types will return null - test classes will need to handle setting the values + return null; + } + } + } + + private String getStringValue(Schema.DescribeFieldResult fieldDescribe) { + String stringValue = 'Test string for ' + fieldDescribe.getType(); + Integer maxLength = fieldDescribe.getLength(); + + return stringValue.left(maxLength).trim(); + } + } +} diff --git a/nebula-logger/plugins/Slack/plugin/slack/classes/SlackLoggerPlugin.cls-meta.xml b/nebula-logger/core/tests/configuration/utilities/LoggerMockDataCreator.cls-meta.xml similarity index 100% rename from nebula-logger/plugins/Slack/plugin/slack/classes/SlackLoggerPlugin.cls-meta.xml rename to nebula-logger/core/tests/configuration/utilities/LoggerMockDataCreator.cls-meta.xml diff --git a/nebula-logger/core/tests/log-management/classes/LogBatchPurgeScheduler_Tests.cls b/nebula-logger/core/tests/log-management/classes/LogBatchPurgeScheduler_Tests.cls index 392d9585e..c63b111ac 100644 --- a/nebula-logger/core/tests/log-management/classes/LogBatchPurgeScheduler_Tests.cls +++ b/nebula-logger/core/tests/log-management/classes/LogBatchPurgeScheduler_Tests.cls @@ -4,19 +4,16 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=false) private class LogBatchPurgeScheduler_Tests { private static final String TEST_CRON_EXPRESSION = '0 0 23 * * ?'; @IsTest static void it_should_schedule_job() { - Test.startTest(); + LoggerTestConfigurator.setMock(new LoggerParameter__mdt(DeveloperName = 'EnableLoggerSystemMessages', Value__c = 'true')); - LoggerParameter.setMockParameter(new LoggerParameter__mdt(DeveloperName = 'EnableLoggerSystemMessages', Value__c = 'true')); Id jobId = System.schedule('Test schedule of LogBatchPurgeScheduler', TEST_CRON_EXPRESSION, new LogBatchPurgeScheduler()); - Test.stopTest(); - CronTrigger cronTrigger = [SELECT Id, CronExpression, TimesTriggered, NextFireTime FROM CronTrigger WHERE Id = :jobId]; System.assertEquals(TEST_CRON_EXPRESSION, cronTrigger.CronExpression); System.assertEquals(0, cronTrigger.TimesTriggered); diff --git a/nebula-logger/core/tests/log-management/classes/LogBatchPurger_Tests.cls b/nebula-logger/core/tests/log-management/classes/LogBatchPurger_Tests.cls index d707c4dae..de294434a 100644 --- a/nebula-logger/core/tests/log-management/classes/LogBatchPurger_Tests.cls +++ b/nebula-logger/core/tests/log-management/classes/LogBatchPurger_Tests.cls @@ -4,68 +4,110 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class LogBatchPurger_Tests { - private static final Integer NUMBER_OF_LOG_ENTRIES = 10; + private static final Integer NUMBER_OF_LOG_ENTRIES_TO_CREATE = 3; + + private static Boolean ranPluginStart = false; + private static Boolean ranPluginExecute = false; + private static Boolean ranPluginFinish = false; + private static LoggerPlugin__mdt pluginConfiguration; + private static LoggerBatchableContext batchInput; + private static List pluginRecords; @TestSetup static void setupData() { + LoggerSObjectHandler.shouldExecute(false); LoggerSettings__c settings = Logger.getUserSettings(); settings.IsEnabled__c = false; settings.LoggingLevel__c = LoggingLevel.FINEST.name(); insert settings; Date scheduledDeletionDate = System.today().addDays(-7); - Log__c log = new Log__c(LogRetentionDate__c = scheduledDeletionDate, TransactionId__c = '1234'); + Log__c log = new Log__c(LogRetentionDate__c = scheduledDeletionDate); + LoggerMockDataCreator.createDataBuilder(log).populateRequiredFields().getRecord(); insert log; List logEntries = new List(); - for (Integer i = 0; i < NUMBER_OF_LOG_ENTRIES; i++) { + for (Integer i = 0; i < NUMBER_OF_LOG_ENTRIES_TO_CREATE; i++) { LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, LoggingLevel__c = LoggingLevel.INFO.name()); - + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); logEntries.add(logEntry); } insert logEntries; - LoggerTag__c tag = new LoggerTag__c(Name = 'My important tag'); + LoggerTag__c tag = (LoggerTag__c) LoggerMockDataCreator.createDataBuilder(Schema.LoggerTag__c.SObjectType).populateRequiredFields().getRecord(); insert tag; List logEntryTags = new List(); for (LogEntry__c logEntry : logEntries) { LogEntryTag__c logEntryTag = new LogEntryTag__c(LogEntry__c = logEntry.Id, Tag__c = tag.Id); + LoggerMockDataCreator.createDataBuilder(logEntryTag).populateRequiredFields().getRecord(); logEntryTags.add(logEntryTag); } insert logEntryTags; } + @IsTest + static void it_should_throw_an_exception_when_data_cannot_be_purged() { + LoggerTestConfigurator.setMock(new LoggerParameter__mdt(DeveloperName = 'EnableLoggerSystemMessages', Value__c = 'true')); + LogBatchPurger batchJobInstance = new LogBatchPurger(); + batchJobInstance.currentSObjectType = Schema.Log__c.SObjectType; + List nullLogsList = null; + Database.BatchableContext mockBatchableContext = LoggerMockDataCreator.createBatchableContext('some_fake_job_id'); + Exception thrownNullPointerException; + + try { + batchJobInstance.execute(mockBatchableContext, nullLogsList); + } catch (NullPointerException ex) { + thrownNullPointerException = ex; + } + + System.assertNotEquals(null, thrownNullPointerException); + } + + @IsTest + static void it_should_default_chained_job_batch_size_to_200() { + LogBatchPurger batchJobInstance = new LogBatchPurger(); + + System.assertEquals(200, batchJobInstance.chainedBatchSize); + } + + @IsTest + static void it_should_set_chained_job_batch_size() { + LogBatchPurger batchJobInstance = new LogBatchPurger(); + Integer specifiedBatchSize = 123; + + batchJobInstance.setChainedBatchSize(specifiedBatchSize); + + System.assertEquals(specifiedBatchSize, batchJobInstance.chainedBatchSize); + } + @IsTest static void it_should_delete_a_log_after_scheduled_deletion_date_when_system_messages_enabled() { LoggerSettings__c settings = Logger.getUserSettings(); settings.IsEnabled__c = true; settings.LoggingLevel__c = LoggingLevel.FINEST.name(); upsert settings; - - LoggerParameter.setMockParameter(new LoggerParameter__mdt(DeveloperName = 'EnableLoggerSystemMessages', Value__c = 'true')); - + LoggerTestConfigurator.setMock(new LoggerParameter__mdt(DeveloperName = 'EnableLoggerSystemMessages', Value__c = 'true')); System.assertEquals(true, Logger.getUserSettings().IsEnabled__c); System.assertEquals(true, LoggerParameter.getBoolean('EnableLoggerSystemMessages', null)); System.assertEquals(LoggingLevel.FINEST.name(), Logger.getUserSettings().LoggingLevel__c); - List logs = [SELECT Id, LogRetentionDate__c FROM Log__c]; List logEntries = [SELECT Id FROM LogEntry__c]; - System.assertEquals(1, logs.size()); - System.assertEquals(NUMBER_OF_LOG_ENTRIES, logEntries.size()); - + System.assertEquals(NUMBER_OF_LOG_ENTRIES_TO_CREATE, logEntries.size()); // Verify assumption that the log in the database has a deletion date in the past Log__c log = logs.get(0); System.assertNotEquals(null, log.LogRetentionDate__c); System.assert(log.LogRetentionDate__c < System.today()); - Test.startTest(); + LoggerSObjectHandler.shouldExecute(true); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + Database.executeBatch(new LogBatchPurger()); - Test.stopTest(); + Test.stopTest(); logs = [SELECT Id FROM Log__c WHERE Id IN :logs]; logEntries = [SELECT Id FROM LogEntry__c WHERE Id IN :logEntries]; System.assertEquals(0, logs.size(), logs); @@ -77,27 +119,25 @@ private class LogBatchPurger_Tests { LoggerSettings__c settings = Logger.getUserSettings(); settings.IsEnabled__c = true; upsert settings; - LoggerParameter.setMockParameter(new LoggerParameter__mdt(DeveloperName = 'EnableLoggerSystemMessages', Value__c = String.valueOf(false))); - + LoggerTestConfigurator.setMock(new LoggerParameter__mdt(DeveloperName = 'EnableLoggerSystemMessages', Value__c = String.valueOf(false))); System.assertEquals(true, Logger.getUserSettings().IsEnabled__c); System.assertEquals(false, LoggerParameter.getBoolean('EnableLoggerSystemMessages', null)); System.assertEquals(LoggingLevel.FINEST.name(), Logger.getUserSettings().LoggingLevel__c); - List logs = [SELECT Id, LogRetentionDate__c FROM Log__c]; List logEntries = [SELECT Id FROM LogEntry__c]; - System.assertEquals(1, logs.size()); - System.assertEquals(NUMBER_OF_LOG_ENTRIES, logEntries.size()); - + System.assertEquals(NUMBER_OF_LOG_ENTRIES_TO_CREATE, logEntries.size()); // Verify assumption that the log in the database has a deletion date in the past Log__c log = logs.get(0); System.assertNotEquals(null, log.LogRetentionDate__c); System.assert(log.LogRetentionDate__c < System.today()); - Test.startTest(); + LoggerSObjectHandler.shouldExecute(false); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + Database.executeBatch(new LogBatchPurger()); - Test.stopTest(); + Test.stopTest(); logs = [SELECT Id FROM Log__c WHERE Id IN :logs]; logEntries = [SELECT Id FROM LogEntry__c WHERE Id IN :logEntries]; System.assertEquals(0, logs.size(), logs); @@ -106,57 +146,60 @@ private class LogBatchPurger_Tests { @IsTest static void it_should_not_delete_a_log_before_scheduled_deletion_date() { + LoggerSObjectHandler.shouldExecute(false); List logs = [SELECT Id, LogRetentionDate__c FROM Log__c]; List logEntries = [SELECT Id FROM LogEntry__c]; - System.assertEquals(1, logs.size()); - System.assertEquals(NUMBER_OF_LOG_ENTRIES, logEntries.size()); - + System.assertEquals(NUMBER_OF_LOG_ENTRIES_TO_CREATE, logEntries.size()); // Set the log's deletion date to be in the future Log__c log = logs.get(0); log.LogRetentionDate__c = System.today().addDays(7); update log; log = [SELECT Id, LogRetentionDate__c FROM Log__c]; System.assert(log.LogRetentionDate__c > System.today()); - Test.startTest(); + LoggerSObjectHandler.shouldExecute(false); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + Database.executeBatch(new LogBatchPurger()); - Test.stopTest(); + Test.stopTest(); logs = [SELECT Id FROM Log__c WHERE Id IN :logs]; logEntries = [SELECT Id FROM LogEntry__c WHERE Id IN :logEntries]; System.assertEquals(1, logs.size()); - System.assertEquals(NUMBER_OF_LOG_ENTRIES, logEntries.size()); + System.assertEquals(NUMBER_OF_LOG_ENTRIES_TO_CREATE, logEntries.size()); } @IsTest static void it_should_not_delete_a_log_without_a_scheduled_deletion_date_and_with_log_entries() { + LoggerSObjectHandler.shouldExecute(false); List logs = [SELECT Id, TotalLogEntries__c, LogRetentionDate__c FROM Log__c]; List logEntries = [SELECT Id FROM LogEntry__c]; - System.assertEquals(1, logs.size()); - System.assertEquals(NUMBER_OF_LOG_ENTRIES, logs.get(0).TotalLogEntries__c); - System.assertEquals(NUMBER_OF_LOG_ENTRIES, logEntries.size()); - + System.assertEquals(NUMBER_OF_LOG_ENTRIES_TO_CREATE, logs.get(0).TotalLogEntries__c); + System.assertEquals(NUMBER_OF_LOG_ENTRIES_TO_CREATE, logEntries.size()); // Set the log's deletion date to be null Log__c log = logs.get(0); log.LogRetentionDate__c = null; update log; log = [SELECT Id, LogRetentionDate__c FROM Log__c]; System.assertEquals(null, log.LogRetentionDate__c); - Test.startTest(); + LoggerSObjectHandler.shouldExecute(false); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + Database.executeBatch(new LogBatchPurger()); - Test.stopTest(); + Test.stopTest(); logs = [SELECT Id FROM Log__c WHERE Id IN :logs]; logEntries = [SELECT Id FROM LogEntry__c WHERE Id IN :logEntries]; System.assertEquals(1, logs.size(), logs); - System.assertEquals(NUMBER_OF_LOG_ENTRIES, logEntries.size(), logEntries); + System.assertEquals(NUMBER_OF_LOG_ENTRIES_TO_CREATE, logEntries.size(), logEntries); } @IsTest static void it_should_delete_a_log_with_a_scheduled_deletion_date_and_without_log_entries() { + LoggerSObjectHandler.shouldExecute(false); Date retentionDate = System.today().addDays(-1); Log__c log = new Log__c(TransactionId__c = '5678'); insert log; @@ -165,17 +208,20 @@ private class LogBatchPurger_Tests { log = [SELECT Id, LogRetentionDate__c, TotalLogEntries__c FROM Log__c WHERE Id = :log.Id]; System.assertEquals(retentionDate, log.LogRetentionDate__c, 'Log should not have a retention date'); System.assertEquals(0, log.TotalLogEntries__c, 'Log should not have any related log entries'); - Test.startTest(); + LoggerSObjectHandler.shouldExecute(false); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + Database.executeBatch(new LogBatchPurger()); - Test.stopTest(); + Test.stopTest(); List matchingLogs = [SELECT Id FROM Log__c WHERE Id = :log.Id]; System.assertEquals(0, matchingLogs.size(), 'Test log should have been deleted'); } @IsTest static void it_should_delete_a_log_without_a_scheduled_deletion_date_and_without_log_entries() { + LoggerSObjectHandler.shouldExecute(false); Log__c log = new Log__c(TransactionId__c = '5678'); insert log; log.LogRetentionDate__c = null; @@ -183,12 +229,191 @@ private class LogBatchPurger_Tests { log = [SELECT Id, LogRetentionDate__c, TotalLogEntries__c FROM Log__c WHERE Id = :log.Id]; System.assertEquals(null, log.LogRetentionDate__c, 'Log should not have a retention date'); System.assertEquals(0, log.TotalLogEntries__c, 'Log should not have any related log entries'); - Test.startTest(); + LoggerSObjectHandler.shouldExecute(false); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + Database.executeBatch(new LogBatchPurger()); - Test.stopTest(); + Test.stopTest(); List matchingLogs = [SELECT Id FROM Log__c WHERE Id = :log.Id]; System.assertEquals(0, matchingLogs.size(), 'Test log should have been deleted'); } + + @IsTest + static void it_should_run_apex_plugin_in_start_method() { + LoggerSObjectHandler.shouldExecute(false); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerPlugin__mdt mockPluginConfiguration = new LoggerPlugin__mdt( + DeveloperName = 'Mock_Plugin', + IsEnabled__c = true, + BatchPurgerApexClass__c = MockBatchPurgerPlugin.class.getName() + ); + LoggerTestConfigurator.setMock(mockPluginConfiguration); + LogBatchPurger batchJobInstance = new LogBatchPurger(); + batchJobInstance.currentSObjectType = Schema.LogEntry__c.SObjectType; + System.assertEquals(false, ranPluginStart); + System.assertEquals(false, ranPluginExecute); + System.assertEquals(false, ranPluginFinish); + System.assertEquals(null, pluginConfiguration); + System.assertEquals(null, batchInput); + Database.BatchableContext mockBatchableContext = LoggerMockDataCreator.createBatchableContext('some_fake_job_id'); + + batchJobInstance.start(mockBatchableContext); + + LoggerBatchableContext expectedInput = new LoggerBatchableContext(mockBatchableContext, batchJobInstance.currentSObjectType); + System.assertEquals( + 3, + batchJobInstance.getExecutedApexPlugins().size(), + 'The map of executed Apex plugins should have 3 keys - one for each enum value in LogBatchPurger.BatchableMethod (START, EXECUTE, and FINISH)' + ); + System.assertEquals( + 1, + batchJobInstance.getExecutedApexPlugins().get(LogBatchPurger.BatchableMethod.START).size(), + 'One Apex plugin should have run in the batch job\'s start method' + ); + System.assertEquals( + 0, + batchJobInstance.getExecutedApexPlugins().get(LogBatchPurger.BatchableMethod.EXECUTE).size(), + 'No Apex plugins should have run in the batch job\'s execute method' + ); + System.assertEquals( + 0, + batchJobInstance.getExecutedApexPlugins().get(LogBatchPurger.BatchableMethod.FINISH).size(), + 'No Apex plugins should have run in the batch job\'s finish method' + ); + LoggerPlugin.Batchable apexStartPlugin = batchJobInstance.getExecutedApexPlugins().get(LogBatchPurger.BatchableMethod.START).get(0); + System.assertEquals(true, apexStartPlugin instanceof MockBatchPurgerPlugin, apexStartPlugin); + System.assertEquals(true, ranPluginStart); + System.assertEquals(false, ranPluginExecute); + System.assertEquals(false, ranPluginFinish); + System.assertEquals(mockPluginConfiguration, pluginConfiguration); + System.assertEquals(expectedInput.batchableContext, batchInput.batchableContext); + System.assertEquals(expectedInput.sobjectType, batchInput.sobjectType); + } + + @IsTest + static void it_should_run_apex_plugin_in_execute_method() { + LoggerSObjectHandler.shouldExecute(false); + LoggerPlugin__mdt mockPluginConfiguration = new LoggerPlugin__mdt( + DeveloperName = 'Mock_Plugin', + IsEnabled__c = true, + BatchPurgerApexClass__c = MockBatchPurgerPlugin.class.getName() + ); + LoggerTestConfigurator.setMock(mockPluginConfiguration); + LogBatchPurger batchJobInstance = new LogBatchPurger(); + batchJobInstance.currentSObjectType = Schema.LogEntry__c.SObjectType; + System.assertEquals(false, ranPluginStart); + System.assertEquals(false, ranPluginExecute); + System.assertEquals(false, ranPluginFinish); + System.assertEquals(null, pluginConfiguration); + System.assertEquals(null, batchInput); + List logsToDelete = [SELECT Id FROM Log__c]; + System.assertNotEquals(0, logsToDelete.size()); + Database.BatchableContext mockBatchableContext = LoggerMockDataCreator.createBatchableContext('some_fake_job_id'); + + batchJobInstance.execute(mockBatchableContext, logsToDelete); + + LoggerBatchableContext expectedInput = new LoggerBatchableContext(mockBatchableContext, batchJobInstance.currentSObjectType); + System.assertEquals( + 3, + batchJobInstance.getExecutedApexPlugins().size(), + 'The map of executed Apex plugins should have 3 keys - one for each enum value in LogBatchPurger.BatchableMethod (START, EXECUTE, and FINISH)' + ); + System.assertEquals( + 0, + batchJobInstance.getExecutedApexPlugins().get(LogBatchPurger.BatchableMethod.START).size(), + 'No Apex plugins should have run in the batch job\'s start method' + ); + System.assertEquals( + 1, + batchJobInstance.getExecutedApexPlugins().get(LogBatchPurger.BatchableMethod.EXECUTE).size(), + 'One Apex plugin should have run in the batch job\'s execute method' + ); + System.assertEquals( + 0, + batchJobInstance.getExecutedApexPlugins().get(LogBatchPurger.BatchableMethod.FINISH).size(), + 'No Apex plugins should have run in the batch job\'s finish method' + ); + LoggerPlugin.Batchable apexExecutePlugin = batchJobInstance.getExecutedApexPlugins().get(LogBatchPurger.BatchableMethod.EXECUTE).get(0); + System.assertEquals(true, apexExecutePlugin instanceof MockBatchPurgerPlugin, apexExecutePlugin); + System.assertEquals(false, ranPluginStart); + System.assertEquals(true, ranPluginExecute); + System.assertEquals(false, ranPluginFinish); + System.assertEquals(mockPluginConfiguration, pluginConfiguration); + System.assertEquals(expectedInput.batchableContext, batchInput.batchableContext); + logsToDelete = [SELECT Id FROM Log__c WHERE Id IN :logsToDelete]; + System.assertEquals(0, logsToDelete.size(), 'All logs should have still been deleted by LogBatchPurger after running plugins: ' + logsToDelete); + } + + @IsTest + static void it_should_run_apex_plugin_in_finish_method() { + LoggerSObjectHandler.shouldExecute(false); + LoggerPlugin__mdt mockPluginConfiguration = new LoggerPlugin__mdt( + DeveloperName = 'Mock_Plugin', + IsEnabled__c = true, + BatchPurgerApexClass__c = MockBatchPurgerPlugin.class.getName() + ); + LoggerTestConfigurator.setMock(mockPluginConfiguration); + LogBatchPurger batchJobInstance = new LogBatchPurger(); + batchJobInstance.currentSObjectType = Schema.LogEntry__c.SObjectType; + System.assertEquals(false, ranPluginStart); + System.assertEquals(false, ranPluginExecute); + System.assertEquals(false, ranPluginFinish); + System.assertEquals(null, pluginConfiguration); + System.assertEquals(null, batchInput); + Database.BatchableContext mockBatchableContext = LoggerMockDataCreator.createBatchableContext('some_fake_job_id'); + + batchJobInstance.finish(mockBatchableContext); + + LoggerBatchableContext expectedInput = new LoggerBatchableContext(mockBatchableContext, batchJobInstance.currentSObjectType); + System.assertEquals( + 3, + batchJobInstance.getExecutedApexPlugins().size(), + 'The map of executed Apex plugins should have 3 keys - one for each enum value in LogBatchPurger.BatchableMethod (START, EXECUTE, and FINISH)' + ); + System.assertEquals( + 0, + batchJobInstance.getExecutedApexPlugins().get(LogBatchPurger.BatchableMethod.START).size(), + 'No Apex plugins should have run in the batch job\'s start method' + ); + System.assertEquals( + 0, + batchJobInstance.getExecutedApexPlugins().get(LogBatchPurger.BatchableMethod.EXECUTE).size(), + 'No Apex plugins should have run in the batch job\'s execute method' + ); + System.assertEquals( + 1, + batchJobInstance.getExecutedApexPlugins().get(LogBatchPurger.BatchableMethod.FINISH).size(), + 'One Apex plugin should have run in the batch job\'s finish method' + ); + LoggerPlugin.Batchable apexFinishPlugin = batchJobInstance.getExecutedApexPlugins().get(LogBatchPurger.BatchableMethod.FINISH).get(0); + System.assertEquals(true, apexFinishPlugin instanceof MockBatchPurgerPlugin, apexFinishPlugin); + System.assertEquals(false, ranPluginStart); + System.assertEquals(false, ranPluginExecute); + System.assertEquals(true, ranPluginFinish); + System.assertEquals(mockPluginConfiguration, pluginConfiguration); + System.assertEquals(expectedInput.sobjectType, batchInput.sobjectType); + } + + public class MockBatchPurgerPlugin implements LoggerPlugin.Batchable { + public void start(LoggerPlugin__mdt configuration, LoggerBatchableContext input) { + ranPluginStart = true; + pluginConfiguration = configuration; + batchInput = input; + } + + public void execute(LoggerPlugin__mdt configuration, LoggerBatchableContext input, List scope) { + ranPluginExecute = true; + pluginConfiguration = configuration; + batchInput = input; + pluginRecords = scope; + } + + public void finish(LoggerPlugin__mdt configuration, LoggerBatchableContext input) { + ranPluginFinish = true; + pluginConfiguration = configuration; + batchInput = input; + } + } } diff --git a/nebula-logger/core/tests/log-management/classes/LogEntryEventHandler_Tests.cls b/nebula-logger/core/tests/log-management/classes/LogEntryEventHandler_Tests.cls index f1240d83e..154a3dad5 100644 --- a/nebula-logger/core/tests/log-management/classes/LogEntryEventHandler_Tests.cls +++ b/nebula-logger/core/tests/log-management/classes/LogEntryEventHandler_Tests.cls @@ -4,55 +4,85 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class LogEntryEventHandler_Tests { private static final String MOCK_RELEASE_NUMBER = '230.12.2'; private static final String MOCK_RELEASE_VERSION = 'Spring \'21 Patch 12.2'; @IsTest static void it_should_return_the_logEntryEvent_sobjectType() { - Test.startTest(); System.assertEquals(Schema.LogEntryEvent__e.SObjectType, new LogEntryEventHandler().getSObjectType()); - Test.stopTest(); + } + + @IsTest + static void it_should_not_run_when_disabled_via_configuration() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntryEvent__e.SObjectType).IsEnabled__c = false; + LogEntryEvent__e logEntryEvent = createLogEntryEvent(); + + LoggerDataStore.getEventBus().publishRecord(logEntryEvent); + LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); + + System.assertEquals( + 0, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should not have executed' + ); } @IsTest static void it_should_gracefully_skip_execution_when_logEntryEvents_list_is_empty() { - List logEntryEvents = new List(); - System.assert(logEntryEvents.isEmpty()); + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.Log__c.SObjectType).IsEnabled__c = false; + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntry__c.SObjectType).IsEnabled__c = false; + Integer countOfLogs = [SELECT COUNT() FROM Log__c]; + System.assertEquals(0, countOfLogs); + Integer countOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; + System.assertEquals(0, countOfLogEntries); - Test.startTest(); - new LogEntryEventHandler().executeBeforeInsert(logEntryEvents); - new LogEntryEventHandler().executeAfterInsert(logEntryEvents); - Test.stopTest(); + List saveResults = LoggerMockDataStore.getEventBus().publishRecords(new List()); + LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); + + System.assertEquals(true, saveResults.isEmpty()); + System.assertEquals( + 1, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed one time for AFTER_INSERT' + ); + countOfLogs = [SELECT COUNT() FROM Log__c]; + System.assertEquals(0, countOfLogs); + countOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; + System.assertEquals(0, countOfLogEntries); } @IsTest static void it_should_not_create_log_or_log_entry_data_when_platform_event_storage_is_disabled() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.Log__c.SObjectType).IsEnabled__c = false; + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntry__c.SObjectType).IsEnabled__c = false; Integer countOfLogs = [SELECT COUNT() FROM Log__c]; System.assertEquals(0, countOfLogs); Integer countOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; System.assertEquals(0, countOfLogEntries); - - Logger.getUserSettings().IsSavingEnabled__c = true; LoggerSettings__c settings = Logger.getUserSettings(); - settings.IsPlatformEventStorageEnabled__c = false; + settings.IsEnabled__c = true; + settings.IsSavingEnabled__c = true; + settings.DefaultPlatformEventStorageLocation__c = null; upsert settings; - LogEntryEvent__e logEntryEvent = new LogEntryEvent__e( - EpochTimestamp__c = System.now().getTime(), - LoggedById__c = UserInfo.getUserId(), - Message__c = 'my message', - Timestamp__c = System.now(), - TransactionEntryNumber__c = 1, - TransactionId__c = '123-456-789-0' - ); + LogEntryEvent__e logEntryEvent = createLogEntryEvent(); - Test.startTest(); - Database.SaveResult saveResult = EventBus.publish(logEntryEvent); - Test.stopTest(); + Database.SaveResult saveResult = LoggerMockDataStore.getEventBus().publishRecord(logEntryEvent); + LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); - + System.assertEquals( + 1, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed one time for AFTER_INSERT' + ); countOfLogs = [SELECT COUNT() FROM Log__c]; System.assertEquals(0, countOfLogs); countOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; @@ -60,165 +90,61 @@ private class LogEntryEventHandler_Tests { } @IsTest - static void it_should_normalize_simple_event_data_into_log_and_log_entry() { - String transactionId = '123-456-789-0'; + static void it_should_normalize_event_data_into_log_and_log_entry() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.Log__c.SObjectType).IsEnabled__c = false; + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntry__c.SObjectType).IsEnabled__c = false; + LogEntryEvent__e logEntryEvent = createLogEntryEvent(); - LogEntryEvent__e logEntryEvent = new LogEntryEvent__e( - EpochTimestamp__c = System.now().getTime(), - LoggedById__c = UserInfo.getUserId(), - Message__c = 'my message', - Timestamp__c = System.now(), - TransactionEntryNumber__c = 1, - TransactionId__c = transactionId - ); - - Test.startTest(); - Database.SaveResult saveResult = EventBus.publish(logEntryEvent); - Test.stopTest(); + Database.SaveResult saveResult = LoggerMockDataStore.getEventBus().publishRecord(logEntryEvent); + LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); - + System.assertEquals( + 1, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed one time for AFTER_INSERT' + ); Log__c log = getLog(); System.assertEquals(1, log.LogEntries__r.size()); LogEntry__c logEntry = log.LogEntries__r.get(0); - System.assertEquals(logEntryEvent.TransactionId__c, log.TransactionId__c); validateLogFields(logEntryEvent, log); validateLogEntryFields(logEntryEvent, logEntry); } - @IsTest - static void it_should_normalize_complex_event_data_into_log_and_log_entry() { - String transactionId = '123-456-789-0'; - User currentUser = getCurrentUser(); - DmlException dmlException = new DmlException(); - - LogEntryEvent__e logEntryEvent = new LogEntryEvent__e( - ApiVersion__c = '99.0', - EpochTimestamp__c = System.now().getTime(), - ExceptionStackTrace__c = dmlException.getStackTraceString(), - ExceptionType__c = dmlException.getTypeName(), - LimitsAggregateQueriesMax__c = 987, - LimitsAggregateQueriesUsed__c = 123, - LimitsAsyncCallsMax__c = 987, - LimitsAsyncCallsUsed__c = 123, - LimitsCalloutsMax__c = 987, - LimitsCalloutsUsed__c = 123, - LimitsCpuTimeMax__c = 987, - LimitsCpuTimeUsed__c = 123, - LimitsDmlRowsMax__c = 987, - LimitsDmlRowsUsed__c = 123, - LimitsDmlStatementsMax__c = 987, - LimitsDmlStatementsUsed__c = 123, - LimitsEmailInvocationsMax__c = 987, - LimitsEmailInvocationsUsed__c = 123, - LimitsFutureCallsMax__c = 987, - LimitsFutureCallsUsed__c = 123, - LimitsHeapSizeMax__c = 987, - LimitsHeapSizeUsed__c = 123, - LimitsMobilePushApexCallsMax__c = 987, - LimitsMobilePushApexCallsUsed__c = 123, - LimitsPublishImmediateDmlStatementsMax__c = 987, - LimitsPublishImmediateDmlStatementsUsed__c = 123, - LimitsQueueableJobsMax__c = 987, - LimitsQueueableJobsUsed__c = 123, - LimitsSoqlQueriesMax__c = 987, - LimitsSoqlQueriesUsed__c = 123, - LimitsSoqlQueryLocatorRowsMax__c = 987, - LimitsSoqlQueryLocatorRowsUsed__c = 123, - LimitsSoqlQueryRowsMax__c = 987, - LimitsSoqlQueryRowsUsed__c = 123, - LimitsSoslSearchesMax__c = 987, - LimitsSoslSearchesUsed__c = 123, - Locale__c = 'es-ES', - LoggerVersionNumber__c = 'v4.6.10', - LoggedById__c = UserInfo.getUserId(), - LoggingLevel__c = 'DEBUG', - LoggingLevelOrdinal__c = 9, - LoginDomain__c = 'https://fake.my.salesforce.com', - LoginHistoryId__c = '255.255.255.255', - LoginType__c = null, - LogoutUrl__c = null, - Message__c = 'My message', - MessageTruncated__c = false, - NetworkId__c = 'Fake-ID', - OriginLocation__c = 'right here', - OriginType__c = 'Apex', - ProfileId__c = currentUser.ProfileId, - RecordId__c = currentUser.Id, - RecordJson__c = JSON.serializePretty(currentUser), - RecordSObjectClassification__c = 'Standard Object', - RecordSObjectType__c = 'User', - Scenario__c = 'Apex test execution', - SessionId__c = null, - SessionSecurityLevel__c = null, - SessionType__c = null, - SourceIp__c = null, - StackTrace__c = 'I started here \nand then went there', - SystemMode__c = System.Quiddity.SYNCHRONOUS.name(), - ThemeDisplayed__c = 'SomeTheme', - Timestamp__c = System.now(), - TimeZoneId__c = 'fake-id', - TimeZoneName__c = 'My time zone name', - TransactionEntryNumber__c = 1, - TransactionId__c = transactionId, - TriggerIsExecuting__c = false, - TriggerOperationType__c = 'SomeOperation', - TriggerSObjectType__c = 'Account', - UserLoggingLevel__c = 'DEBUG', - UserLoggingLevelOrdinal__c = 9, - UserRoleId__c = currentUser.UserRoleId, - UserType__c = null - ); - - Test.startTest(); - Database.SaveResult saveResult = EventBus.publish(logEntryEvent); - Test.stopTest(); - - System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); - - Log__c log = getLog(); - System.assertEquals(1, log.LogEntries__r.size()); - LogEntry__c logEntry = log.LogEntries__r.get(0); - - validateLogFields(logEntryEvent, log); - validateLogEntryFields(logEntryEvent, logEntry); - } - @IsTest static void it_should_normalize_event_data_for_multiple_transactions_into_multiple_logs() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.Log__c.SObjectType).IsEnabled__c = false; + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntry__c.SObjectType).IsEnabled__c = false; List transactionIds = new List{ '123-456', '789-0' }; System.assertEquals(2, transactionIds.size()); - List logEntryEvents = new List(); for (Integer i = 0; i < transactionIds.size(); i++) { - LogEntryEvent__e logEntryEvent = new LogEntryEvent__e( - EpochTimestamp__c = System.now().getTime(), - Message__c = 'my message', - Timestamp__c = System.now(), - TransactionEntryNumber__c = i, - TransactionId__c = transactionIds.get(i) - ); - + LogEntryEvent__e logEntryEvent = createLogEntryEvent(); + logEntryEvent.TransactionEntryNumber__c = i; + logEntryEvent.TransactionId__c = transactionIds.get(i); logEntryEvents.add(logEntryEvent); } System.assertEquals(transactionIds.size(), logEntryEvents.size()); - Test.startTest(); - List saveResults = EventBus.publish(logEntryEvents); - Test.getEventBus().deliver(); - System.assertEquals(transactionIds.size(), saveResults.size()); - Test.stopTest(); + List saveResults = LoggerMockDataStore.getEventBus().publishRecords(logEntryEvents); + LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); + System.assertEquals(transactionIds.size(), saveResults.size()); for (Database.SaveResult saveResult : saveResults) { System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); } - + System.assertEquals( + 1, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed one time for AFTER_INSERT' + ); List logs = [SELECT Id, TransactionId__c, (SELECT Id FROM LogEntries__r) FROM Log__c]; - System.assertEquals(2, logs.size(), logs); - - // Convert the list of txn IDs to a set so we can use `contains()` Set uniqueTransactionIds = new Set(transactionIds); for (Log__c log : logs) { System.assert(uniqueTransactionIds.contains(log.TransactionId__c), log.TransactionId__c); @@ -268,32 +194,30 @@ private class LogEntryEventHandler_Tests { @IsTest static void it_should_create_tag_records_when_enabled() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.Log__c.SObjectType).IsEnabled__c = false; + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntry__c.SObjectType).IsEnabled__c = false; System.assertEquals(true, LoggerParameter.TAGGING_IS_ENABLED, 'Tagging is not enabled within test context, cannot execute tagging test'); - List tags = new List{ 'test-tag-1', 'test-tag-2' }; - LogEntryEvent__e logEntryEvent = new LogEntryEvent__e( - EpochTimestamp__c = System.now().getTime(), - Message__c = 'my message', - Timestamp__c = System.now(), - Tags__c = String.join(tags, '\n'), - TransactionEntryNumber__c = 1, - TransactionId__c = '123-456-789-0' - ); + LogEntryEvent__e logEntryEvent = createLogEntryEvent(); + logEntryEvent.Tags__c = String.join(tags, '\n'); - Test.startTest(); - Database.SaveResult saveResult = EventBus.publish(logEntryEvent); - Test.stopTest(); + Database.SaveResult saveResult = LoggerMockDataStore.getEventBus().publishRecord(logEntryEvent); + LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); - + System.assertEquals( + 1, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed one time for AFTER_INSERT' + ); Log__c log = getLog(); System.assertEquals(1, log.LogEntries__r.size()); LogEntry__c logEntry = log.LogEntries__r.get(0); - System.assertEquals(logEntryEvent.TransactionId__c, log.TransactionId__c); validateLogFields(logEntryEvent, log); validateLogEntryFields(logEntryEvent, logEntry); - List logEntryTags = [SELECT Id, LogEntry__c, Tag__c, Tag__r.Name FROM LogEntryTag__c WHERE LogEntry__c = :logEntry.Id]; System.assertEquals(tags.size(), logEntryTags.size()); Set tagsSet = new Set(tags); @@ -304,35 +228,32 @@ private class LogEntryEventHandler_Tests { @IsTest static void it_should_reuse_existing_tag_records() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.Log__c.SObjectType).IsEnabled__c = false; + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntry__c.SObjectType).IsEnabled__c = false; System.assertEquals(true, LoggerParameter.TAGGING_IS_ENABLED, 'Tagging is not enabled within test context, cannot execute tagging test'); - String testTagName = 'Some tag!'; LoggerTag__c tag = new LoggerTag__c(Name = testTagName); insert tag; + LogEntryEvent__e logEntryEvent = createLogEntryEvent(); + logEntryEvent.Tags__c = testTagName; - LogEntryEvent__e logEntryEvent = new LogEntryEvent__e( - EpochTimestamp__c = System.now().getTime(), - Message__c = 'my message', - Timestamp__c = System.now(), - Tags__c = testTagName, - TransactionEntryNumber__c = 1, - TransactionId__c = '123-456-789-0' - ); - - Test.startTest(); - Database.SaveResult saveResult = EventBus.publish(logEntryEvent); - Test.stopTest(); + Database.SaveResult saveResult = LoggerMockDataStore.getEventBus().publishRecord(logEntryEvent); + LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); - + System.assertEquals( + 1, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed one time for AFTER_INSERT' + ); Log__c log = getLog(); System.assertEquals(1, log.LogEntries__r.size()); LogEntry__c logEntry = log.LogEntries__r.get(0); - System.assertEquals(logEntryEvent.TransactionId__c, log.TransactionId__c); validateLogFields(logEntryEvent, log); validateLogEntryFields(logEntryEvent, logEntry); - Integer countOfTagsWithTagName = [SELECT COUNT() FROM LoggerTag__c WHERE Name = :testTagName]; System.assertEquals(1, countOfTagsWithTagName); LogEntryTag__c logEntryTag = [SELECT Id, LogEntry__c, Tag__c, Tag__r.Name FROM LogEntryTag__c WHERE LogEntry__c = :logEntry.Id]; @@ -342,20 +263,16 @@ private class LogEntryEventHandler_Tests { @IsTest static void it_should_append_tags_for_contains_rule() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.Log__c.SObjectType).IsEnabled__c = false; + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntry__c.SObjectType).IsEnabled__c = false; System.assertEquals(true, LoggerParameter.TAGGING_IS_ENABLED, 'Tagging is not enabled within test context, cannot execute tagging test'); - - LogEntryEvent__e logEntryEvent = new LogEntryEvent__e( - EpochTimestamp__c = System.now().getTime(), - Message__c = 'my message', - Timestamp__c = System.now(), - Tags__c = null, - TransactionEntryNumber__c = 1, - TransactionId__c = '123-456-789-0' - ); - - Test.startTest(); + LogEntryEvent__e logEntryEvent = createLogEntryEvent(); + logEntryEvent.Message__c = 'my message'; + logEntryEvent.Tags__c = null; String configuredTagName = 'CMDT Tag'; - LogEntryEventHandler.TAG_ASSIGNMENT_RULES.add( + LoggerTestConfigurator.setMock( new LogEntryTagRule__mdt( SObjectField__c = Schema.LogEntry__c.Message__c.getDescribe().getName(), ComparisonType__c = 'CONTAINS', @@ -363,19 +280,22 @@ private class LogEntryEventHandler_Tests { Tags__c = configuredTagName ) ); - Database.SaveResult saveResult = EventBus.publish(logEntryEvent); - Test.stopTest(); - System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); + Database.SaveResult saveResult = LoggerMockDataStore.getEventBus().publishRecord(logEntryEvent); + LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); + System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); + System.assertEquals( + 1, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed one time for AFTER_INSERT' + ); Log__c log = getLog(); System.assertEquals(1, log.LogEntries__r.size()); LogEntry__c logEntry = log.LogEntries__r.get(0); - System.assertEquals(logEntryEvent.TransactionId__c, log.TransactionId__c); validateLogFields(logEntryEvent, log); validateLogEntryFields(logEntryEvent, logEntry); - Integer countOfTagsWithTagName = [SELECT COUNT() FROM LoggerTag__c WHERE Name = :configuredTagName]; System.assertEquals(1, countOfTagsWithTagName); LogEntryTag__c logEntryTag = [SELECT Id, LogEntry__c, Tag__c, Tag__r.Name FROM LogEntryTag__c WHERE LogEntry__c = :logEntry.Id]; @@ -384,20 +304,15 @@ private class LogEntryEventHandler_Tests { @IsTest static void it_should_append_tags_for_equals_rule() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.Log__c.SObjectType).IsEnabled__c = false; + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntry__c.SObjectType).IsEnabled__c = false; System.assertEquals(true, LoggerParameter.TAGGING_IS_ENABLED, 'Tagging is not enabled within test context, cannot execute tagging test'); - - LogEntryEvent__e logEntryEvent = new LogEntryEvent__e( - EpochTimestamp__c = System.now().getTime(), - Message__c = 'my message', - Timestamp__c = System.now(), - Tags__c = null, - TransactionEntryNumber__c = 1, - TransactionId__c = '123-456-789-0' - ); - - Test.startTest(); + LogEntryEvent__e logEntryEvent = createLogEntryEvent(); + logEntryEvent.Tags__c = null; String configuredTagName = 'CMDT Tag'; - LogEntryEventHandler.TAG_ASSIGNMENT_RULES.add( + LoggerTestConfigurator.setMock( new LogEntryTagRule__mdt( SObjectField__c = Schema.LogEntry__c.Message__c.getDescribe().getName(), ComparisonType__c = 'EQUALS', @@ -405,19 +320,22 @@ private class LogEntryEventHandler_Tests { Tags__c = configuredTagName ) ); - Database.SaveResult saveResult = EventBus.publish(logEntryEvent); - Test.stopTest(); - System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); + Database.SaveResult saveResult = LoggerMockDataStore.getEventBus().publishRecord(logEntryEvent); + LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); + System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); + System.assertEquals( + 1, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed one time for AFTER_INSERT' + ); Log__c log = getLog(); System.assertEquals(1, log.LogEntries__r.size()); LogEntry__c logEntry = log.LogEntries__r.get(0); - System.assertEquals(logEntryEvent.TransactionId__c, log.TransactionId__c); validateLogFields(logEntryEvent, log); validateLogEntryFields(logEntryEvent, logEntry); - Integer countOfTagsWithTagName = [SELECT COUNT() FROM LoggerTag__c WHERE Name = :configuredTagName]; System.assertEquals(1, countOfTagsWithTagName); LogEntryTag__c logEntryTag = [SELECT Id, LogEntry__c, Tag__c, Tag__r.Name FROM LogEntryTag__c WHERE LogEntry__c = :logEntry.Id]; @@ -426,22 +344,17 @@ private class LogEntryEventHandler_Tests { @IsTest static void it_should_append_tags_for_regex_rule() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.Log__c.SObjectType).IsEnabled__c = false; + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntry__c.SObjectType).IsEnabled__c = false; System.assertEquals(true, LoggerParameter.TAGGING_IS_ENABLED, 'Tagging is not enabled within test context, cannot execute tagging test'); - String zipCodeRegEx = '(^[0-9]{4}?[0-9]$|^[0-9]{4}?[0-9]-[0-9]{4}$)'; - - LogEntryEvent__e logEntryEvent = new LogEntryEvent__e( - EpochTimestamp__c = System.now().getTime(), - Message__c = '94541', - Timestamp__c = System.now(), - Tags__c = null, - TransactionEntryNumber__c = 1, - TransactionId__c = '123-456-789-0' - ); - - Test.startTest(); + LogEntryEvent__e logEntryEvent = createLogEntryEvent(); + logEntryEvent.Message__c = '94541'; + logEntryEvent.Tags__c = null; String configuredTagName = 'CMDT Tag'; - LogEntryEventHandler.TAG_ASSIGNMENT_RULES.add( + LoggerTestConfigurator.setMock( new LogEntryTagRule__mdt( SObjectField__c = Schema.LogEntry__c.Message__c.getDescribe().getName(), ComparisonType__c = 'MATCHES_REGEX', @@ -449,19 +362,22 @@ private class LogEntryEventHandler_Tests { Tags__c = configuredTagName ) ); - Database.SaveResult saveResult = EventBus.publish(logEntryEvent); - Test.stopTest(); - System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); + Database.SaveResult saveResult = LoggerMockDataStore.getEventBus().publishRecord(logEntryEvent); + LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); + System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); + System.assertEquals( + 1, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed one time for AFTER_INSERT' + ); Log__c log = getLog(); System.assertEquals(1, log.LogEntries__r.size()); LogEntry__c logEntry = log.LogEntries__r.get(0); - System.assertEquals(logEntryEvent.TransactionId__c, log.TransactionId__c); validateLogFields(logEntryEvent, log); validateLogEntryFields(logEntryEvent, logEntry); - Integer countOfTagsWithTagName = [SELECT COUNT() FROM LoggerTag__c WHERE Name = :configuredTagName]; System.assertEquals(1, countOfTagsWithTagName); LogEntryTag__c logEntryTag = [SELECT Id, LogEntry__c, Tag__c, Tag__r.Name FROM LogEntryTag__c WHERE LogEntry__c = :logEntry.Id]; @@ -470,20 +386,16 @@ private class LogEntryEventHandler_Tests { @IsTest static void it_should_append_tags_for_startsWith_rule() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.Log__c.SObjectType).IsEnabled__c = false; + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntry__c.SObjectType).IsEnabled__c = false; System.assertEquals(true, LoggerParameter.TAGGING_IS_ENABLED, 'Tagging is not enabled within test context, cannot execute tagging test'); - - LogEntryEvent__e logEntryEvent = new LogEntryEvent__e( - EpochTimestamp__c = System.now().getTime(), - Message__c = 'my message', - Timestamp__c = System.now(), - Tags__c = null, - TransactionEntryNumber__c = 1, - TransactionId__c = '123-456-789-0' - ); - - Test.startTest(); + LogEntryEvent__e logEntryEvent = createLogEntryEvent(); + logEntryEvent.Message__c = 'my message'; + logEntryEvent.Tags__c = null; String configuredTagName = 'CMDT Tag'; - LogEntryEventHandler.TAG_ASSIGNMENT_RULES.add( + LoggerTestConfigurator.setMock( new LogEntryTagRule__mdt( SObjectField__c = Schema.LogEntry__c.Message__c.getDescribe().getName(), ComparisonType__c = 'STARTS_WITH', @@ -491,19 +403,22 @@ private class LogEntryEventHandler_Tests { Tags__c = configuredTagName ) ); - Database.SaveResult saveResult = EventBus.publish(logEntryEvent); - Test.stopTest(); - System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); + Database.SaveResult saveResult = LoggerMockDataStore.getEventBus().publishRecord(logEntryEvent); + LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); + System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); + System.assertEquals( + 1, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed one time for AFTER_INSERT' + ); Log__c log = getLog(); System.assertEquals(1, log.LogEntries__r.size()); LogEntry__c logEntry = log.LogEntries__r.get(0); - System.assertEquals(logEntryEvent.TransactionId__c, log.TransactionId__c); validateLogFields(logEntryEvent, log); validateLogEntryFields(logEntryEvent, logEntry); - Integer countOfTagsWithTagName = [SELECT COUNT() FROM LoggerTag__c WHERE Name = :configuredTagName]; System.assertEquals(1, countOfTagsWithTagName); LogEntryTag__c logEntryTag = [SELECT Id, LogEntry__c, Tag__c, Tag__r.Name FROM LogEntryTag__c WHERE LogEntry__c = :logEntry.Id]; @@ -512,37 +427,32 @@ private class LogEntryEventHandler_Tests { @IsTest static void it_should_set_api_release_number_and_api_release_version_from_callout_when_enabled() { - Test.setMock(HttpCalloutMock.class, new SuccessCalloutMock()); + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.Log__c.SObjectType).IsEnabled__c = false; + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntry__c.SObjectType).IsEnabled__c = false; + System.Test.setMock(HttpCalloutMock.class, LoggerMockDataCreator.createHttpCallout().setStatusCode(200).setResponseBody(createStatusApiResponseJson())); LoggerParameter__mdt mockCallStatusApiParameter = new LoggerParameter__mdt(DeveloperName = 'CallStatusApi', Value__c = 'true'); - LoggerParameter.setMockParameter(mockCallStatusApiParameter); + LoggerTestConfigurator.setMock(mockCallStatusApiParameter); System.assertEquals(true, LoggerParameter.CALL_STATUS_API); + LogEntryEvent__e logEntryEvent = createLogEntryEvent(); - LogEntryEvent__e logEntryEvent = new LogEntryEvent__e( - EpochTimestamp__c = System.now().getTime(), - Message__c = 'my message', - Timestamp__c = System.now(), - TransactionEntryNumber__c = 1, - TransactionId__c = '123-456-789-0' - ); - - Database.SaveResult saveResult; - - Test.startTest(); - - saveResult = EventBus.publish(logEntryEvent); - // Normally, you don't have to call Test.getEventBus().deliver() if you're also using Test.stopTest() - // But, in this case, there are 3 transactions happening (original test, async platform event, and async future method) - // So, call Test.getEventBus().deliver() and Test.stopTest() to make sure all transactions are completed before running asserts - Test.getEventBus().deliver(); - - Test.stopTest(); + // TODO Test.startTest() & stopTest() are still being used so that the callout in LogEntryEventHandler executes, + // but it be nice if this was instead mocked via LoggerMockDataStore (? or some other similar class?) + System.Test.startTest(); + Database.SaveResult saveResult = LoggerMockDataStore.getEventBus().publishRecord(logEntryEvent); + LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); + System.Test.stopTest(); System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); - + System.assertEquals( + 1, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed one time for AFTER_INSERT' + ); Log__c log = getLog(); System.assertEquals(1, log.LogEntries__r.size()); LogEntry__c logEntry = log.LogEntries__r.get(0); - System.assertEquals(MOCK_RELEASE_NUMBER, log.ApiReleaseNumber__c); System.assertEquals(MOCK_RELEASE_VERSION, log.ApiReleaseVersion__c); validateLogFields(logEntryEvent, log); @@ -551,44 +461,35 @@ private class LogEntryEventHandler_Tests { @IsTest static void it_should_set_api_release_number_and_api_release_version_from_recent_record() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.Log__c.SObjectType).IsEnabled__c = false; + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntry__c.SObjectType).IsEnabled__c = false; Log__c recentLog = new Log__c(ApiReleaseNumber__c = 'QWERTY', ApiReleaseVersion__c = 'ASDF', TransactionId__c = 'ABC-XYZ'); insert recentLog; - insert new LogEntry__c(Log__c = recentLog.Id, Timestamp__c = System.now().addHours(-1)); - LoggerParameter__mdt mockCallStatusApiParameter = new LoggerParameter__mdt(DeveloperName = 'CallStatusApi', Value__c = 'true'); - LoggerParameter.setMockParameter(mockCallStatusApiParameter); + LoggerTestConfigurator.setMock(mockCallStatusApiParameter); + LogEntryEvent__e logEntryEvent = createLogEntryEvent(); - String transactionId = '123-456-789-0'; - LogEntryEvent__e logEntryEvent = new LogEntryEvent__e( - EpochTimestamp__c = System.now().getTime(), - Message__c = 'my message', - Timestamp__c = System.now(), - TransactionEntryNumber__c = 1, - TransactionId__c = transactionId - ); - - Database.SaveResult saveResult; - - Test.startTest(); - - saveResult = EventBus.publish(logEntryEvent); - // Normally, you don't have to call Test.getEventBus().deliver() if you're also using Test.stopTest() - // But, in this case, there are 3 transactions happening (original test, async platform event, and async future method) - // So, call Test.getEventBus().deliver() and Test.stopTest() to make sure all transactions are completed before running asserts - Test.getEventBus().deliver(); - - Test.stopTest(); + // TODO Test.startTest() & stopTest() are still being used so that the callout in LogEntryEventHandler executes, + // but it be nice if this was instead mocked via LoggerMockDataStore (? or some other similar class?) + System.Test.startTest(); + Database.SaveResult saveResult = LoggerMockDataStore.getEventBus().publishRecord(logEntryEvent); + LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); + System.Test.stopTest(); System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); - + System.assertEquals( + 1, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed one time for AFTER_INSERT' + ); System.assertEquals(0, Limits.getCallouts()); - Log__c log = getLog(); System.assertNotEquals(recentLog.Id, log.Id, log.StartTime__c); System.assertEquals(1, log.LogEntries__r.size()); LogEntry__c logEntry = log.LogEntries__r.get(0); - System.assertEquals(recentLog.ApiReleaseNumber__c, log.ApiReleaseNumber__c); System.assertEquals(recentLog.ApiReleaseVersion__c, log.ApiReleaseVersion__c); validateLogFields(logEntryEvent, log); @@ -597,29 +498,32 @@ private class LogEntryEventHandler_Tests { @IsTest static void it_should_set_not_api_release_number_or_api_release_version_from_callout_when_disabled() { - Test.setMock(HttpCalloutMock.class, new SuccessCalloutMock()); + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.Log__c.SObjectType).IsEnabled__c = false; + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntry__c.SObjectType).IsEnabled__c = false; + Test.setMock(HttpCalloutMock.class, LoggerMockDataCreator.createHttpCallout().setStatusCode(400).setResponseBody(createStatusApiResponseJson())); LoggerParameter__mdt mockCallStatusApiParameter = new LoggerParameter__mdt(DeveloperName = 'CallStatusApi', Value__c = 'false'); - LoggerParameter.setMockParameter(mockCallStatusApiParameter); + LoggerTestConfigurator.setMock(mockCallStatusApiParameter); + LogEntryEvent__e logEntryEvent = createLogEntryEvent(); - String transactionId = '123-456-789-0'; - LogEntryEvent__e logEntryEvent = new LogEntryEvent__e( - EpochTimestamp__c = System.now().getTime(), - Message__c = 'my message', - Timestamp__c = System.now(), - TransactionEntryNumber__c = 1, - TransactionId__c = transactionId - ); - - Test.startTest(); - Database.SaveResult saveResult = EventBus.publish(logEntryEvent); - Test.stopTest(); + // TODO Test.startTest() & stopTest() are still being used so that the callout in LogEntryEventHandler executes, + // but it be nice if this was instead mocked via LoggerMockDataStore (? or some other similar class?) + System.Test.startTest(); + Database.SaveResult saveResult = LoggerMockDataStore.getEventBus().publishRecord(logEntryEvent); + LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); + System.Test.stopTest(); System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); - + System.assertEquals( + 1, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed one time for AFTER_INSERT' + ); + System.assertEquals(0, Limits.getCallouts()); Log__c log = getLog(); System.assertEquals(1, log.LogEntries__r.size()); LogEntry__c logEntry = log.LogEntries__r.get(0); - System.assertEquals(logEntryEvent.TransactionId__c, log.TransactionId__c); System.assertEquals(null, log.ApiReleaseNumber__c); System.assertEquals(null, log.ApiReleaseVersion__c); @@ -629,43 +533,39 @@ private class LogEntryEventHandler_Tests { @IsTest static void it_should_skip_setting_api_release_number_and_api_release_version_when_callout_fails() { - Test.setMock(HttpCalloutMock.class, new FailureCalloutMock()); + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.Log__c.SObjectType).IsEnabled__c = false; + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntry__c.SObjectType).IsEnabled__c = false; + Test.setMock(HttpCalloutMock.class, LoggerMockDataCreator.createHttpCallout().setStatusCode(400).setResponseBody(createStatusApiResponseJson())); LoggerParameter__mdt mockCallStatusApiParameter = new LoggerParameter__mdt(DeveloperName = 'CallStatusApi', Value__c = 'true'); - LoggerParameter.setMockParameter(mockCallStatusApiParameter); - - String transactionId = '123-456-789-0'; - LogEntryEvent__e logEntryEvent = new LogEntryEvent__e( - Message__c = 'my message', - Timestamp__c = System.now(), - TransactionEntryNumber__c = 1, - TransactionId__c = transactionId - ); - + LoggerTestConfigurator.setMock(mockCallStatusApiParameter); + LogEntryEvent__e logEntryEvent = createLogEntryEvent(); Database.SaveResult saveResult; - try { - Test.startTest(); - - saveResult = EventBus.publish(logEntryEvent); - // Normally, you don't have to call Test.getEventBus().deliver() if you're also using Test.stopTest() - // But, in this case, there are 3 transactions happening (original test, async platform event, and async future method) - // So, call Test.getEventBus().deliver() and Test.stopTest() to make sure all transactions are completed before running asserts - Test.getEventBus().deliver(); - Test.stopTest(); + try { + // TODO Test.startTest() & stopTest() are still being used so that the callout in LogEntryEventHandler executes, + // but it be nice if this was instead mocked via LoggerMockDataStore (? or some other similar class?) + System.Test.startTest(); + saveResult = LoggerMockDataStore.getEventBus().publishRecord(logEntryEvent); + LoggerMockDataStore.getEventBus().deliver(new LogEntryEventHandler()); + System.Test.stopTest(); System.assert(false, 'Exception expected, this assert should not run'); } catch (Exception ex) { System.assertEquals(CalloutException.class.getName(), ex.getTypeName()); - String expectedErrorMessage = 'Callout failed for https://api.status.salesforce.com/v1/instances/'; System.assert(ex.getMessage().contains(expectedErrorMessage)); } System.assertEquals(true, saveResult.isSuccess(), saveResult.getErrors()); - + System.assertEquals( + 1, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed one time for AFTER_INSERT' + ); Log__c log = getLog(); System.assertEquals(1, log.LogEntries__r.size()); LogEntry__c logEntry = log.LogEntries__r.get(0); - System.assertEquals(logEntryEvent.TransactionId__c, log.TransactionId__c); System.assertEquals(null, log.ApiReleaseNumber__c); System.assertEquals(null, log.ApiReleaseVersion__c); @@ -673,44 +573,33 @@ private class LogEntryEventHandler_Tests { validateLogEntryFields(logEntryEvent, logEntry); } - private class SuccessCalloutMock implements HttpCalloutMock { - public HttpResponse respond(HttpRequest request) { - LogEntryEventHandler.StatusApiResponse apiResponse = new LogEntryEventHandler.StatusApiResponse(); - apiResponse.releaseNumber = MOCK_RELEASE_NUMBER; - apiResponse.releaseVersion = MOCK_RELEASE_VERSION; - - HttpResponse response = new HttpResponse(); - response.setBody(JSON.serialize(apiResponse)); - response.setHeader('Content-Type', 'application/json'); - response.setStatusCode(200); - - return response; - } - } - - private class FailureCalloutMock implements HttpCalloutMock { - public HttpResponse respond(HttpRequest request) { - HttpResponse response = new HttpResponse(); - response.setStatusCode(400); - return response; - } + private static LogEntryEvent__e createLogEntryEvent() { + // The data builder class handles populating field values, but for some fields, + // certain values are expected (e.g., LoggedById__c should have a valid user ID), + // so this method handles any additional manipulation to the field values + LogEntryEvent__e logEntryEvent = (LogEntryEvent__e) LoggerMockDataCreator.createDataBuilder(Schema.LogEntryEvent__e.SObjectType) + .populateAllFields() + .getRecord(); + logEntryEvent.LoggedById__c = UserInfo.getUserId(); + logEntryEvent.LoggingLevel__c = LoggingLevel.INFO.name(); + logEntryEvent.LoggingLevelOrdinal__c = LoggingLevel.INFO.ordinal(); + logEntryEvent.UserLoggingLevel__c = LoggingLevel.INFO.name(); + logEntryEvent.UserLoggingLevelOrdinal__c = LoggingLevel.INFO.ordinal(); + logEntryEvent.ProfileId__c = UserInfo.getProfileId(); + logEntryEvent.TimestampString__c = String.valueOf(logEntryEvent.Timestamp__c.getTime()); + logEntryEvent.ParentLogTransactionId__c = null; + logEntryEvent.RecordId__c = UserInfo.getUserId(); + logEntryEvent.RecordCollectionSize__c = 1; + logEntryEvent.RecordCollectionType__c = 'Single'; + + return logEntryEvent; } - private static User getCurrentUser() { - return [ - SELECT - Id, - ProfileId, - Profile.Name, - Profile.UserLicenseId, - Profile.UserLicense.LicenseDefinitionKey, - Profile.UserLicense.Name, - Username, - UserRoleId, - UserRole.Name - FROM User - WHERE Id = :UserInfo.getUserId() - ]; + private static String createStatusApiResponseJson() { + LogEntryEventHandler.StatusApiResponse apiResponse = new LogEntryEventHandler.StatusApiResponse(); + apiResponse.releaseNumber = MOCK_RELEASE_NUMBER; + apiResponse.releaseVersion = MOCK_RELEASE_VERSION; + return JSON.serialize(apiResponse); } private static Log__c getLog() { @@ -761,9 +650,24 @@ private class LogEntryEventHandler_Tests { UserType__c, ( SELECT + ComponentType__c, + DatabaseResultCollectionSize__c, + DatabaseResultCollectionType__c, + DatabaseResultJson__c, + DatabaseResultType__c, EpochTimestamp__c, ExceptionStackTrace__c, ExceptionType__c, + HttpRequestBody__c, + HttpRequestBodyMasked__c, + HttpRequestCompressed__c, + HttpRequestEndpoint__c, + HttpRequestMethod__c, + HttpResponseBody__c, + HttpResponseBodyMasked__c, + HttpResponseHeaderKeys__c, + HttpResponseStatus__c, + HttpResponseStatusCode__c, LimitsAggregateQueriesMax__c, LimitsAggregateQueriesUsed__c, LimitsAsyncCallsMax__c, @@ -805,8 +709,11 @@ private class LogEntryEventHandler_Tests { Name, OriginType__c, OriginLocation__c, + RecordCollectionSize__c, + RecordCollectionType__c, RecordId__c, RecordJson__c, + RecordJsonMasked__c, RecordSObjectClassification__c, RecordSObjectType__c, RecordSObjectTypeNamespace__c, @@ -837,104 +744,263 @@ private class LogEntryEventHandler_Tests { Id logOwnerId = logEntryEvent.LoggedById__c == null ? UserInfo.getUserId() : logEntryEvent.LoggedById__c; - System.assertEquals(logEntryEvent.ApiVersion__c, log.ApiVersion__c); - System.assertEquals(logEntryEvent.Locale__c, log.Locale__c); - System.assertEquals(logEntryEvent.LoggedById__c, log.LoggedBy__c); - System.assertEquals(logEntryEvent.LoggedByUsername__c, log.LoggedByUsername__c); - System.assertEquals(logEntryEvent.LoggerVersionNumber__c, log.LoggerVersionNumber__c); - System.assertEquals(logEntryEvent.LoginDomain__c, log.LoginDomain__c); - System.assertEquals(logEntryEvent.LoginHistoryId__c, log.LoginHistoryId__c); - System.assertEquals(logEntryEvent.LoginType__c, log.LoginType__c); - System.assertEquals(logEntryEvent.LogoutUrl__c, log.LogoutUrl__c); - System.assertEquals(logEntryEvent.NetworkId__c, log.NetworkId__c); - System.assertEquals(logOwnerId, log.OwnerId); - System.assertEquals(logEntryEvent.ProfileId__c, log.ProfileId__c); - System.assertEquals(logEntryEvent.ProfileName__c, log.ProfileName__c); - System.assertEquals(logEntryEvent.Scenario__c, log.Scenario__c); - System.assertEquals(logEntryEvent.SessionId__c, log.SessionId__c); - System.assertEquals(logEntryEvent.SessionId__c, log.SessionId__c); - System.assertEquals(logEntryEvent.SessionSecurityLevel__c, log.SessionSecurityLevel__c); - System.assertEquals(logEntryEvent.SessionType__c, log.SessionType__c); - System.assertEquals(logEntryEvent.SourceIp__c, log.SourceIp__c); - System.assertEquals(logEntryEvent.SystemMode__c, log.SystemMode__c); - System.assertEquals(logEntryEvent.ThemeDisplayed__c, log.ThemeDisplayed__c); - System.assertEquals(logEntryEvent.TimeZoneId__c, log.TimeZoneId__c); - System.assertEquals(logEntryEvent.TimeZoneName__c, log.TimeZoneName__c); - System.assertEquals(logEntryEvent.TransactionId__c, log.TransactionId__c); - System.assertEquals(logEntryEvent.UserLoggingLevel__c, log.UserLoggingLevel__c); - System.assertEquals(logEntryEvent.UserLoggingLevelOrdinal__c, log.UserLoggingLevelOrdinal__c); - // System.assertEquals(currentUser.UserRoleId, log.UserRoleId__c); - // System.assertEquals(currentUser.UserRoleId == null ? null : currentUser.UserRole.Name, log.UserRoleName__c); - System.assertEquals(logEntryEvent.UserType__c, log.UserType__c); + System.assertEquals(logEntryEvent.ApiVersion__c, log.ApiVersion__c, 'log.ApiVersion__c was not properly set'); + System.assertEquals(logEntryEvent.Locale__c, log.Locale__c, 'log.Locale__c was not properly set'); + System.assertEquals(logEntryEvent.LoggedById__c, log.LoggedBy__c, 'log.LoggedBy__c was not properly set'); + System.assertEquals(logEntryEvent.LoggedByUsername__c, log.LoggedByUsername__c, 'log.LoggedByUsername__c was not properly set'); + System.assertEquals(logEntryEvent.LoggerVersionNumber__c, log.LoggerVersionNumber__c, 'log.LoggerVersionNumber__c was not properly set'); + System.assertEquals(logEntryEvent.LoginDomain__c, log.LoginDomain__c, 'log.LoginDomain__c was not properly set'); + System.assertEquals(logEntryEvent.LoginHistoryId__c, log.LoginHistoryId__c, 'log.LoginHistoryId__c was not properly set'); + System.assertEquals(logEntryEvent.LoginType__c, log.LoginType__c, 'log.LoginType__c was not properly set'); + System.assertEquals(logEntryEvent.LogoutUrl__c, log.LogoutUrl__c, 'log.LogoutUrl__c was not properly set'); + System.assertEquals(logEntryEvent.NetworkId__c, log.NetworkId__c, 'log.NetworkId__c was not properly set'); + System.assertEquals(logOwnerId, log.OwnerId, 'log.OwnerId was not properly set'); + System.assertEquals(logEntryEvent.ProfileId__c, log.ProfileId__c, 'log.ProfileId__c was not properly set'); + System.assertEquals(logEntryEvent.ProfileName__c, log.ProfileName__c, 'log.ProfileName__c was not properly set'); + System.assertEquals(logEntryEvent.Scenario__c, log.Scenario__c, 'log.Scenario__c was not properly set'); + System.assertEquals(logEntryEvent.SessionId__c, log.SessionId__c, 'log.SessionId__c was not properly set'); + System.assertEquals(logEntryEvent.SessionId__c, log.SessionId__c, 'log.SessionId__c was not properly set'); + System.assertEquals(logEntryEvent.SessionSecurityLevel__c, log.SessionSecurityLevel__c, 'log.SessionSecurityLevel__c was not properly set'); + System.assertEquals(logEntryEvent.SessionType__c, log.SessionType__c, 'log.SessionType__c was not properly set'); + System.assertEquals(logEntryEvent.SourceIp__c, log.SourceIp__c, 'log.SourceIp__c was not properly set'); + System.assertEquals(logEntryEvent.SystemMode__c, log.SystemMode__c, 'log.SystemMode__c was not properly set'); + System.assertEquals(logEntryEvent.ThemeDisplayed__c, log.ThemeDisplayed__c, 'log.ThemeDisplayed__c was not properly set'); + System.assertEquals(logEntryEvent.TimeZoneId__c, log.TimeZoneId__c, 'log.TimeZoneId__c was not properly set'); + System.assertEquals(logEntryEvent.TimeZoneName__c, log.TimeZoneName__c, 'log.TimeZoneName__c was not properly set'); + System.assertEquals(logEntryEvent.TransactionId__c, log.TransactionId__c, 'log.TransactionId__c was not properly set'); + System.assertEquals(logEntryEvent.UserLoggingLevel__c, log.UserLoggingLevel__c, 'log.UserLoggingLevel__c was not properly set'); + System.assertEquals(logEntryEvent.UserLoggingLevelOrdinal__c, log.UserLoggingLevelOrdinal__c, 'log.UserLoggingLevelOrdinal__c was not properly set'); + // System.assertEquals(currentUser.UserRoleId, log.UserRoleId__c, 'log.UserRoleId__c was not properly set'); + // System.assertEquals(currentUser.UserRoleId == null ? null : currentUser.UserRole.Name, log.UserRoleName__c, 'log.UserRoleName__c was not properly set'); + System.assertEquals(logEntryEvent.UserType__c, log.UserType__c, 'log.UserType__c was not properly set'); // Org fields - System.assertEquals(logEntryEvent.OrganizationDomainUrl__c, log.OrganizationDomainUrl__c); - System.assertEquals(logEntryEvent.OrganizationEnvironmentType__c, log.OrganizationEnvironmentType__c); - System.assertEquals(logEntryEvent.OrganizationId__c, log.OrganizationId__c); - System.assertEquals(logEntryEvent.OrganizationInstanceName__c, log.OrganizationInstanceName__c); - System.assertEquals(logEntryEvent.OrganizationName__c, log.OrganizationName__c); - System.assertEquals(logEntryEvent.OrganizationNamespacePrefix__c, log.OrganizationNamespacePrefix__c); - System.assertEquals(logEntryEvent.OrganizationType__c, log.OrganizationType__c); + System.assertEquals(logEntryEvent.OrganizationDomainUrl__c, log.OrganizationDomainUrl__c, 'log.OrganizationDomainUrl__c was not properly set'); + System.assertEquals( + logEntryEvent.OrganizationEnvironmentType__c, + log.OrganizationEnvironmentType__c, + 'log.OrganizationEnvironmentType__c was not properly set' + ); + System.assertEquals(logEntryEvent.OrganizationId__c, log.OrganizationId__c, 'log.OrganizationId__c was not properly set'); + System.assertEquals(logEntryEvent.OrganizationInstanceName__c, log.OrganizationInstanceName__c, 'log.OrganizationInstanceName__c was not properly set'); + System.assertEquals(logEntryEvent.OrganizationName__c, log.OrganizationName__c, 'log.OrganizationName__c was not properly set'); + System.assertEquals( + logEntryEvent.OrganizationNamespacePrefix__c, + log.OrganizationNamespacePrefix__c, + 'log.OrganizationNamespacePrefix__c was not properly set' + ); + System.assertEquals(logEntryEvent.OrganizationType__c, log.OrganizationType__c, 'log.OrganizationType__c was not properly set'); // Profile fields - System.assertEquals(logEntryEvent.UserLicenseDefinitionKey__c, log.UserLicenseDefinitionKey__c); - System.assertEquals(logEntryEvent.UserLicenseId__c, log.UserLicenseId__c); - System.assertEquals(logEntryEvent.UserLicenseName__c, log.UserLicenseName__c); + System.assertEquals(logEntryEvent.UserLicenseDefinitionKey__c, log.UserLicenseDefinitionKey__c, 'log.UserLicenseDefinitionKey__c was not properly set'); + System.assertEquals(logEntryEvent.UserLicenseId__c, log.UserLicenseId__c, 'log.UserLicenseId__c was not properly set'); + System.assertEquals(logEntryEvent.UserLicenseName__c, log.UserLicenseName__c, 'log.UserLicenseName__c was not properly set'); } private static void validateLogEntryFields(LogEntryEvent__e logEntryEvent, LogEntry__c logEntry) { - System.assertEquals(logEntryEvent.EpochTimestamp__c, logEntry.EpochTimestamp__c); - System.assertEquals(logEntryEvent.ExceptionStackTrace__c, logEntry.ExceptionStackTrace__c); - System.assertEquals(logEntryEvent.ExceptionType__c, logEntry.ExceptionType__c); - System.assertEquals(logEntryEvent.LimitsAggregateQueriesMax__c, logEntry.LimitsAggregateQueriesMax__c); - System.assertEquals(logEntryEvent.LimitsAggregateQueriesUsed__c, logEntry.LimitsAggregateQueriesUsed__c); - System.assertEquals(logEntryEvent.LimitsAsyncCallsMax__c, logEntry.LimitsAsyncCallsMax__c); - System.assertEquals(logEntryEvent.LimitsAsyncCallsUsed__c, logEntry.LimitsAsyncCallsUsed__c); - System.assertEquals(logEntryEvent.LimitsCalloutsMax__c, logEntry.LimitsCalloutsMax__c); - System.assertEquals(logEntryEvent.LimitsCalloutsUsed__c, logEntry.LimitsCalloutsUsed__c); - System.assertEquals(logEntryEvent.LimitsCpuTimeMax__c, logEntry.LimitsCpuTimeMax__c); - System.assertEquals(logEntryEvent.LimitsCpuTimeUsed__c, logEntry.LimitsCpuTimeUsed__c); - System.assertEquals(logEntryEvent.LimitsDmlRowsMax__c, logEntry.LimitsDmlRowsMax__c); - System.assertEquals(logEntryEvent.LimitsDmlRowsUsed__c, logEntry.LimitsDmlRowsUsed__c); - System.assertEquals(logEntryEvent.LimitsDmlStatementsMax__c, logEntry.LimitsDmlStatementsMax__c); - System.assertEquals(logEntryEvent.LimitsDmlStatementsUsed__c, logEntry.LimitsDmlStatementsUsed__c); - System.assertEquals(logEntryEvent.LimitsEmailInvocationsMax__c, logEntry.LimitsEmailInvocationsMax__c); - System.assertEquals(logEntryEvent.LimitsEmailInvocationsUsed__c, logEntry.LimitsEmailInvocationsUsed__c); - System.assertEquals(logEntryEvent.LimitsFutureCallsMax__c, logEntry.LimitsFutureCallsMax__c); - System.assertEquals(logEntryEvent.LimitsFutureCallsUsed__c, logEntry.LimitsFutureCallsUsed__c); - System.assertEquals(logEntryEvent.LimitsHeapSizeMax__c, logEntry.LimitsHeapSizeMax__c); - System.assertEquals(logEntryEvent.LimitsHeapSizeUsed__c, logEntry.LimitsHeapSizeUsed__c); - System.assertEquals(logEntryEvent.LimitsMobilePushApexCallsMax__c, logEntry.LimitsMobilePushApexCallsMax__c); - System.assertEquals(logEntryEvent.LimitsMobilePushApexCallsUsed__c, logEntry.LimitsMobilePushApexCallsUsed__c); - System.assertEquals(logEntryEvent.LimitsPublishImmediateDmlStatementsMax__c, logEntry.LimitsPublishImmediateDmlStatementsMax__c); - System.assertEquals(logEntryEvent.LimitsPublishImmediateDmlStatementsUsed__c, logEntry.LimitsPublishImmediateDmlStatementsUsed__c); - System.assertEquals(logEntryEvent.LimitsQueueableJobsMax__c, logEntry.LimitsQueueableJobsMax__c); - System.assertEquals(logEntryEvent.LimitsQueueableJobsUsed__c, logEntry.LimitsQueueableJobsUsed__c); - System.assertEquals(logEntryEvent.LimitsSoqlQueriesMax__c, logEntry.LimitsSoqlQueriesMax__c); - System.assertEquals(logEntryEvent.LimitsSoqlQueriesUsed__c, logEntry.LimitsSoqlQueriesUsed__c); - System.assertEquals(logEntryEvent.LimitsSoqlQueryLocatorRowsMax__c, logEntry.LimitsSoqlQueryLocatorRowsMax__c); - System.assertEquals(logEntryEvent.LimitsSoqlQueryLocatorRowsUsed__c, logEntry.LimitsSoqlQueryLocatorRowsUsed__c); - System.assertEquals(logEntryEvent.LimitsSoqlQueryRowsMax__c, logEntry.LimitsSoqlQueryRowsMax__c); - System.assertEquals(logEntryEvent.LimitsSoqlQueryRowsUsed__c, logEntry.LimitsSoqlQueryRowsUsed__c); - System.assertEquals(logEntryEvent.LimitsSoslSearchesUsed__c, logEntry.LimitsSoslSearchesUsed__c); - System.assertEquals(logEntryEvent.LimitsSoslSearchesMax__c, logEntry.LimitsSoslSearchesMax__c); - System.assertEquals(logEntryEvent.LoggingLevel__c, logEntry.LoggingLevel__c); - System.assertEquals(logEntryEvent.LoggingLevelOrdinal__c, logEntry.LoggingLevelOrdinal__c); - System.assertEquals(logEntryEvent.Message__c, logEntry.Message__c); - System.assertEquals(logEntryEvent.MessageTruncated__c, logEntry.MessageTruncated__c); - System.assertEquals(logEntry.Id, logEntry.Name); - System.assertEquals(logEntryEvent.OriginType__c, logEntry.OriginType__c); - System.assertEquals(logEntryEvent.OriginLocation__c, logEntry.OriginLocation__c); - System.assertEquals(logEntryEvent.RecordId__c, logEntry.RecordId__c); - System.assertEquals(logEntryEvent.RecordJson__c, logEntry.RecordJson__c); - System.assertEquals(logEntryEvent.RecordSObjectClassification__c, logEntry.RecordSObjectClassification__c); - System.assertEquals(logEntryEvent.RecordSObjectType__c, logEntry.RecordSObjectType__c); - System.assertEquals(logEntryEvent.RecordSObjectTypeNamespace__c, logEntry.RecordSObjectTypeNamespace__c); - System.assertEquals(logEntryEvent.StackTrace__c, logEntry.StackTrace__c); - System.assertEquals(logEntryEvent.Timestamp__c, logEntry.Timestamp__c); - System.assertEquals(logEntryEvent.TransactionEntryNumber__c, logEntry.TransactionEntryNumber__c); - System.assertEquals(logEntryEvent.TriggerIsExecuting__c, logEntry.TriggerIsExecuting__c); - System.assertEquals(logEntryEvent.TriggerOperationType__c, logEntry.TriggerOperationType__c); - System.assertEquals(logEntryEvent.TriggerSObjectType__c, logEntry.TriggerSObjectType__c); + System.assertEquals(logEntryEvent.ComponentType__c, logEntry.ComponentType__c, 'logEntry.ComponentType__c was not properly set'); + System.assertEquals( + logEntryEvent.DatabaseResultCollectionSize__c, + logEntry.DatabaseResultCollectionSize__c, + 'logEntry.DatabaseResultCollectionSize__c was not properly set' + ); + System.assertEquals( + logEntryEvent.DatabaseResultCollectionType__c, + logEntry.DatabaseResultCollectionType__c, + 'logEntry.DatabaseResultCollectionType__c was not properly set' + ); + System.assertEquals(logEntryEvent.DatabaseResultJson__c, logEntry.DatabaseResultJson__c, 'logEntry.DatabaseResultJson__c was not properly set'); + System.assertEquals(logEntryEvent.DatabaseResultType__c, logEntry.DatabaseResultType__c, 'logEntry.DatabaseResultType__c was not properly set'); + System.assertEquals(logEntryEvent.EpochTimestamp__c, logEntry.EpochTimestamp__c, 'logEntry.EpochTimestamp__c was not properly set'); + System.assertEquals(logEntryEvent.ExceptionStackTrace__c, logEntry.ExceptionStackTrace__c, 'logEntry.ExceptionStackTrace__c was not properly set'); + System.assertEquals(logEntryEvent.ExceptionType__c, logEntry.ExceptionType__c, 'logEntry.ExceptionType__c was not properly set'); + System.assertEquals(logEntryEvent.HttpRequestBody__c, logEntry.HttpRequestBody__c, 'logEntry.HttpRequestBody__c was not properly set'); + System.assertEquals( + logEntryEvent.HttpRequestBodyMasked__c, + logEntry.HttpRequestBodyMasked__c, + 'logEntry.HttpRequestBodyMasked__c was not properly set' + ); + System.assertEquals( + logEntryEvent.HttpRequestCompressed__c, + logEntry.HttpRequestCompressed__c, + 'logEntry.HttpRequestCompressed__c was not properly set' + ); + System.assertEquals(logEntryEvent.HttpRequestEndpoint__c, logEntry.HttpRequestEndpoint__c, 'logEntry.HttpRequestEndpoint__c was not properly set'); + System.assertEquals(logEntryEvent.HttpRequestMethod__c, logEntry.HttpRequestMethod__c, 'logEntry.HttpRequestMethod__c was not properly set'); + System.assertEquals(logEntryEvent.HttpResponseBody__c, logEntry.HttpResponseBody__c, 'logEntry.HttpResponseBody__c was not properly set'); + System.assertEquals( + logEntryEvent.HttpResponseBodyMasked__c, + logEntry.HttpResponseBodyMasked__c, + 'logEntry.HttpResponseBodyMasked__c was not properly set' + ); + System.assertEquals( + logEntryEvent.HttpResponseHeaderKeys__c, + logEntry.HttpResponseHeaderKeys__c, + 'logEntry.HttpResponseHeaderKeys__c was not properly set' + ); + System.assertEquals(logEntryEvent.HttpResponseStatus__c, logEntry.HttpResponseStatus__c, 'logEntry.HttpResponseStatus__c was not properly set'); + System.assertEquals( + logEntryEvent.HttpResponseStatusCode__c, + logEntry.HttpResponseStatusCode__c, + 'logEntry.HttpResponseStatusCode__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsAggregateQueriesMax__c, + logEntry.LimitsAggregateQueriesMax__c, + 'logEntry.LimitsAggregateQueriesMax__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsAggregateQueriesUsed__c, + logEntry.LimitsAggregateQueriesUsed__c, + 'logEntry.LimitsAggregateQueriesUsed__c was not properly set' + ); + System.assertEquals(logEntryEvent.LimitsAsyncCallsMax__c, logEntry.LimitsAsyncCallsMax__c, 'logEntry.LimitsAsyncCallsMax__c was not properly set'); + System.assertEquals(logEntryEvent.LimitsAsyncCallsUsed__c, logEntry.LimitsAsyncCallsUsed__c, 'logEntry.LimitsAsyncCallsUsed__c was not properly set'); + System.assertEquals(logEntryEvent.LimitsCalloutsMax__c, logEntry.LimitsCalloutsMax__c, 'logEntry.LimitsCalloutsMax__c was not properly set'); + System.assertEquals(logEntryEvent.LimitsCalloutsUsed__c, logEntry.LimitsCalloutsUsed__c, 'logEntry.LimitsCalloutsUsed__c was not properly set'); + System.assertEquals(logEntryEvent.LimitsCpuTimeMax__c, logEntry.LimitsCpuTimeMax__c, 'logEntry.LimitsCpuTimeMax__c was not properly set'); + System.assertEquals(logEntryEvent.LimitsCpuTimeUsed__c, logEntry.LimitsCpuTimeUsed__c, 'logEntry.LimitsCpuTimeUsed__c was not properly set'); + System.assertEquals(logEntryEvent.LimitsDmlRowsMax__c, logEntry.LimitsDmlRowsMax__c, 'logEntry.LimitsDmlRowsMax__c was not properly set'); + System.assertEquals(logEntryEvent.LimitsDmlRowsUsed__c, logEntry.LimitsDmlRowsUsed__c, 'logEntry.LimitsDmlRowsUsed__c was not properly set'); + System.assertEquals( + logEntryEvent.LimitsDmlStatementsMax__c, + logEntry.LimitsDmlStatementsMax__c, + 'logEntry.LimitsDmlStatementsMax__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsDmlStatementsUsed__c, + logEntry.LimitsDmlStatementsUsed__c, + 'logEntry.LimitsDmlStatementsUsed__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsEmailInvocationsMax__c, + logEntry.LimitsEmailInvocationsMax__c, + 'logEntry.LimitsEmailInvocationsMax__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsEmailInvocationsUsed__c, + logEntry.LimitsEmailInvocationsUsed__c, + 'logEntry.LimitsEmailInvocationsUsed__c was not properly set' + ); + System.assertEquals(logEntryEvent.LimitsFutureCallsMax__c, logEntry.LimitsFutureCallsMax__c, 'logEntry.LimitsFutureCallsMax__c was not properly set'); + System.assertEquals( + logEntryEvent.LimitsFutureCallsUsed__c, + logEntry.LimitsFutureCallsUsed__c, + 'logEntry.LimitsFutureCallsUsed__c was not properly set' + ); + System.assertEquals(logEntryEvent.LimitsHeapSizeMax__c, logEntry.LimitsHeapSizeMax__c, 'logEntry.LimitsHeapSizeMax__c was not properly set'); + System.assertEquals(logEntryEvent.LimitsHeapSizeUsed__c, logEntry.LimitsHeapSizeUsed__c, 'logEntry.LimitsHeapSizeUsed__c was not properly set'); + System.assertEquals( + logEntryEvent.LimitsMobilePushApexCallsMax__c, + logEntry.LimitsMobilePushApexCallsMax__c, + 'logEntry.LimitsMobilePushApexCallsMax__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsMobilePushApexCallsUsed__c, + logEntry.LimitsMobilePushApexCallsUsed__c, + 'logEntry.LimitsMobilePushApexCallsUsed__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsPublishImmediateDmlStatementsMax__c, + logEntry.LimitsPublishImmediateDmlStatementsMax__c, + 'logEntry.LimitsPublishImmediateDmlStatementsMax__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsPublishImmediateDmlStatementsUsed__c, + logEntry.LimitsPublishImmediateDmlStatementsUsed__c, + 'logEntry.LimitsPublishImmediateDmlStatementsUsed__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsQueueableJobsMax__c, + logEntry.LimitsQueueableJobsMax__c, + 'logEntry.LimitsQueueableJobsMax__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsQueueableJobsUsed__c, + logEntry.LimitsQueueableJobsUsed__c, + 'logEntry.LimitsQueueableJobsUsed__c was not properly set' + ); + System.assertEquals(logEntryEvent.LimitsSoqlQueriesMax__c, logEntry.LimitsSoqlQueriesMax__c, 'logEntry.LimitsSoqlQueriesMax__c was not properly set'); + System.assertEquals( + logEntryEvent.LimitsSoqlQueriesUsed__c, + logEntry.LimitsSoqlQueriesUsed__c, + 'logEntry.LimitsSoqlQueriesUsed__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsSoqlQueryLocatorRowsMax__c, + logEntry.LimitsSoqlQueryLocatorRowsMax__c, + 'logEntry.LimitsSoqlQueryLocatorRowsMax__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsSoqlQueryLocatorRowsUsed__c, + logEntry.LimitsSoqlQueryLocatorRowsUsed__c, + 'logEntry.LimitsSoqlQueryLocatorRowsUsed__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsSoqlQueryRowsMax__c, + logEntry.LimitsSoqlQueryRowsMax__c, + 'logEntry.LimitsSoqlQueryRowsMax__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsSoqlQueryRowsUsed__c, + logEntry.LimitsSoqlQueryRowsUsed__c, + 'logEntry.LimitsSoqlQueryRowsUsed__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsSoslSearchesUsed__c, + logEntry.LimitsSoslSearchesUsed__c, + 'logEntry.LimitsSoslSearchesUsed__c was not properly set' + ); + System.assertEquals( + logEntryEvent.LimitsSoslSearchesMax__c, + logEntry.LimitsSoslSearchesMax__c, + 'logEntry.LimitsSoslSearchesMax__c was not properly set' + ); + System.assertEquals(logEntryEvent.LoggingLevel__c, logEntry.LoggingLevel__c, 'logEntry.LoggingLevel__c was not properly set'); + System.assertEquals(logEntryEvent.LoggingLevelOrdinal__c, logEntry.LoggingLevelOrdinal__c, 'logEntry.LoggingLevelOrdinal__c was not properly set'); + System.assertEquals(logEntryEvent.Message__c, logEntry.Message__c, 'logEntry.Message__c was not properly set'); + System.assertEquals(logEntryEvent.MessageTruncated__c, logEntry.MessageTruncated__c, 'logEntry.MessageTruncated__c was not properly set'); + System.assertEquals(logEntry.Id, logEntry.Name, 'logEntry.Name was not properly set'); + System.assertEquals(logEntryEvent.OriginType__c, logEntry.OriginType__c, 'logEntry.OriginType__c was not properly set'); + System.assertEquals(logEntryEvent.OriginLocation__c, logEntry.OriginLocation__c, 'logEntry.OriginLocation__c was not properly set'); + System.assertEquals(logEntryEvent.RecordCollectionSize__c, logEntry.RecordCollectionSize__c, 'logEntry.RecordCollectionSize__c was not properly set'); + System.assertEquals(logEntryEvent.RecordCollectionType__c, logEntry.RecordCollectionType__c, 'logEntry.RecordCollectionType__c was not properly set'); + System.assertEquals(logEntryEvent.RecordId__c, logEntry.RecordId__c, 'logEntry.RecordId__c was not properly set'); + System.assertEquals(logEntryEvent.RecordJson__c, logEntry.RecordJson__c, 'logEntry.RecordJson__c was not properly set'); + System.assertEquals(logEntryEvent.RecordJsonMasked__c, logEntry.RecordJsonMasked__c, 'logEntry.RecordJsonMasked__c was not properly set'); + System.assertEquals( + logEntryEvent.RecordSObjectClassification__c, + logEntry.RecordSObjectClassification__c, + 'logEntry.RecordSObjectClassification__c was not properly set' + ); + System.assertEquals(logEntryEvent.RecordSObjectType__c, logEntry.RecordSObjectType__c, 'logEntry.RecordSObjectType__c was not properly set'); + System.assertEquals( + logEntryEvent.RecordSObjectTypeNamespace__c, + logEntry.RecordSObjectTypeNamespace__c, + 'logEntry.RecordSObjectTypeNamespace__c was not properly set' + ); + System.assertEquals(logEntryEvent.RecordId__c, logEntry.RecordId__c, 'logEntry.RecordId__c was not properly set'); + System.assertEquals(logEntryEvent.RecordJson__c, logEntry.RecordJson__c, 'logEntry.RecordJson__c was not properly set'); + System.assertEquals( + logEntryEvent.RecordSObjectClassification__c, + logEntry.RecordSObjectClassification__c, + 'logEntry.RecordSObjectClassification__c was not properly set' + ); + System.assertEquals(logEntryEvent.RecordSObjectType__c, logEntry.RecordSObjectType__c, 'logEntry.RecordSObjectType__c was not properly set'); + System.assertEquals( + logEntryEvent.RecordSObjectTypeNamespace__c, + logEntry.RecordSObjectTypeNamespace__c, + 'logEntry.RecordSObjectTypeNamespace__c was not properly set' + ); + System.assertEquals(logEntryEvent.StackTrace__c, logEntry.StackTrace__c, 'logEntry.StackTrace__c was not properly set'); + System.assertEquals(logEntryEvent.Timestamp__c, logEntry.Timestamp__c, 'logEntry.Timestamp__c was not properly set'); + System.assertEquals( + logEntryEvent.TransactionEntryNumber__c, + logEntry.TransactionEntryNumber__c, + 'logEntry.TransactionEntryNumber__c was not properly set' + ); + System.assertEquals(logEntryEvent.TriggerIsExecuting__c, logEntry.TriggerIsExecuting__c, 'logEntry.TriggerIsExecuting__c was not properly set'); + System.assertEquals(logEntryEvent.TriggerOperationType__c, logEntry.TriggerOperationType__c, 'logEntry.TriggerOperationType__c was not properly set'); + System.assertEquals(logEntryEvent.TriggerSObjectType__c, logEntry.TriggerSObjectType__c, 'logEntry.TriggerSObjectType__c was not properly set'); } } diff --git a/nebula-logger/core/tests/log-management/classes/LogEntryFieldSetPicklist_Tests.cls b/nebula-logger/core/tests/log-management/classes/LogEntryFieldSetPicklist_Tests.cls index de4fefd1f..9fb7bbf8b 100644 --- a/nebula-logger/core/tests/log-management/classes/LogEntryFieldSetPicklist_Tests.cls +++ b/nebula-logger/core/tests/log-management/classes/LogEntryFieldSetPicklist_Tests.cls @@ -4,7 +4,7 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class LogEntryFieldSetPicklist_Tests { @IsTest static void it_should_return_null_for_default_value() { diff --git a/nebula-logger/core/tests/log-management/classes/LogEntryHandler_Tests.cls b/nebula-logger/core/tests/log-management/classes/LogEntryHandler_Tests.cls index a73e05666..182082e55 100644 --- a/nebula-logger/core/tests/log-management/classes/LogEntryHandler_Tests.cls +++ b/nebula-logger/core/tests/log-management/classes/LogEntryHandler_Tests.cls @@ -4,57 +4,46 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class LogEntryHandler_Tests { - public class LogEntryPluginTest extends LoggerSObjectHandlerPlugin { - public override void execute( - TriggerOperation triggerOperationType, - List triggerNew, - Map triggerNewMap, - List triggerOld, - Map triggerOldMap - ) { - if (triggerOperationType == TriggerOperation.BEFORE_INSERT) { - for (LogEntry__c logEntry : (List) triggerNew) { - // The specific field changed doesn't really matter - we just want to ensure that whatever - // logic implemented in the instance of LoggerSObjectHandlerPlugin is executed - logEntry.Message__c = 'Some String'; - } - } - } - } - - private static String getNamespacePrefix() { - String className = LogEntryHandler_Tests.class.getName(); - String namespacePrefix = className.contains('.') ? className.substringBefore('.') : ''; - - return namespacePrefix; - } - @TestSetup static void setupData() { - Log__c log = new Log__c(TransactionId__c = '1234'); + LoggerSObjectHandler.shouldExecute(false); + Log__c log = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); insert log; Test.setCreatedDate(log.Id, System.now().addDays(-8)); } @IsTest static void it_should_return_the_logEntry_sobjectType() { - Test.startTest(); System.assertEquals(Schema.LogEntry__c.SObjectType, new LogEntryHandler().getSObjectType()); - Test.stopTest(); } @IsTest - static void it_should_save_log_entry_without_related_record_id() { + static void it_should_not_run_when_disabled_via_configuration() { + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntry__c.SObjectType).IsEnabled__c = false; Log__c log = [SELECT Id FROM Log__c LIMIT 1]; + LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id); + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); + + LoggerDataStore.getDatabase().insertRecord(logEntry); + System.assertEquals(0, LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntry__c.SObjectType).size(), 'Handler class should not have executed'); + } + + @IsTest + static void it_should_save_log_entry_without_related_record_id() { + Log__c log = [SELECT Id FROM Log__c LIMIT 1]; LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, RecordId__c = null); - Test.startTest(); - insert logEntry; - Test.stopTest(); + LoggerDataStore.getDatabase().insertRecord(logEntry); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntry__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); logEntry = [SELECT Id, RecordId__c FROM LogEntry__c WHERE Id = :logEntry.Id]; System.assertEquals(null, logEntry.RecordId__c); } @@ -63,13 +52,15 @@ private class LogEntryHandler_Tests { static void it_should_populate_related_record_fields_on_log_entry_with_related_user_record_id() { Log__c log = [SELECT Id FROM Log__c LIMIT 1]; User currentUser = [SELECT Id, Username FROM User WHERE Id = :UserInfo.getUserId()]; - LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, RecordId__c = currentUser.Id); - Test.startTest(); - insert logEntry; - Test.stopTest(); + LoggerDataStore.getDatabase().insertRecord(logEntry); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntry__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); logEntry = [SELECT Id, RecordId__c, RecordName__c FROM LogEntry__c WHERE Id = :logEntry.Id]; System.assertEquals(currentUser.Id, logEntry.RecordId__c); System.assertEquals(currentUser.Username, logEntry.RecordName__c); @@ -79,13 +70,15 @@ private class LogEntryHandler_Tests { static void it_should_populate_related_record_fields_on_log_entry_with_related_profile_record_id() { Log__c log = [SELECT Id FROM Log__c LIMIT 1]; Profile currentProfile = [SELECT Id, Name, Description FROM Profile WHERE Id = :UserInfo.getProfileId()]; - LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, RecordId__c = currentProfile.Id); - Test.startTest(); - insert logEntry; - Test.stopTest(); + LoggerDataStore.getDatabase().insertRecord(logEntry); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntry__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); logEntry = [SELECT Id, RecordId__c, RecordName__c FROM LogEntry__c WHERE Id = :logEntry.Id]; System.assertEquals(currentProfile.Id, logEntry.RecordId__c); System.assertEquals(currentProfile.Name, logEntry.RecordName__c); @@ -94,14 +87,17 @@ private class LogEntryHandler_Tests { @IsTest static void it_should_set_hasRecordJson_to_true_when_populated() { Log__c log = [SELECT Id FROM Log__c LIMIT 1]; - String recordJson = '{}'; LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, RecordJson__c = recordJson); + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); - Test.startTest(); - insert logEntry; - Test.stopTest(); + LoggerDataStore.getDatabase().insertRecord(logEntry); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntry__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); logEntry = [SELECT Id, HasRecordJson__c, RecordJson__c FROM LogEntry__c WHERE Id = :logEntry.Id]; System.assert(logEntry.HasRecordJson__c); System.assertEquals(recordJson, logEntry.RecordJson__c); @@ -110,20 +106,21 @@ private class LogEntryHandler_Tests { @IsTest static void it_should_set_hasRecordJson_to_true_when_updated() { Log__c log = [SELECT Id FROM Log__c LIMIT 1]; - LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, RecordJson__c = null); - insert logEntry; + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); + LoggerDataStore.getDatabase().insertRecord(logEntry); logEntry = [SELECT Id, RecordJson__c FROM LogEntry__c WHERE Id = :logEntry.Id]; System.assertEquals(null, logEntry.RecordJson__c); - - Test.startTest(); - String recordJson = '{}'; logEntry.RecordJson__c = recordJson; - update logEntry; - Test.stopTest(); + update logEntry; + System.assertEquals( + 4, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntry__c.SObjectType).size(), + 'Handler class should have executed four times - two times for BEFORE_INSERT/AFTER_INSERT' + ' and two more times for BEFORE_UPDATE/AFTER_UPDATE' + ); logEntry = [SELECT Id, HasRecordJson__c, RecordJson__c FROM LogEntry__c WHERE Id = :logEntry.Id]; System.assert(logEntry.HasRecordJson__c); System.assertEquals(recordJson, logEntry.RecordJson__c); @@ -132,13 +129,16 @@ private class LogEntryHandler_Tests { @IsTest static void it_should_set_hasExceptionStackTrace_to_false_when_null() { Log__c log = [SELECT Id FROM Log__c LIMIT 1]; - LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, ExceptionStackTrace__c = null); + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); - Test.startTest(); - insert logEntry; - Test.stopTest(); + LoggerDataStore.getDatabase().insertRecord(logEntry); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntry__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); logEntry = [SELECT Id, HasExceptionStackTrace__c, ExceptionStackTrace__c FROM LogEntry__c WHERE Id = :logEntry.Id]; System.assert(!logEntry.HasExceptionStackTrace__c); System.assertEquals(null, logEntry.ExceptionStackTrace__c); @@ -147,14 +147,17 @@ private class LogEntryHandler_Tests { @IsTest static void it_should_set_hasExceptionStackTrace_to_true_when_populated() { Log__c log = [SELECT Id FROM Log__c LIMIT 1]; - String stackTrace = 'something'; LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, ExceptionStackTrace__c = stackTrace); + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); - Test.startTest(); - insert logEntry; - Test.stopTest(); + LoggerDataStore.getDatabase().insertRecord(logEntry); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntry__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); logEntry = [SELECT Id, HasExceptionStackTrace__c, ExceptionStackTrace__c FROM LogEntry__c WHERE Id = :logEntry.Id]; System.assert(logEntry.HasExceptionStackTrace__c); System.assertEquals(stackTrace, logEntry.ExceptionStackTrace__c); @@ -163,20 +166,21 @@ private class LogEntryHandler_Tests { @IsTest static void it_should_set_hasExceptionStackTrace_to_true_when_updated() { Log__c log = [SELECT Id FROM Log__c LIMIT 1]; - LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, ExceptionStackTrace__c = null); - insert logEntry; + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); + LoggerDataStore.getDatabase().insertRecord(logEntry); logEntry = [SELECT Id, ExceptionStackTrace__c FROM LogEntry__c WHERE Id = :logEntry.Id]; System.assertEquals(null, logEntry.ExceptionStackTrace__c); - Test.startTest(); - String stackTrace = 'something'; logEntry.ExceptionStackTrace__c = stackTrace; update logEntry; - Test.stopTest(); - + System.assertEquals( + 4, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntry__c.SObjectType).size(), + 'Handler class should have executed four times - two times for BEFORE_INSERT/AFTER_INSERT' + ' and two more times for BEFORE_UPDATE/AFTER_UPDATE' + ); logEntry = [SELECT Id, HasExceptionStackTrace__c, ExceptionStackTrace__c FROM LogEntry__c WHERE Id = :logEntry.Id]; System.assert(logEntry.HasExceptionStackTrace__c); System.assertEquals(stackTrace, logEntry.ExceptionStackTrace__c); @@ -185,13 +189,16 @@ private class LogEntryHandler_Tests { @IsTest static void it_should_set_hasStackTrace_to_false_when_null() { Log__c log = [SELECT Id FROM Log__c LIMIT 1]; - LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, StackTrace__c = null); + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); - Test.startTest(); - insert logEntry; - Test.stopTest(); + LoggerDataStore.getDatabase().insertRecord(logEntry); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntry__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); logEntry = [SELECT Id, HasStackTrace__c, StackTrace__c FROM LogEntry__c WHERE Id = :logEntry.Id]; System.assert(!logEntry.HasStackTrace__c); System.assertEquals(null, logEntry.StackTrace__c); @@ -200,14 +207,17 @@ private class LogEntryHandler_Tests { @IsTest static void it_should_set_hasStackTrace_to_true_when_populated() { Log__c log = [SELECT Id FROM Log__c LIMIT 1]; - String stackTrace = 'something'; LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, StackTrace__c = stackTrace); + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); - Test.startTest(); - insert logEntry; - Test.stopTest(); + LoggerDataStore.getDatabase().insertRecord(logEntry); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntry__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); logEntry = [SELECT Id, HasStackTrace__c, StackTrace__c FROM LogEntry__c WHERE Id = :logEntry.Id]; System.assert(logEntry.HasStackTrace__c); System.assertEquals(stackTrace, logEntry.StackTrace__c); @@ -216,20 +226,21 @@ private class LogEntryHandler_Tests { @IsTest static void it_should_set_hasStackTrace_to_true_when_updated() { Log__c log = [SELECT Id FROM Log__c LIMIT 1]; - LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, StackTrace__c = null); - insert logEntry; + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); + LoggerDataStore.getDatabase().insertRecord(logEntry); logEntry = [SELECT Id, StackTrace__c FROM LogEntry__c WHERE Id = :logEntry.Id]; System.assertEquals(null, logEntry.StackTrace__c); - Test.startTest(); - String stackTrace = 'something'; logEntry.StackTrace__c = stackTrace; update logEntry; - Test.stopTest(); - + System.assertEquals( + 4, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntry__c.SObjectType).size(), + 'Handler class should have executed four times - two times for BEFORE_INSERT/AFTER_INSERT' + ' and two more times for BEFORE_UPDATE/AFTER_UPDATE' + ); logEntry = [SELECT Id, HasStackTrace__c, StackTrace__c FROM LogEntry__c WHERE Id = :logEntry.Id]; System.assert(logEntry.HasStackTrace__c); System.assertEquals(stackTrace, logEntry.StackTrace__c); @@ -239,7 +250,15 @@ private class LogEntryHandler_Tests { static void it_should_set_skip_setting_apex_class_details_when_origin_location_is_null() { Log__c log = [SELECT Id FROM Log__c LIMIT 1]; LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, OriginLocation__c = null, OriginType__c = 'Apex'); - insert logEntry; + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); + + LoggerDataStore.getDatabase().insertRecord(logEntry); + + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntry__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); logEntry = [ SELECT Id, @@ -276,10 +295,17 @@ private class LogEntryHandler_Tests { FROM ApexClass WHERE NamespacePrefix = :getNamespacePrefix() AND Name = :exampleTopLevelClassName ]; - Log__c log = [SELECT Id FROM Log__c LIMIT 1]; LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, OriginLocation__c = exampleTopLevelClassMethodName, OriginType__c = 'Apex'); - insert logEntry; + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); + + LoggerDataStore.getDatabase().insertRecord(logEntry); + + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntry__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); logEntry = [ SELECT Id, @@ -315,10 +341,17 @@ private class LogEntryHandler_Tests { FROM ApexClass WHERE NamespacePrefix = :getNamespacePrefix() AND Name = :exampleTopLevelClassName ]; - Log__c log = [SELECT Id FROM Log__c LIMIT 1]; LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, OriginLocation__c = exampleInnerClassMethodName, OriginType__c = 'Apex'); - insert logEntry; + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); + + LoggerDataStore.getDatabase().insertRecord(logEntry); + + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntry__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); logEntry = [ SELECT Id, @@ -343,24 +376,10 @@ private class LogEntryHandler_Tests { System.assertEquals(methodName, logEntry.ApexMethodName__c); } - @IsTest - static void it_should_run_apex_plugin_when_configured() { - String expectedMessage = 'Some String'; - - Log__c log = [SELECT Id FROM Log__c LIMIT 1]; - - Test.startTest(); - - // Use the mock configurations - LoggerPlugin__mdt plugin = new LoggerPlugin__mdt(PluginType__c = 'Apex', PluginApiName__c = LogEntryPluginTest.class.getName()); - LoggerSObjectHandler.setMockPlugin(Schema.LogEntry__c.SObjectType, plugin); - - LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, Message__c = 'qwerty'); - insert logEntry; - - logEntry = [SELECT Id, Message__c FROM LogEntry__c WHERE Id = :logEntry.Id]; - System.assertEquals(expectedMessage, logEntry.Message__c); + private static String getNamespacePrefix() { + String className = LogEntryHandler_Tests.class.getName(); + String namespacePrefix = className.contains('.') ? className.substringBefore('.') : ''; - Test.stopTest(); + return namespacePrefix; } } diff --git a/nebula-logger/core/tests/log-management/classes/LogEntryTagHandler_Tests.cls b/nebula-logger/core/tests/log-management/classes/LogEntryTagHandler_Tests.cls index 5a22f06b6..b9bdc7aea 100644 --- a/nebula-logger/core/tests/log-management/classes/LogEntryTagHandler_Tests.cls +++ b/nebula-logger/core/tests/log-management/classes/LogEntryTagHandler_Tests.cls @@ -4,37 +4,62 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class LogEntryTagHandler_Tests { @TestSetup static void setupData() { - Log__c log = new Log__c(TransactionId__c = '1234'); + LoggerSObjectHandler.shouldExecute(false); + + Log__c log = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); insert log; List logEntries = new List(); for (Integer i = 0; i < 3; i++) { - logEntries.add(new LogEntry__c(Log__c = log.Id, Message__c = 'log entry #' + i)); + LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, TransactionEntryNumber__c = i + 1); + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); + logEntries.add(logEntry); } insert logEntries; - insert new LoggerTag__c(Name = 'Some tag'); + insert LoggerMockDataCreator.createDataBuilder(Schema.LoggerTag__c.SObjectType).populateRequiredFields().getRecord(); } @IsTest - static void it_should_return_the_logEntry_sobjectType() { - Test.startTest(); + static void it_should_return_the_logEntryTag_sobjectType() { System.assertEquals(Schema.LogEntryTag__c.SObjectType, new LogEntryTagHandler().getSObjectType()); - Test.stopTest(); } @IsTest - static void it_should_set_unique_id_on_insert() { + static void it_should_not_run_when_disabled_via_configuration() { + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(false); LogEntry__c logEntry = [SELECT Id FROM LogEntry__c LIMIT 1]; LoggerTag__c tag = [SELECT Id FROM LoggerTag__c LIMIT 1]; + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(true); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LogEntryTag__c.SObjectType).IsEnabled__c = false; + LogEntryTag__c logEntryTag = new LogEntryTag__c(LogEntry__c = logEntry.Id, Tag__c = tag.Id); + + LoggerDataStore.getDatabase().insertRecord(logEntryTag); + + System.assertEquals( + 0, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryTag__c.SObjectType).size(), + 'Handler class should not have executed' + ); + } + @IsTest + static void it_should_set_unique_id_on_insert() { + LogEntry__c logEntry = [SELECT Id FROM LogEntry__c LIMIT 1]; + LoggerTag__c tag = [SELECT Id FROM LoggerTag__c LIMIT 1]; LogEntryTag__c logEntryTag = new LogEntryTag__c(LogEntry__c = logEntry.Id, Tag__c = tag.Id); - insert logEntryTag; + LoggerDataStore.getDatabase().insertRecord(logEntryTag); + + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryTag__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); logEntryTag = [SELECT Id, LogEntry__c, Tag__c, UniqueId__c FROM LogEntryTag__c WHERE Id = :logEntryTag.Id]; System.assertEquals(logEntry.Id + '' + tag.Id, logEntryTag.UniqueId__c); } @@ -43,12 +68,19 @@ private class LogEntryTagHandler_Tests { static void it_should_set_unique_id_on_update() { LogEntry__c logEntry = [SELECT Id FROM LogEntry__c LIMIT 1]; LoggerTag__c tag = [SELECT Id FROM LoggerTag__c LIMIT 1]; - LogEntryTag__c logEntryTag = new LogEntryTag__c(LogEntry__c = logEntry.Id, Tag__c = tag.Id); - insert logEntryTag; + LoggerDataStore.getDatabase().insertRecord(logEntryTag); + logEntryTag = [SELECT Id, LogEntry__c, Tag__c, UniqueId__c FROM LogEntryTag__c WHERE Id = :logEntryTag.Id]; + System.assertEquals(logEntry.Id + '' + tag.Id, logEntryTag.UniqueId__c); logEntryTag.UniqueId__c = 'something else'; + update logEntryTag; + System.assertEquals( + 4, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryTag__c.SObjectType).size(), + 'Handler class should have executed four times - two times for BEFORE_INSERT/AFTER_INSERT' + ' and two more times for BEFORE_UPDATE/AFTER_UPDATE' + ); logEntryTag = [SELECT Id, LogEntry__c, Tag__c, UniqueId__c FROM LogEntryTag__c WHERE Id = :logEntryTag.Id]; System.assertEquals(logEntry.Id + '' + tag.Id, logEntryTag.UniqueId__c); } @@ -57,17 +89,26 @@ private class LogEntryTagHandler_Tests { static void it_should_not_insert_duplicate_tag() { LogEntry__c logEntry = [SELECT Id FROM LogEntry__c LIMIT 1]; LoggerTag__c tag = [SELECT Id FROM LoggerTag__c LIMIT 1]; - LogEntryTag__c logEntryTag = new LogEntryTag__c(LogEntry__c = logEntry.Id, Tag__c = tag.Id); - insert logEntryTag; - + LoggerDataStore.getDatabase().insertRecord(logEntryTag); LogEntryTag__c duplicateLogEntryTag = new LogEntryTag__c(LogEntry__c = logEntry.Id, Tag__c = tag.Id); + Exception thrownException; + try { insert duplicateLogEntryTag; System.assert(false, 'Exception expected on previous line'); } catch (Exception ex) { - String expectedDuplicateError = 'DUPLICATE_VALUE'; - System.assert(ex.getMessage().contains(expectedDuplicateError), ex.getMessage()); + thrownException = ex; } + + System.assertEquals( + 3, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryTag__c.SObjectType).size(), + 'Handler class should have executed three times - once for BEFORE_INSERT and once for AFTER_INSERT for the first record,' + + ' and once for BEFORE_INSERT on the errored duplicate' + ); + System.assertNotEquals(null, thrownException, 'An exception should have been thrown'); + String expectedDuplicateError = 'DUPLICATE_VALUE'; + System.assert(thrownException.getMessage().contains(expectedDuplicateError), thrownException.getMessage()); } } diff --git a/nebula-logger/core/tests/log-management/classes/LogHandler_Tests.cls b/nebula-logger/core/tests/log-management/classes/LogHandler_Tests.cls index 1a8994bc8..99b9a3fce 100644 --- a/nebula-logger/core/tests/log-management/classes/LogHandler_Tests.cls +++ b/nebula-logger/core/tests/log-management/classes/LogHandler_Tests.cls @@ -4,7 +4,7 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=false) private class LogHandler_Tests { private static final String HIGH_PRIORITY = Schema.Log__c.Priority__c.getDescribe().getPicklistValues().get(0).getValue(); private static final String MEDIUM_PRIORITY = Schema.Log__c.Priority__c.getDescribe().getPicklistValues().get(1).getValue(); @@ -13,45 +13,32 @@ private class LogHandler_Tests { private static final String FIRST_STATUS = Schema.Log__c.Status__c.getDescribe().getPicklistValues().get(0).getValue(); private static final String SECOND_STATUS = Schema.Log__c.Status__c.getDescribe().getPicklistValues().get(1).getValue(); - public class LogPluginTest extends LoggerSObjectHandlerPlugin { - public override void execute( - TriggerOperation triggerOperationType, - List triggerNew, - Map triggerNewMap, - List triggerOld, - Map triggerOldMap - ) { - if (triggerOperationType == TriggerOperation.BEFORE_INSERT) { - for (Log__c log : (List) triggerNew) { - // The specific field changed doesn't really matter - we just want to ensure that whatever - // logic implemented in the instance of LoggerSObjectHandlerPlugin is executed - log.ProfileName__c = 'Some String'; - } - } - } + @IsTest + static void it_should_return_the_log_sobjectType() { + System.assertEquals(Schema.Log__c.SObjectType, new LogHandler().getSObjectType()); } - @TestSetup - static void setupData() { - Map logStatusByName = new Map(); - LogStatus__mdt openStatus = new LogStatus__mdt(IsActive__c = true, MasterLabel = FIRST_STATUS, IsClosed__c = false, IsResolved__c = false); - logStatusByName.put(openStatus.MasterLabel, openStatus); - - LogStatus__mdt closedStatus = new LogStatus__mdt(IsActive__c = true, MasterLabel = SECOND_STATUS, IsClosed__c = true, IsResolved__c = true); - logStatusByName.put(closedStatus.MasterLabel, closedStatus); + @IsTest + static void it_should_not_run_when_disabled_via_configuration() { + setupConfigurations(); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(false); + Log__c log = new Log__c( + ClosedBy__c = UserInfo.getUserId(), + ClosedDate__c = System.now(), + IsClosed__c = true, + IsResolved__c = true, + Status__c = FIRST_STATUS, + TransactionId__c = '1234' + ); - LogHandler.LOG_STATUS_NAME_TO_STATUS.putAll(logStatusByName); - } + LoggerDataStore.getDatabase().insertRecord(log); - @IsTest - static void it_should_return_the_log_sobjectType() { - Test.startTest(); - System.assertEquals(Schema.Log__c.SObjectType, new LogHandler().getSObjectType()); - Test.stopTest(); + System.assertEquals(0, LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), 'Handler class should not have executed'); } @IsTest static void it_should_clear_closed_status_fields_when_open() { + setupConfigurations(); Log__c log = new Log__c( ClosedBy__c = UserInfo.getUserId(), ClosedDate__c = System.now(), @@ -61,10 +48,13 @@ private class LogHandler_Tests { TransactionId__c = '1234' ); - Test.startTest(); - insert log; - Test.stopTest(); + LoggerDataStore.getDatabase().insertRecord(log); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); log = [SELECT Id, ClosedBy__c, ClosedDate__c, IsClosed__c, IsResolved__c, Status__c FROM Log__c WHERE Id = :log.Id]; System.assertEquals(null, log.ClosedBy__c); System.assertEquals(null, log.ClosedDate__c); @@ -74,6 +64,7 @@ private class LogHandler_Tests { @IsTest static void it_should_set_closed_status_fields_when_closed() { + setupConfigurations(); Log__c log = new Log__c( ClosedBy__c = null, ClosedDate__c = null, @@ -83,10 +74,13 @@ private class LogHandler_Tests { TransactionId__c = '1234' ); - Test.startTest(); - insert log; - Test.stopTest(); + LoggerDataStore.getDatabase().insertRecord(log); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); log = [SELECT Id, ClosedBy__c, ClosedDate__c, IsClosed__c, IsResolved__c, Status__c FROM Log__c WHERE Id = :log.Id]; System.assertEquals(UserInfo.getUserId(), log.ClosedBy__c); System.assertEquals(System.today(), log.ClosedDate__c.date()); @@ -95,194 +89,276 @@ private class LogHandler_Tests { @IsTest static void it_should_set_owner_when_default_configured_with_user_id() { + setupConfigurations(); User currentUser = new User(Id = UserInfo.getUserId(), ProfileId = UserInfo.getProfileId()); - User expectedLogOwnerUser = LoggerTestUtils.createUser(); + User expectedLogOwnerUser = LoggerMockDataCreator.createUser(); insert expectedLogOwnerUser; LoggerSettings__c currentUserSettings = Logger.getUserSettings(currentUser); currentUserSettings.DefaultLogOwner__c = expectedLogOwnerUser.Id; insert currentUserSettings; - Log__c log = new Log__c(LoggedBy__c = currentUser.Id, OwnerId = currentUser.Id, TransactionId__c = '1234'); - insert log; + LoggerDataStore.getDatabase().insertRecord(log); + + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); log = [SELECT Id, OwnerId FROM Log__c WHERE Id = :log.Id]; System.assertEquals(expectedLogOwnerUser.Id, log.OwnerId, log); } @IsTest static void it_should_set_owner_when_default_configured_with_username() { + setupConfigurations(); User currentUser = new User(Id = UserInfo.getUserId(), ProfileId = UserInfo.getProfileId()); - User expectedLogOwnerUser = LoggerTestUtils.createUser(); + User expectedLogOwnerUser = LoggerMockDataCreator.createUser(); insert expectedLogOwnerUser; LoggerSettings__c currentUserSettings = Logger.getUserSettings(currentUser); currentUserSettings.DefaultLogOwner__c = expectedLogOwnerUser.Username; insert currentUserSettings; - Log__c log = new Log__c(LoggedBy__c = currentUser.Id, OwnerId = currentUser.Id, TransactionId__c = '1234'); - insert log; + LoggerDataStore.getDatabase().insertRecord(log); + + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); log = [SELECT Id, OwnerId FROM Log__c WHERE Id = :log.Id]; System.assertEquals(expectedLogOwnerUser.Id, log.OwnerId, log); } @IsTest static void it_should_set_owner_when_default_configured_with_queue_id() { + setupConfigurations(); User currentUser = new User(Id = UserInfo.getUserId(), ProfileId = UserInfo.getProfileId()); - Group expectedLogOwnerQueue = LoggerTestUtils.insertQueue(Schema.Log__c.SObjectType); + Group expectedLogOwnerQueue = LoggerMockDataCreator.insertQueue('Some_Log_Queue', Schema.Log__c.SObjectType); LoggerSettings__c currentUserSettings = Logger.getUserSettings(currentUser); currentUserSettings.DefaultLogOwner__c = expectedLogOwnerQueue.Id; insert currentUserSettings; - Log__c log = new Log__c(LoggedBy__c = currentUser.Id, OwnerId = currentUser.Id, TransactionId__c = '1234'); - insert log; + LoggerDataStore.getDatabase().insertRecord(log); + + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); log = [SELECT Id, OwnerId FROM Log__c WHERE Id = :log.Id]; System.assertEquals(expectedLogOwnerQueue.Id, log.OwnerId, log); } @IsTest static void it_should_set_owner_when_default_configured_with_queue_developer_name() { + setupConfigurations(); User currentUser = new User(Id = UserInfo.getUserId(), ProfileId = UserInfo.getProfileId()); - Group expectedLogOwnerQueue = LoggerTestUtils.insertQueue(Schema.Log__c.SObjectType); + Group expectedLogOwnerQueue = LoggerMockDataCreator.insertQueue('Some_Log_Queue', Schema.Log__c.SObjectType); LoggerSettings__c currentUserSettings = Logger.getUserSettings(currentUser); currentUserSettings.DefaultLogOwner__c = expectedLogOwnerQueue.DeveloperName; insert currentUserSettings; - Log__c log = new Log__c(LoggedBy__c = currentUser.Id, OwnerId = currentUser.Id, TransactionId__c = '1234'); - insert log; + LoggerDataStore.getDatabase().insertRecord(log); + + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); log = [SELECT Id, OwnerId FROM Log__c WHERE Id = :log.Id]; System.assertEquals(expectedLogOwnerQueue.Id, log.OwnerId, log); } @IsTest static void it_should_use_current_user_as_owner_when_no_default_configured() { + setupConfigurations(); User currentUser = new User(Id = UserInfo.getUserId(), ProfileId = UserInfo.getProfileId()); LoggerSettings__c currentUserSettings = Logger.getUserSettings(currentUser); currentUserSettings.DefaultLogOwner__c = null; insert currentUserSettings; - Log__c log = new Log__c(LoggedBy__c = currentUser.Id, OwnerId = currentUser.Id, TransactionId__c = '1234'); - insert log; + LoggerDataStore.getDatabase().insertRecord(log); + + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); log = [SELECT Id, OwnerId FROM Log__c WHERE Id = :log.Id]; System.assertEquals(UserInfo.getUserId(), log.OwnerId, log); } @IsTest - static void it_should_keep_existing_retention_date_when_populated() { + static void it_should_keep_existing_retention_details_when_populated() { + setupConfigurations(); Integer defaultDaysToRetainLog = 10; - + String defaultLogPurgeAction = 'Some Action'; LoggerSettings__c settings = Logger.getUserSettings(); settings.DefaultNumberOfDaysToRetainLogs__c = defaultDaysToRetainLog; + settings.DefaultLogPurgeAction__c = defaultLogPurgeAction; upsert settings; - - Test.startTest(); - Integer specifiedDaysToRetainLog = 50; Date retentionDate = System.today().addDays(specifiedDaysToRetainLog); - Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), LogRetentionDate__c = retentionDate, TransactionId__c = '1234'); - insert log; + String specifiedLogPurgeAction = 'A Different Action'; + Log__c log = new Log__c( + LoggedBy__c = UserInfo.getUserId(), + LogPurgeAction__c = specifiedLogPurgeAction, + LogRetentionDate__c = retentionDate, + TransactionId__c = '1234' + ); - Test.stopTest(); + LoggerDataStore.getDatabase().insertRecord(log); - log = [SELECT Id, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); + log = [SELECT Id, LogPurgeAction__c, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; System.assertNotEquals(defaultDaysToRetainLog, specifiedDaysToRetainLog); + System.assertNotEquals(defaultLogPurgeAction, specifiedLogPurgeAction); + System.assertEquals(specifiedLogPurgeAction, log.LogPurgeAction__c); System.assertEquals(retentionDate, log.LogRetentionDate__c); } @IsTest - static void it_should_set_retention_date_when_configured_via_logger_settings() { + static void it_should_set_retention_details_when_configured_via_logger_settings() { + setupConfigurations(); Integer daysToRetainLog = 90; Date expectedRetentionDate = System.today().addDays(daysToRetainLog); + String expectedLogPurgeAction = 'Some Action'; Logger.getUserSettings().DefaultNumberOfDaysToRetainLogs__c = daysToRetainLog; + Logger.getUserSettings().DefaultLogPurgeAction__c = expectedLogPurgeAction; upsert Logger.getUserSettings(); + Log__c log = (Log__c) LoggerMockDataCreator.createDataBuilder(new Log__c(LoggedBy__c = UserInfo.getUserId())).populateRequiredFields().getRecord(); - Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), TransactionId__c = '1234'); - insert log; + LoggerDataStore.getDatabase().insertRecord(log); - log = [SELECT Id, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); + log = [SELECT Id, LogPurgeAction__c, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(expectedLogPurgeAction, log.LogPurgeAction__c); System.assertEquals(expectedRetentionDate, log.LogRetentionDate__c); } @IsTest - static void it_should_set_retention_date_when_configured_via_scenario_rules() { + static void it_should_set_retention_details_when_configured_via_scenario_rules() { + setupConfigurations(); Integer defaultDaysToRetainLog = 1; Integer daysToRetainLog = 90; Date expectedRetentionDate = System.today().addDays(daysToRetainLog); Logger.getUserSettings().DefaultNumberOfDaysToRetainLogs__c = defaultDaysToRetainLog; upsert Logger.getUserSettings(); String transactionScenarioName = 'some scenario'; - LogScenarioRule__mdt scenarioRule = new LogScenarioRule__mdt(Scenario__c = transactionScenarioName, NumberOfDaysToRetainLogs__c = daysToRetainLog); - LogHandler.setMockScenarioRule(scenarioRule); + LoggerTestConfigurator.setMock(new LogScenarioRule__mdt(Scenario__c = transactionScenarioName, NumberOfDaysToRetainLogs__c = daysToRetainLog)); + Log__c log = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); + log.Scenario__c = transactionScenarioName; - Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), Scenario__c = transactionScenarioName, TransactionId__c = '1234'); - insert log; + LoggerDataStore.getDatabase().insertRecord(log); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); log = [SELECT Id, Scenario__c, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; System.assertEquals(expectedRetentionDate, log.LogRetentionDate__c); } @IsTest - static void it_should_have_null_retention_date_when_no_retention_configured() { + static void it_should_have_null_retention_details_when_no_retention_configured() { + setupConfigurations(); LoggerSettings__c settings = Logger.getUserSettings(); + insert settings; settings.DefaultNumberOfDaysToRetainLogs__c = null; + settings.DefaultLogPurgeAction__c = null; upsert settings; - - Test.startTest(); - - Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), TransactionId__c = '1234'); - insert log; - - Test.stopTest(); - - log = [SELECT Id, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; + settings = [SELECT Id, DefaultLogPurgeAction__c FROM LoggerSettings__c WHERE Id = :settings.Id]; + System.assertEquals(null, settings.DefaultLogPurgeAction__c); + Log__c log = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); + log.LoggedBy__c = UserInfo.getUserId(); + log.ProfileId__c = UserInfo.getProfileId(); + + LoggerDataStore.getDatabase().insertRecord(log); + + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); + String defaultLogPurgeActionPicklistValue = getDefaultPicklistValue(Schema.Log__c.LogPurgeAction__c); + log = [SELECT Id, LogPurgeAction__c, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(defaultLogPurgeActionPicklistValue, log.LogPurgeAction__c); System.assertEquals(null, log.LogRetentionDate__c); } @IsTest - static void it_should_set_priority_to_high_when_there_are_errors() { - Log__c log = new Log__c(Priority__c = LOW_PRIORITY, TransactionId__c = '1234'); - insert log; + static void it_should_set_priority_to_high_when_there_is_an_error_log_entry() { + setupConfigurations(); + Log__c log = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); + log.Priority__c = LOW_PRIORITY; + LoggerDataStore.getDatabase().insertRecord(log); log = [SELECT Id, Priority__c FROM Log__c WHERE Id = :log.Id]; System.assertEquals(LOW_PRIORITY, log.Priority__c); - Test.startTest(); - insert new LogEntry__c(Log__c = log.Id, LoggingLevel__c = 'ERROR'); - Test.stopTest(); + insert LoggerMockDataCreator.createDataBuilder(new LogEntry__c(Log__c = log.Id, LoggingLevel__c = LoggingLevel.ERROR.name())) + .populateRequiredFields() + .getRecord(); + System.assertEquals( + 4, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed four times - two times for BEFORE_INSERT/AFTER_INSERT' + + ' and two more times for BEFORE_UPDATE/AFTER_UPDATE (triggered indirectly by the insert of a related LogEntry__c record)' + ); log = [SELECT Id, Priority__c FROM Log__c WHERE Id = :log.Id]; System.assertEquals(HIGH_PRIORITY, log.Priority__c); } @IsTest - static void it_should_set_priority_to_medium_when_there_are_warnings() { + static void it_should_set_priority_to_medium_when_there_is_a_warn_log_entry() { + setupConfigurations(); Log__c log = new Log__c(Priority__c = LOW_PRIORITY, TransactionId__c = '1234'); - insert log; + LoggerDataStore.getDatabase().insertRecord(log); log = [SELECT Id, Priority__c FROM Log__c WHERE Id = :log.Id]; System.assertEquals(LOW_PRIORITY, log.Priority__c); - Test.startTest(); insert new LogEntry__c(Log__c = log.Id, LoggingLevel__c = 'WARN'); - Test.stopTest(); + System.assertEquals( + 4, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed four times - two times for BEFORE_INSERT/AFTER_INSERT' + + ' and two more times for BEFORE_UPDATE/AFTER_UPDATE (triggered indirectly by the insert of a related LogEntry__c record)' + ); log = [SELECT Id, Priority__c FROM Log__c WHERE Id = :log.Id]; System.assertEquals(MEDIUM_PRIORITY, log.Priority__c); } @IsTest static void it_should_grant_read_access_to_user_when_access_level_is_read() { + setupConfigurations(); LoggerSettings__c settings = Logger.getUserSettings(); settings.DefaultLogShareAccessLevel__c = 'Read'; upsert settings; - - Test.startTest(); Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), TransactionId__c = '1234'); - insert log; - Test.stopTest(); - List logShares = [SELECT AccessLevel, ParentId, RowCause, UserOrGroupId FROM Log__Share WHERE ParentId = :log.Id AND AccessLevel != 'All']; + LoggerDataStore.getDatabase().insertRecord(log); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); + List logShares = [SELECT AccessLevel, ParentId, RowCause, UserOrGroupId FROM Log__Share WHERE ParentId = :log.Id AND AccessLevel != 'All']; System.assertEquals(1, logShares.size(), logShares); System.assertEquals('Read', logShares.get(0).AccessLevel); System.assertEquals(log.Id, logShares.get(0).ParentId); @@ -292,17 +368,20 @@ private class LogHandler_Tests { @IsTest static void it_should_grant_edit_access_to_user_when_access_level_is_edit() { + setupConfigurations(); LoggerSettings__c settings = Logger.getUserSettings(); settings.DefaultLogShareAccessLevel__c = 'Edit'; upsert settings; - - Test.startTest(); Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), TransactionId__c = '1234'); - insert log; - Test.stopTest(); - List logShares = [SELECT AccessLevel, ParentId, RowCause, UserOrGroupId FROM Log__Share WHERE ParentId = :log.Id AND AccessLevel != 'All']; + LoggerDataStore.getDatabase().insertRecord(log); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); + List logShares = [SELECT AccessLevel, ParentId, RowCause, UserOrGroupId FROM Log__Share WHERE ParentId = :log.Id AND AccessLevel != 'All']; System.assertEquals(1, logShares.size(), logShares); System.assertEquals('Edit', logShares.get(0).AccessLevel); System.assertEquals(log.Id, logShares.get(0).ParentId); @@ -312,52 +391,57 @@ private class LogHandler_Tests { @IsTest static void it_should_not_grant_access_to_user_when_access_level_is_null() { + setupConfigurations(); LoggerSettings__c settings = Logger.getUserSettings(); settings.DefaultLogShareAccessLevel__c = null; upsert settings; - - Test.startTest(); Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), TransactionId__c = '1234'); - insert log; - Test.stopTest(); - List logShares = [SELECT AccessLevel, ParentId, RowCause, UserOrGroupId FROM Log__Share WHERE ParentId = :log.Id AND AccessLevel != 'All']; + LoggerDataStore.getDatabase().insertRecord(log); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); + List logShares = [SELECT AccessLevel, ParentId, RowCause, UserOrGroupId FROM Log__Share WHERE ParentId = :log.Id AND AccessLevel != 'All']; System.assertEquals(0, logShares.size(), logShares); } @IsTest static void it_should_not_grant_access_to_user_when_access_level_is_an_unknown_string() { + setupConfigurations(); LoggerSettings__c settings = Logger.getUserSettings(); settings.DefaultLogShareAccessLevel__c = 'FAKE LEVEL'; upsert settings; - - Test.startTest(); Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), TransactionId__c = '1234'); - insert log; - Test.stopTest(); - List logShares = [SELECT AccessLevel, ParentId, RowCause, UserOrGroupId FROM Log__Share WHERE ParentId = :log.Id AND AccessLevel != 'All']; + LoggerDataStore.getDatabase().insertRecord(log); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.Log__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); + List logShares = [SELECT AccessLevel, ParentId, RowCause, UserOrGroupId FROM Log__Share WHERE ParentId = :log.Id AND AccessLevel != 'All']; System.assertEquals(0, logShares.size(), logShares); } - @IsTest - static void it_should_run_apex_plugin_when_configured() { - String expectedProfileName = 'Some String'; - - Test.startTest(); - - // Use the mock configurations - LoggerPlugin__mdt plugin = new LoggerPlugin__mdt(PluginType__c = 'Apex', PluginApiName__c = LogPluginTest.class.getName()); - LoggerSObjectHandler.setMockPlugin(Schema.Log__c.SObjectType, plugin); - - Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), TransactionId__c = '1234'); - insert log; + private static String getDefaultPicklistValue(Schema.SObjectField field) { + List picklistEntries = field.getDescribe().getPicklistValues(); + for (Schema.PicklistEntry picklistEntry : picklistEntries) { + if (picklistEntry.isDefaultValue()) { + return picklistEntry.getValue(); + } + } + return null; + } - log = [SELECT Id, ProfileName__c FROM Log__c WHERE Id = :log.Id]; - System.assertEquals(expectedProfileName, log.ProfileName__c); + private static void setupConfigurations() { + LogStatus__mdt openStatus = new LogStatus__mdt(IsActive__c = true, MasterLabel = FIRST_STATUS, IsClosed__c = false, IsResolved__c = false); + LoggerTestConfigurator.setMock(openStatus); - Test.stopTest(); + LogStatus__mdt closedStatus = new LogStatus__mdt(IsActive__c = true, MasterLabel = SECOND_STATUS, IsClosed__c = true, IsResolved__c = true); + LoggerTestConfigurator.setMock(closedStatus); } } diff --git a/nebula-logger/core/tests/log-management/classes/LogMassDeleteExtension_Tests.cls b/nebula-logger/core/tests/log-management/classes/LogMassDeleteExtension_Tests.cls index 3a6856854..b0e173215 100644 --- a/nebula-logger/core/tests/log-management/classes/LogMassDeleteExtension_Tests.cls +++ b/nebula-logger/core/tests/log-management/classes/LogMassDeleteExtension_Tests.cls @@ -4,13 +4,16 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=false) private class LogMassDeleteExtension_Tests { @TestSetup static void setupData() { + LoggerSObjectHandler.shouldExecute(false); + List logs = new List(); for (Integer i = 0; i < 10; i++) { Log__c log = new Log__c(TransactionId__c = 'TXN-' + i); + LoggerMockDataCreator.createDataBuilder(log).populateRequiredFields().getRecord(); logs.add(log); } insert logs; @@ -19,12 +22,10 @@ private class LogMassDeleteExtension_Tests { @IsTest static void it_should_return_deletable_logs() { List logs = [SELECT Id, Name FROM Log__c]; - List logIds = new List(); for (Log__c selectedLog : logs) { logIds.add(selectedLog.Id); } - List expectedDeletableLogs = new List(); for (UserRecordAccess recordAccess : [ SELECT RecordId @@ -33,20 +34,14 @@ private class LogMassDeleteExtension_Tests { ]) { expectedDeletableLogs.add(new Log__c(Id = recordAccess.RecordId)); } - ApexPages.StandardSetController controller = new ApexPages.StandardSetController(logs); controller.setSelected(logs); - PageReference pageReference = Page.LogMassDelete; Test.setCurrentPage(pageReference); - Test.startTest(); - LogMassDeleteExtension extension = new LogMassDeleteExtension(controller); List returnedDeletableLogs = extension.getDeletableLogs(); - Test.stopTest(); - System.assertEquals(expectedDeletableLogs.size(), returnedDeletableLogs.size()); } @@ -63,21 +58,14 @@ private class LogMassDeleteExtension_Tests { logsToKeep.add(logs.get(i)); } } - ApexPages.StandardSetController controller = new ApexPages.StandardSetController(logs); controller.setSelected(logsToDelete); - PageReference pageReference = Page.LogMassDelete; Test.setCurrentPage(pageReference); - Test.startTest(); - LogMassDeleteExtension extension = new LogMassDeleteExtension(controller); extension.deleteSelectedLogs(); - Test.stopTest(); - - // Verify that only the selected logs were deleted logsToDelete = [SELECT Id, IsDeleted FROM Log__c WHERE Id IN :logsToDelete ALL ROWS]; for (Log__c log : logsToDelete) { System.assertEquals(true, log.IsDeleted, log); diff --git a/nebula-logger/core/tests/log-management/classes/LoggerBatchableContext_Tests.cls b/nebula-logger/core/tests/log-management/classes/LoggerBatchableContext_Tests.cls new file mode 100644 index 000000000..8465891e6 --- /dev/null +++ b/nebula-logger/core/tests/log-management/classes/LoggerBatchableContext_Tests.cls @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +@SuppressWarnings('PMD.MethodNamingConventions') +@IsTest(IsParallel=true) +private class LoggerBatchableContext_Tests { + @IsTest + static void it_constructs_instance_when_both_parameters_provided() { + Database.BatchableContext mockBatchableContext = LoggerMockDataCreator.createBatchableContext('some_fake_job_id'); + Schema.SObjectType sobjectType = Schema.LogEntryEvent__e.SObjectType; + + LoggerBatchableContext context = new LoggerBatchableContext(mockBatchableContext, sobjectType); + + System.assertEquals(mockBatchableContext, context.batchableContext); + System.assertEquals(sobjectType, context.sobjectType); + System.assertEquals(sobjectType.getDescribe().getName(), context.sobjectTypeName); + } + + @IsTest + static void it_constructs_instance_when_neither_parameters_provided() { + Database.BatchableContext nullBatchableContext = null; + Schema.SObjectType nullSObjectType = null; + + LoggerBatchableContext context = new LoggerBatchableContext(nullBatchableContext, nullSObjectType); + + System.assertEquals(null, context.batchableContext); + System.assertEquals(null, context.sobjectType); + System.assertEquals(null, context.sobjectTypeName); + } +} diff --git a/nebula-logger/plugins/Slack/plugin/slack/classes/SlackLoggerPlugin_Tests.cls-meta.xml b/nebula-logger/core/tests/log-management/classes/LoggerBatchableContext_Tests.cls-meta.xml similarity index 100% rename from nebula-logger/plugins/Slack/plugin/slack/classes/SlackLoggerPlugin_Tests.cls-meta.xml rename to nebula-logger/core/tests/log-management/classes/LoggerBatchableContext_Tests.cls-meta.xml diff --git a/nebula-logger/core/tests/log-management/classes/LoggerEmailSender_Tests.cls b/nebula-logger/core/tests/log-management/classes/LoggerEmailSender_Tests.cls new file mode 100644 index 000000000..8df5ae14b --- /dev/null +++ b/nebula-logger/core/tests/log-management/classes/LoggerEmailSender_Tests.cls @@ -0,0 +1,134 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +@SuppressWarnings('PMD.MethodNamingConventions') +@IsTest(IsParallel=true) +private class LoggerEmailSender_Tests { + @IsTest + static void it_should_filter_apex_error_recipients() { + ApexEmailNotification emailListNotification = new ApexEmailNotification(Email = 'hello@test.com;fake.person@not.real.com.biz', UserId = null); + ApexEmailNotification userNotification = new ApexEmailNotification(Email = null, UserId = UserInfo.getUserId()); + ApexEmailNotification invalidNotification = new ApexEmailNotification(Email = null, UserId = null); + LoggerEmailSender.MOCK_NOTIFICATIONS.addAll(new List{ emailListNotification, userNotification, invalidNotification }); + + List returnedRecipients = LoggerEmailSender.CACHED_APEX_ERROR_RECIPIENTS; + + System.assertEquals(3, returnedRecipients.size(), 'Should have returned 3 recipients: 1 for the user ID, and 2 for the email addresses'); + for (String recipient : returnedRecipients) { + Boolean matchesUserNotification = String.valueOf(userNotification.UserId) == recipient; + Boolean matchesEmailListNotification = new Set(emailListNotification.Email.split(';')).contains(recipient.trim()); + System.assertEquals( + true, + matchesUserNotification || matchesEmailListNotification, + 'Returned recipient ' + + recipient + + ' should match either the user notification or the email list notification\n' + + JSON.serializePretty(LoggerEmailSender.MOCK_NOTIFICATIONS) + ); + } + } + + @IsTest + static void it_should_send_email_notification_for_saveResult_errors_when_enabled() { + LoggerEmailSender.CACHED_APEX_ERROR_RECIPIENTS.add(UserInfo.getUserId()); + System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent yet'); + + // LogEntry__c requires a Log__c parent record, so inserting a LogEntry__c with no fields set will (intentionally) fail + List saveResultsWithErrors = new List{ LoggerMockDataCreator.createDatabaseSaveResult(false) }; + LoggerEmailSender.sendErrorEmail(Schema.LogEntry__c.SObjectType, saveResultsWithErrors); + + System.assertEquals( + true, + LoggerEmailSender.SENT_EMAILS.get(0).getHtmlBody().contains(saveResultsWithErrors.get(0).errors.get(0).getMessage()), + 'Email message should contain SaveResult error message' + ); + if (LoggerEmailSender.IS_EMAIL_DELIVERABILITY_ENABLED == true) { + System.assertEquals(1, Limits.getEmailInvocations(), 'Email should have been sent'); + } else { + System.assertEquals(0, Limits.getEmailInvocations(), 'Deliverability is not currently enabled'); + } + } + + @IsTest + static void it_should_not_send_email_notification_for_saveResult_errors_when_no_recipients_configured() { + LoggerTestConfigurator.setMock(new LoggerParameter__mdt(DeveloperName = 'SendErrorEmailNotifications', Value__c = 'true')); + System.assertEquals(true, LoggerParameter.SEND_ERROR_EMAIL_NOTIFICATIONS); + LoggerEmailSender.CACHED_APEX_ERROR_RECIPIENTS.clear(); + System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent yet'); + + // LogEntry__c requires a Log__c parent record, so inserting a LogEntry__c with no fields set will (intentionally) fail + List saveResultsWithErrors = new List{ LoggerMockDataCreator.createDatabaseSaveResult(false) }; + LoggerEmailSender.sendErrorEmail(Schema.LogEntry__c.SObjectType, saveResultsWithErrors); + + System.assertEquals(true, LoggerEmailSender.SENT_EMAILS.isEmpty(), 'No email messages should have been generated'); + System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent'); + } + + @IsTest + static void it_should_not_send_email_notification_for_saveResult_errors_when_disabled() { + LoggerTestConfigurator.setMock(new LoggerParameter__mdt(DeveloperName = 'SendErrorEmailNotifications', Value__c = 'false')); + System.assertEquals(false, LoggerParameter.SEND_ERROR_EMAIL_NOTIFICATIONS); + LoggerEmailSender.CACHED_APEX_ERROR_RECIPIENTS.add(UserInfo.getUserId()); + System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent yet'); + + // LogEntry__c requires a Log__c parent record, so inserting a LogEntry__c with no fields set will (intentionally) fail + List saveResultsWithErrors = new List{ LoggerMockDataCreator.createDatabaseSaveResult(false) }; + LoggerEmailSender.sendErrorEmail(Schema.LogEntry__c.SObjectType, saveResultsWithErrors); + + System.assertEquals(true, LoggerEmailSender.SENT_EMAILS.isEmpty(), 'No email messages should have been generated'); + System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent'); + } + + @IsTest + static void it_should_send_email_notification_for_upsertResult_errors_when_enabled() { + LoggerEmailSender.CACHED_APEX_ERROR_RECIPIENTS.add(UserInfo.getUserId()); + System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent yet'); + + // LogEntry__c requires a Log__c parent record, so inserting a LogEntry__c with no fields set will (intentionally) fail + List upsertResultsWithErrors = Database.upsert(new List{ new LogEntry__c() }, false); + LoggerEmailSender.sendErrorEmail(Schema.LogEntry__c.SObjectType, upsertResultsWithErrors); + + System.assertEquals( + true, + LoggerEmailSender.SENT_EMAILS.get(0).getHtmlBody().contains(upsertResultsWithErrors.get(0).errors.get(0).getMessage()), + 'Email message should contain UpsertResult error message' + ); + if (LoggerEmailSender.IS_EMAIL_DELIVERABILITY_ENABLED == true) { + System.assertEquals(1, Limits.getEmailInvocations(), 'Email should have been sent'); + } else { + System.assertEquals(0, Limits.getEmailInvocations(), 'Deliverability is not currently enabled'); + } + } + + @IsTest + static void it_should_not_send_email_notification_for_upsertResult_errors_when_no_recipients_configured() { + LoggerTestConfigurator.setMock(new LoggerParameter__mdt(DeveloperName = 'SendErrorEmailNotifications', Value__c = 'true')); + System.assertEquals(true, LoggerParameter.SEND_ERROR_EMAIL_NOTIFICATIONS); + LoggerEmailSender.CACHED_APEX_ERROR_RECIPIENTS.clear(); + System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent yet'); + + // LogEntry__c requires a Log__c parent record, so inserting a LogEntry__c with no fields set will (intentionally) fail + List upsertResultsWithErrors = Database.upsert(new List{ new LogEntry__c() }, false); + LoggerEmailSender.sendErrorEmail(Schema.LogEntry__c.SObjectType, upsertResultsWithErrors); + + System.assertEquals(true, LoggerEmailSender.SENT_EMAILS.isEmpty(), 'No email messages should have been generated'); + System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent'); + } + + @IsTest + static void it_should_not_send_email_notification_for_upsertResult_errors_when_disabled() { + LoggerTestConfigurator.setMock(new LoggerParameter__mdt(DeveloperName = 'SendErrorEmailNotifications', Value__c = 'false')); + System.assertEquals(false, LoggerParameter.SEND_ERROR_EMAIL_NOTIFICATIONS); + LoggerEmailSender.CACHED_APEX_ERROR_RECIPIENTS.add(UserInfo.getUserId()); + System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent yet'); + + // LogEntry__c requires a Log__c parent record, so inserting a LogEntry__c with no fields set will (intentionally) fail + List upsertResultsWithErrors = Database.upsert(new List{ new LogEntry__c() }, false); + LoggerEmailSender.sendErrorEmail(Schema.LogEntry__c.SObjectType, upsertResultsWithErrors); + + System.assertEquals(0, Limits.getEmailInvocations(), 'No emails should have been sent'); + System.assertEquals(true, LoggerEmailSender.SENT_EMAILS.isEmpty(), 'No email messages should have been generated'); + } +} diff --git a/nebula-logger/core/tests/log-management/classes/LoggerEmailSender_Tests.cls-meta.xml b/nebula-logger/core/tests/log-management/classes/LoggerEmailSender_Tests.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/core/tests/log-management/classes/LoggerEmailSender_Tests.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/core/tests/log-management/classes/LoggerSObjectMetadata_Tests.cls b/nebula-logger/core/tests/log-management/classes/LoggerSObjectMetadata_Tests.cls index 50fc37c60..803773c8e 100644 --- a/nebula-logger/core/tests/log-management/classes/LoggerSObjectMetadata_Tests.cls +++ b/nebula-logger/core/tests/log-management/classes/LoggerSObjectMetadata_Tests.cls @@ -3,19 +3,28 @@ // See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // //------------------------------------------------------------------------------------------------// +/** + * @description Test class for LoggerSObjectMetadata, used for dynamically converting SObject describe details + * into `@AuraEnabled` objects that can be used in LWCs + * To demonstrate that the class is standalone/would work with any SObject, these test methods + * all use the `User` SObject + */ @SuppressWarnings('PMD.ApexDoc, PMD.ApexUnitTestClassShouldHaveAsserts, PMD.MethodNamingConventions') -@IsTest +@IsTest(IsParallel=true) private class LoggerSObjectMetadata_Tests { @IsTest - static void it_should_return_schema_for_logEntryEvent() { - LoggerSObjectMetadata.SObjectSchema sobjectSchema = LoggerSObjectMetadata.getLogEntryEventSchema(); - validateSObjectDetails(Schema.LogEntryEvent__e.SObjectType, sobjectSchema); + static void it_should_return_schema_for_specified_sobject_api_name() { + Schema.SObjectType userSObjectType = Schema.User.SObjectType; + String userSObjectApiName = userSObjectType.getDescribe().getName(); + LoggerSObjectMetadata.SObjectSchema sobjectSchema = LoggerSObjectMetadata.getSchemaForName(userSObjectApiName); + validateSObjectDetails(userSObjectType, sobjectSchema); } @IsTest - static void it_should_return_schema_for_loggerSettings() { - LoggerSObjectMetadata.SObjectSchema sobjectSchema = LoggerSObjectMetadata.getLoggerSettingsSchema(); - validateSObjectDetails(Schema.LoggerSettings__c.SObjectType, sobjectSchema); + static void it_should_return_schema_for_specified_sobject_type() { + Schema.SObjectType userSObjectType = Schema.User.SObjectType; + LoggerSObjectMetadata.SObjectSchema sobjectSchema = LoggerSObjectMetadata.getSchema(userSObjectType); + validateSObjectDetails(userSObjectType, sobjectSchema); } private static void validateSObjectDetails(SObjectType sobjectType, LoggerSObjectMetadata.SObjectSchema sobjectSchema) { diff --git a/nebula-logger/core/tests/log-management/classes/LoggerSettingsController_Tests.cls b/nebula-logger/core/tests/log-management/classes/LoggerSettingsController_Tests.cls index 474eb964e..38869a1ae 100644 --- a/nebula-logger/core/tests/log-management/classes/LoggerSettingsController_Tests.cls +++ b/nebula-logger/core/tests/log-management/classes/LoggerSettingsController_Tests.cls @@ -4,7 +4,7 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions') -@IsTest +@IsTest(IsParallel=false) private class LoggerSettingsController_Tests { @IsTest static void it_should_return_loggingLevel_picklist_options() { @@ -22,6 +22,34 @@ private class LoggerSettingsController_Tests { } } + @IsTest + static void it_should_return_logPurgeAction_picklist_options() { + List fakeLogPurgeActions = new List{ 'A_FAKE_PURGE_ACTION', 'ANOTHER_ONE', 'SOME_OTHER_PURGE_ACTION' }; + for (String fakeLogPurgeAction : fakeLogPurgeActions) { + LoggerTestConfigurator.setMock( + new LoggerParameter__mdt( + DeveloperName = LoggerSettingsController.CUSTOM_LOG_PURGE_ACTION_PREFIX + fakeLogPurgeAction, + Value__c = fakeLogPurgeAction + ) + ); + } + + List picklistOptions = LoggerSettingsController.getPicklistOptions().purgeActionOptions; + + Set expectedLogPurgeActions = new Set{ LoggerSettingsController.DELETE_LOG_PURGE_ACTION }; + expectedLogPurgeActions.addAll(fakeLogPurgeActions); + Integer expectedLogPurgeActionsSize = expectedLogPurgeActions.size() + 1; // '--NONE--' is automatically included + System.assertEquals(expectedLogPurgeActionsSize, picklistOptions.size()); + for (LoggerSettingsController.PicklistOption picklistOption : picklistOptions) { + if (String.isBlank(picklistOption.value) == true) { + System.assertEquals('--None--', picklistOption.label); + } else { + System.assertEquals(picklistOption.value, picklistOption.label); + System.assertEquals(true, expectedLogPurgeActions.contains(picklistOption.value)); + } + } + } + @IsTest static void it_should_return_loggerSaveMethod_picklist_options() { Integer expectedLoggerSaveMethodSize = Logger.SaveMethod.values().size() + 1; // '--NONE--' is automatically included @@ -33,7 +61,63 @@ private class LoggerSettingsController_Tests { } else { System.assertEquals(picklistOption.value, picklistOption.label); Logger.SaveMethod matchingLoggerSaveMethod = Logger.SaveMethod.valueOf(picklistOption.value); - System.assertEquals(matchingLoggerSaveMethod.name(), picklistOption.label); + System.assertEquals(matchingLoggerSaveMethod.name(), picklistOption.value); + } + } + } + + @IsTest + static void it_should_append_custom_platformEventStorageLocation_picklist_options_when_configured() { + List fakeStorageLocations = new List{ 'NOT_A_REAL_STORAGE_LOCATION', 'OR_MAYBE_IT_IS_A_REAL_ONE', 'BUT_MAYBE_JUST_A_TEST', 'PROBABLY' }; + for (String fakeStorageLocation : fakeStorageLocations) { + LoggerTestConfigurator.setMock( + new LoggerParameter__mdt( + DeveloperName = LoggerSettingsController.CUSTOM_STORAGE_LOCATION_PREFIX + fakeStorageLocation, + Value__c = fakeStorageLocation + ) + ); + } + + List picklistOptions = LoggerSettingsController.getPicklistOptions().platformEventStorageLocationOptions; + + Set expectedSaveMethods = new Set{ LoggerSettingsController.CUSTOM_OBJECTS_STORAGE_LOCATION }; + expectedSaveMethods.addAll(fakeStorageLocations); + Integer expectedPlatformEventStorageLocationSize = expectedSaveMethods.size() + 1; // '--NONE--' is automatically included + System.assertEquals(expectedPlatformEventStorageLocationSize, picklistOptions.size(), picklistOptions); + for (LoggerSettingsController.PicklistOption picklistOption : picklistOptions) { + if (String.isBlank(picklistOption.value) == true) { + System.assertEquals('--None--', picklistOption.label); + } else { + System.assertEquals(picklistOption.value, picklistOption.label, 'picklistOption==' + picklistOption); + System.assertEquals(true, expectedSaveMethods.contains(picklistOption.value), 'picklistOption==' + picklistOption); + } + } + } + + @IsTest + static void it_should_append_custom_loggerSaveMethod_picklist_options_when_configured() { + List fakeSaveMethods = new List{ 'A_FAKE_SAVE_METHOD', 'ANOTHER_ONE', 'SOME_OTHER_SAVE_METHOD' }; + for (String fakeSaveMethod : fakeSaveMethods) { + LoggerTestConfigurator.setMock( + new LoggerParameter__mdt(DeveloperName = LoggerSettingsController.CUSTOM_SAVE_METHOD_PREFIX + fakeSaveMethod, Value__c = fakeSaveMethod) + ); + } + + List picklistOptions = LoggerSettingsController.getPicklistOptions().saveMethodOptions; + + Set expectedSaveMethods = new Set(); + expectedSaveMethods.addAll(fakeSaveMethods); + for (Logger.SaveMethod saveMethod : Logger.SaveMethod.values()) { + expectedSaveMethods.add(saveMethod.name()); + } + Integer expectedLoggerSaveMethodSize = expectedSaveMethods.size() + 1; // '--NONE--' is automatically included + System.assertEquals(expectedLoggerSaveMethodSize, picklistOptions.size(), picklistOptions); + for (LoggerSettingsController.PicklistOption picklistOption : picklistOptions) { + if (String.isBlank(picklistOption.value) == true) { + System.assertEquals('--None--', picklistOption.label); + } else { + System.assertEquals(picklistOption.value, picklistOption.label, 'picklistOption==' + picklistOption); + System.assertEquals(true, expectedSaveMethods.contains(picklistOption.value), 'picklistOption==' + picklistOption); } } } @@ -169,7 +253,7 @@ private class LoggerSettingsController_Tests { LoggerSettings__c invalidRecord = null; String expectedExceptionMessage; try { - delete invalidRecord; + LoggerDataStore.getDatabase().deleteRecord(invalidRecord); } catch (Exception ex) { expectedExceptionMessage = ex.getMessage(); } @@ -266,6 +350,7 @@ private class LoggerSettingsController_Tests { CreatedDate, DefaultLogShareAccessLevel__c, DefaultNumberOfDaysToRetainLogs__c, + DefaultPlatformEventStorageLocation__c, DefaultSaveMethod__c, Id, IsAnonymousModeEnabled__c, @@ -273,7 +358,6 @@ private class LoggerSettingsController_Tests { IsDataMaskingEnabled__c, IsEnabled__c, IsJavaScriptConsoleLoggingEnabled__c, - IsPlatformEventStorageEnabled__c, IsRecordFieldStrippingEnabled__c, IsSavingEnabled__c, LastModifiedBy.Username, diff --git a/nebula-logger/core/tests/log-management/classes/LoggerTagHandler_Tests.cls b/nebula-logger/core/tests/log-management/classes/LoggerTagHandler_Tests.cls index d38f03144..25566ce47 100644 --- a/nebula-logger/core/tests/log-management/classes/LoggerTagHandler_Tests.cls +++ b/nebula-logger/core/tests/log-management/classes/LoggerTagHandler_Tests.cls @@ -4,29 +4,83 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class LoggerTagHandler_Tests { @IsTest - static void it_should_set_unique_id_when_enabled() { - LoggerTag__c tag = new LoggerTag__c(Name = 'some tag'); - insert tag; + static void it_should_return_the_loggerTag_sobjectType() { + System.assertEquals(Schema.LoggerTag__c.SObjectType, new LoggerTagHandler().getSObjectType()); + } + + @IsTest + static void it_should_not_run_when_disabled_via_configuration() { + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LoggerTestConfigurator.getSObjectHandlerConfiguration(Schema.LoggerTag__c.SObjectType).IsEnabled__c = false; + LoggerTag__c tag = (LoggerTag__c) LoggerMockDataCreator.createDataBuilder(Schema.LoggerTag__c.SObjectType).populateRequiredFields().getRecord(); + + LoggerDataStore.getDatabase().insertRecord(tag); + + System.assertEquals( + 0, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LoggerTag__c.SObjectType).size(), + 'Handler class should not have executed' + ); + } + + @IsTest + static void it_should_set_unique_id_on_insert() { + LoggerTag__c tag = (LoggerTag__c) LoggerMockDataCreator.createDataBuilder(Schema.LoggerTag__c.SObjectType).populateRequiredFields().getRecord(); + tag.Name = 'Some tag name'; + LoggerDataStore.getDatabase().insertRecord(tag); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LoggerTag__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); + tag = [SELECT Id, Name, UniqueId__c FROM LoggerTag__c WHERE Id = :tag.Id]; + System.assertEquals(tag.Name, tag.UniqueId__c); + } + + @IsTest + static void it_should_set_unique_id_on_update() { + LoggerTag__c tag = (LoggerTag__c) LoggerMockDataCreator.createDataBuilder(Schema.LoggerTag__c.SObjectType).populateRequiredFields().getRecord(); + tag.Name = 'Some tag name'; + LoggerDataStore.getDatabase().insertRecord(tag); + + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LoggerTag__c.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); tag = [SELECT Id, Name, UniqueId__c FROM LoggerTag__c WHERE Id = :tag.Id]; System.assertEquals(tag.Name, tag.UniqueId__c); } @IsTest static void it_should_not_insert_duplicate_tag() { - LoggerTag__c tag = new LoggerTag__c(Name = 'some tag'); - insert tag; + LoggerTag__c tag = (LoggerTag__c) LoggerMockDataCreator.createDataBuilder(Schema.LoggerTag__c.SObjectType).populateRequiredFields().getRecord(); + tag.Name = 'Some tag name'; + LoggerDataStore.getDatabase().insertRecord(tag); + LoggerTag__c duplicateTag = (LoggerTag__c) LoggerMockDataCreator.createDataBuilder(new LoggerTag__c(Name = tag.Name)) + .populateRequiredFields() + .getRecord(); + Exception thrownException; - LoggerTag__c duplicateTag = new LoggerTag__c(Name = tag.Name); try { insert duplicateTag; System.assert(false, 'Exception expected on previous line'); } catch (Exception ex) { - String expectedDuplicateError = 'DUPLICATE_VALUE'; - System.assert(ex.getMessage().contains(expectedDuplicateError), ex.getMessage()); + thrownException = ex; } + + System.assertEquals( + 3, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LoggerTag__c.SObjectType).size(), + 'Handler class should have executed three times - once for BEFORE_INSERT and once for AFTER_INSERT for the first record,' + + ' and once for BEFORE_INSERT on the errored duplicate' + ); + System.assertNotEquals(null, thrownException, 'An exception should have been thrown'); + String expectedDuplicateError = 'DUPLICATE_VALUE'; + System.assert(thrownException.getMessage().contains(expectedDuplicateError), thrownException.getMessage()); } } diff --git a/nebula-logger/core/tests/log-management/classes/RelatedLogEntriesController_Tests.cls b/nebula-logger/core/tests/log-management/classes/RelatedLogEntriesController_Tests.cls index ae5eafcc4..9efd31e79 100644 --- a/nebula-logger/core/tests/log-management/classes/RelatedLogEntriesController_Tests.cls +++ b/nebula-logger/core/tests/log-management/classes/RelatedLogEntriesController_Tests.cls @@ -4,7 +4,7 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class RelatedLogEntriesController_Tests { private static final Integer TOTAL_LOG_ENTRIES = 10; private static final Integer TOTAL_RELATED_LOG_ENTRIES = 7; @@ -19,16 +19,18 @@ private class RelatedLogEntriesController_Tests { @TestSetup static void setupData() { - Log__c log = new Log__c(TransactionId__c = '1234'); + LoggerSObjectHandler.shouldExecute(false); + + Log__c log = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); insert log; List logEntries = new List(); for (Integer i = 0; i < TOTAL_LOG_ENTRIES; i++) { LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, Message__c = 'test ' + i); - if (i <= TOTAL_RELATED_LOG_ENTRIES) { logEntry.RecordId__c = UserInfo.getUserId(); } + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); logEntries.add(logEntry); } diff --git a/nebula-logger/core/tests/log-management/testSuites/LoggerLogManagement.testSuite-meta.xml b/nebula-logger/core/tests/log-management/testSuites/LoggerLogManagement.testSuite-meta.xml index 515914a5a..1007c5ecf 100644 --- a/nebula-logger/core/tests/log-management/testSuites/LoggerLogManagement.testSuite-meta.xml +++ b/nebula-logger/core/tests/log-management/testSuites/LoggerLogManagement.testSuite-meta.xml @@ -6,6 +6,8 @@ LogEntryFieldSetPicklist_Tests LogEntryHandler_Tests LogEntryTagHandler_Tests + LoggerBatchableContext_Tests + LoggerEmailSender_Tests LoggerSettingsController_Tests LoggerSObjectMetadata_Tests LoggerTagHandler_Tests diff --git a/nebula-logger/core/tests/log-management/utilities/LoggerTestConfigurator.cls b/nebula-logger/core/tests/log-management/utilities/LoggerTestConfigurator.cls new file mode 100644 index 000000000..6a9dc9cd3 --- /dev/null +++ b/nebula-logger/core/tests/log-management/utilities/LoggerTestConfigurator.cls @@ -0,0 +1,162 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @group Test Utilities + * @description Utility class used to help with setting up Nebula Logger's configurations within a test context. + * These methods are specific to metadata implemented within Nebula Logger. + * These methods can be used when writing Apex tests for plugins. + * @see LoggerMockDataCreator + * @see LoggerMockDataStore + */ +@IsTest +public without sharing class LoggerTestConfigurator { + private static final Map PERMISSION_SETS_BY_NAME = queryPermissionSets(); + + /** + * @description Assigns the permission set `LoggerAdmin` to the specified user ID + * @param userId The ID of the user that should be assigned the permission set + */ + public static void assignAdminPermissionSet(Id userId) { + assignPermissionSet(userId, PERMISSION_SETS_BY_NAME.get('LoggerAdmin')); + } + + /** + * @description Assigns the permission set `LoggerLogViewer` to the specified user ID + * @param userId The ID of the user that should be assigned the permission set + */ + public static void assignLogViewerPermissionSet(Id userId) { + assignPermissionSet(userId, PERMISSION_SETS_BY_NAME.get('LoggerLogViewer')); + } + + /** + * @description Assigns the permission set `LoggerEndUser` to the specified user ID + * @param userId The ID of the user that should be assigned the permission set + */ + public static void assignEndUserPermissionSet(Id userId) { + assignPermissionSet(userId, PERMISSION_SETS_BY_NAME.get('LoggerEndUser')); + } + + /** + * @description Assigns the permission set `LoggerLogCreator` to the specified user ID + * @param userId The ID of the user that should be assigned the permission set + */ + public static void assignLogCreatorPermissionSet(Id userId) { + assignPermissionSet(userId, PERMISSION_SETS_BY_NAME.get('LoggerLogCreator')); + } + + /** + * @description Returns an instance of `LoggerSObjectHandler__mdt` that has been built & configured for the specified `SObjectType` + * @param sobjectType The instance `SObjectType` to check for a configured instance of `LoggerSObjectHandler` + * @return The ``LoggerSObjectHandler__mdt` record that has been configured for the specified `SObjectType` (if any) + */ + public static LoggerSObjectHandler__mdt getSObjectHandlerConfiguration(Schema.SObjectType sobjectType) { + return LoggerSObjectHandler.getHandlerConfiguration(sobjectType); + } + + /** + * @description Loads the mock `LogEntryDataMaskRule__mdt` during test execution + * @param mock The mock instance of `LogEntryDataMaskRule__mdt` to load + */ + public static void setMock(LogEntryDataMaskRule__mdt mock) { + LogEntryEventBuilder.setMockDataMaskRule(mock); + } + + /** + * @description Loads the mock `LogEntryTagRule__mdt` during test execution + * @param mock The mock instance of `LogEntryTagRule__mdt` to load + */ + public static void setMock(LogEntryTagRule__mdt mock) { + LogEntryEventHandler.TAG_ASSIGNMENT_RULES.add(mock); + } + + /** + * @description Loads the mock `LoggerParameter__mdt` during test execution + * @param mock The mock instance of `LoggerParameter__mdt` to load + */ + public static void setMock(LoggerParameter__mdt mock) { + LoggerParameter.setMock(mock); + } + + /** + * @description Loads the mock `LoggerPlugin__mdt` during test execution + * @param mock The mock instance of `LoggerPlugin__mdt` to load + */ + public static void setMock(LoggerPlugin__mdt mock) { + LoggerPlugin.setMock(mock); + } + + /** + * @description Loads the mock `LoggerSObjectHandler__mdt` during test execution + * @param mock The mock instance of `LoggerSObjectHandler__mdt` to load + */ + public static void setMock(LoggerSObjectHandler__mdt mock) { + LoggerSObjectHandler.setMock(mock); + } + + /** + * @description Loads the mock `LogScenarioRule__mdt` during test execution + * @param mock The mock instance of `LogScenarioRule__mdt` to load + */ + public static void setMock(LogScenarioRule__mdt mock) { + Logger.setMockScenarioRule(mock); + LogHandler.setMockScenarioRule(mock); + } + + /** + * @description Loads the mock `LogStatus__mdt` during test execution + * @param mock The mock instance of `LogStatus__mdt` to load + */ + public static void setMock(LogStatus__mdt mock) { + LogHandler.setMockLogStatus(mock); + } + + /** + * @description Creates mock instances of `LoggerSObjectHandler__mdt` for each `SObjectType` used by Nebula Logger, + * with each `LoggerSObjectHandler__mdt` automatically set to `IsEnabled__c == true` + */ + public static void setupMockSObjectHandlerConfigurations() { + setupMockSObjectHandlerConfigurations(true); + } + + /** + * @description Creates mock instances of `LoggerSObjectHandler__mdt` for each `SObjectType` used by Nebula Logger, + * with each `LoggerSObjectHandler__mdt` enabled/disabled based on the provided boolean + * @param isEnabled The Boolean value to control if all mock `LoggerSObjectHandler__mdt` records should be enabled (`true`) or disabled (`false`) + */ + public static void setupMockSObjectHandlerConfigurations(Boolean isEnabled) { + Map sobjectTypeToDefaultHandlerApexClass = new Map{ + Schema.Log__c.SObjectType => LogHandler.class, + Schema.LogEntry__c.SObjectType => LogEntryHandler.class, + Schema.LogEntryEvent__e.SObjectType => LogEntryEventHandler.class, + Schema.LogEntryTag__c.SObjectType => LogEntryTagHandler.class, + Schema.LoggerTag__c.SObjectType => LoggerTagHandler.class + }; + for (Schema.SObjectType sobjectType : sobjectTypeToDefaultHandlerApexClass.keySet()) { + setMock( + new LoggerSObjectHandler__mdt( + IsEnabled__c = isEnabled, + SObjectHandlerApexClass__c = sobjectTypeToDefaultHandlerApexClass.get(sobjectType).getName(), + SObjectType__c = sobjectType.getDescribe().getName() + ) + ); + } + } + + // Helper methods + private static void assignPermissionSet(Id userId, PermissionSet permissionSet) { + PermissionSetAssignment permissionSetAssignment = new PermissionSetAssignment(AssigneeId = userId, PermissionSetId = permissionSet.Id); + insert permissionSetAssignment; + } + + private static Map queryPermissionSets() { + List permissionSetNames = new List{ 'LoggerAdmin', 'LoggerLogViewer', 'LoggerEndUser', 'LoggerLogCreator' }; + Map results = new Map(); + for (PermissionSet permissionSet : [SELECT Id, Name FROM PermissionSet WHERE Name IN :permissionSetNames]) { + results.put(permissionSet.Name, permissionSet); + } + return results; + } +} diff --git a/nebula-logger/core/tests/log-management/utilities/LoggerTestConfigurator.cls-meta.xml b/nebula-logger/core/tests/log-management/utilities/LoggerTestConfigurator.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/core/tests/log-management/utilities/LoggerTestConfigurator.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/core/tests/logger-engine/classes/ComponentLogger_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/ComponentLogger_Tests.cls index 223d7aba5..93a7edd17 100644 --- a/nebula-logger/core/tests/logger-engine/classes/ComponentLogger_Tests.cls +++ b/nebula-logger/core/tests/logger-engine/classes/ComponentLogger_Tests.cls @@ -4,7 +4,7 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class ComponentLogger_Tests { @IsTest static void it_should_return_logger_settings() { @@ -13,28 +13,22 @@ private class ComponentLogger_Tests { loggerSettings.LoggingLevel__c = 'FINEST'; upsert loggerSettings; - Test.startTest(); ComponentLogger.ComponentLoggerSettings componentLoggerSettings = ComponentLogger.getSettings(); - Test.stopTest(); System.assertEquals(loggerSettings.IsEnabled__c, componentLoggerSettings.isEnabled); System.assertEquals(loggerSettings.LoggingLevel__c, componentLoggerSettings.userLoggingLevel.name); - LoggingLevel userLoggingLevel = Logger.getLoggingLevel(loggerSettings.LoggingLevel__c); System.assertEquals(userLoggingLevel.name(), componentLoggerSettings.userLoggingLevel.name); System.assertEquals(userLoggingLevel.ordinal(), componentLoggerSettings.userLoggingLevel.ordinal); - for (LoggingLevel currentLoggingLevel : LoggingLevel.values()) { // We don't care about logging level NONE, or the secret/undocumented INTERNAL logging level if (currentLoggingLevel == LoggingLevel.NONE || currentLoggingLevel == LoggingLevel.INTERNAL) { continue; } - System.assert( componentLoggerSettings.supportedLoggingLevels.containsKey(currentLoggingLevel.name()), 'Cmp settings did not contain level: ' + currentLoggingLevel ); - Integer returnedOrdinal = componentLoggerSettings.supportedLoggingLevels.get(currentLoggingLevel.name()); System.assertEquals(currentLoggingLevel.ordinal(), returnedOrdinal); } @@ -42,24 +36,18 @@ private class ComponentLogger_Tests { @IsTest static void it_should_return_aura_exception_when_it_breaks() { - Test.startTest(); try { ComponentLogger.saveComponentLogEntries(null, null); System.assert(false, 'This assert shouldn\'t run since this is a negative test'); } catch (Exception apexException) { System.assertEquals(AuraHandledException.class.getName(), apexException.getTypeName()); } - Test.stopTest(); } @IsTest static void it_should_save_component_log_entry() { - upsert LoggerSettings__c.getInstance(); - System.assertEquals(0, [SELECT COUNT() FROM Log__c]); - + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); User currentUser = new User(FirstName = UserInfo.getFirstName(), Id = UserInfo.getUserId(), ProfileId = UserInfo.getProfileId()); - - List componentLogEntries = new List(); ComponentLogger.ComponentLogEntry componentLogEntry = new ComponentLogger.ComponentLogEntry(); componentLogEntry.loggingLevel = LoggingLevel.INFO.name(); componentLogEntry.message = 'hello, world'; @@ -67,36 +55,31 @@ private class ComponentLogger_Tests { componentLogEntry.record = currentUser; componentLogEntry.timestamp = System.now().addDays(-1 / 24); componentLogEntry.tags = new List{ 'some tag', 'one more tag' }; - componentLogEntries.add(componentLogEntry); - - Test.startTest(); - ComponentLogger.saveComponentLogEntries(componentLogEntries, null); - Test.stopTest(); - - List logEntries = [ - SELECT Id, LoggingLevel__c, Message__c, RecordId__c, RecordJson__c, RecordSObjectType__c, Timestamp__c - FROM LogEntry__c - ]; - System.assertEquals(1, logEntries.size()); - - LogEntry__c logEntry = logEntries.get(0); - - System.assertEquals(componentLogEntry.loggingLevel, logEntry.LoggingLevel__c); - System.assertEquals(componentLogEntry.message, logEntry.Message__c); - System.assertEquals(componentLogEntry.recordId, logEntry.RecordId__c); - System.assertEquals(JSON.serializePretty(currentUser), logEntry.RecordJson__c); - System.assertEquals(Schema.SObjectType.User.getName(), logEntry.RecordSObjectType__c); - System.assertEquals(componentLogEntry.timestamp, logEntry.Timestamp__c); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + + ComponentLogger.saveComponentLogEntries(new List{ componentLogEntry }, null); + + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals('Component', publishedLogEntryEvent.OriginType__c); + System.assertEquals(componentLogEntry.loggingLevel, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(componentLogEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals(componentLogEntry.recordId, publishedLogEntryEvent.RecordId__c); + System.assertEquals(JSON.serializePretty(currentUser), publishedLogEntryEvent.RecordJson__c); + System.assertEquals(Schema.SObjectType.User.getName(), publishedLogEntryEvent.RecordSObjectType__c); + System.assertEquals(componentLogEntry.timestamp, publishedLogEntryEvent.Timestamp__c); } @IsTest static void it_should_save_component_log_entry_with_queueable_job() { - upsert LoggerSettings__c.getInstance(); - System.assertEquals(0, [SELECT COUNT() FROM Log__c]); - + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerDataStore.setMock(LoggerMockDataStore.getJobQueue()); User currentUser = new User(FirstName = UserInfo.getFirstName(), Id = UserInfo.getUserId(), ProfileId = UserInfo.getProfileId()); - - List componentLogEntries = new List(); + System.assertEquals(0, Limits.getQueueableJobs(), 'Test should start with 0 queueable jobs used'); ComponentLogger.ComponentLogEntry componentLogEntry = new ComponentLogger.ComponentLogEntry(); componentLogEntry.loggingLevel = LoggingLevel.INFO.name(); componentLogEntry.message = 'hello, world'; @@ -104,45 +87,39 @@ private class ComponentLogger_Tests { componentLogEntry.record = currentUser; componentLogEntry.timestamp = System.now().addDays(-1 / 24); componentLogEntry.tags = new List{ 'some tag', 'one more tag' }; - componentLogEntries.add(componentLogEntry); - Test.startTest(); - System.assertEquals(0, Limits.getQueueableJobs(), 'Test should start with 0 queueable jobs used'); - - ComponentLogger.saveComponentLogEntries(componentLogEntries, Logger.SaveMethod.QUEUEABLE.name()); - - System.assertEquals(1, Limits.getQueueableJobs(), 'Log entries should have been saved using the QUEUEABLE save method'); - Test.stopTest(); - - List logEntries = [ - SELECT Id, LoggingLevel__c, Message__c, RecordId__c, RecordJson__c, RecordSObjectType__c, Timestamp__c - FROM LogEntry__c - ]; - System.assertEquals(1, logEntries.size()); - - LogEntry__c logEntry = logEntries.get(0); - - System.assertEquals(componentLogEntry.loggingLevel, logEntry.LoggingLevel__c); - System.assertEquals(componentLogEntry.message, logEntry.Message__c); - System.assertEquals(componentLogEntry.recordId, logEntry.RecordId__c); - System.assertEquals(JSON.serializePretty(currentUser), logEntry.RecordJson__c); - System.assertEquals(Schema.SObjectType.User.getName(), logEntry.RecordSObjectType__c); - System.assertEquals(componentLogEntry.timestamp, logEntry.Timestamp__c); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + System.assertEquals(0, LoggerMockDataStore.getJobQueue().getEnqueuedJobs().size()); + + ComponentLogger.saveComponentLogEntries(new List{ componentLogEntry }, Logger.SaveMethod.QUEUEABLE.name()); + System.assertEquals(1, LoggerMockDataStore.getJobQueue().getEnqueuedJobs().size()); + LoggerMockDataStore.getJobQueue().executeJobs(); + + System.assertEquals(Logger.SaveMethod.QUEUEABLE.name(), Logger.lastSaveMethodNameUsed); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals('Component', publishedLogEntryEvent.OriginType__c); + System.assertEquals(componentLogEntry.loggingLevel, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(componentLogEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals(componentLogEntry.recordId, publishedLogEntryEvent.RecordId__c); + System.assertEquals(JSON.serializePretty(currentUser), publishedLogEntryEvent.RecordJson__c); + System.assertEquals(Schema.SObjectType.User.getName(), publishedLogEntryEvent.RecordSObjectType__c); + System.assertEquals(componentLogEntry.timestamp, publishedLogEntryEvent.Timestamp__c); } @IsTest static void it_should_save_component_log_entry_with_javascript_error() { - upsert LoggerSettings__c.getInstance(); - System.assertEquals(0, [SELECT COUNT() FROM Log__c]); - + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); User currentUser = new User(FirstName = UserInfo.getFirstName(), Id = UserInfo.getUserId(), ProfileId = UserInfo.getProfileId()); - - List componentLogEntries = new List(); ComponentLogger.ComponentError mockComponentError = new ComponentLogger.ComponentError(); mockComponentError.message = 'some javascript error message'; mockComponentError.stack = 'some \nstack \ntrace \nstring'; mockComponentError.type = 'ReferenceError'; - ComponentLogger.ComponentLogEntry componentLogEntry = new ComponentLogger.ComponentLogEntry(); componentLogEntry.error = mockComponentError; componentLogEntry.loggingLevel = LoggingLevel.INFO.name(); @@ -151,137 +128,112 @@ private class ComponentLogger_Tests { componentLogEntry.record = currentUser; componentLogEntry.timestamp = System.now().addDays(-1 / 24); componentLogEntry.tags = new List{ 'some tag', 'one more tag' }; - componentLogEntries.add(componentLogEntry); - - Test.startTest(); - ComponentLogger.saveComponentLogEntries(componentLogEntries, null); - Test.stopTest(); - - List logEntries = [ - SELECT Id, LoggingLevel__c, Message__c, ExceptionMessage__c, ExceptionStackTrace__c, ExceptionType__c, Timestamp__c - FROM LogEntry__c - ]; - System.assertEquals(1, logEntries.size()); - - LogEntry__c logEntry = logEntries.get(0); - - System.assertEquals(componentLogEntry.loggingLevel, logEntry.LoggingLevel__c); - System.assertEquals(componentLogEntry.message, logEntry.Message__c); - System.assertEquals(componentLogEntry.timestamp, logEntry.Timestamp__c); - System.assertEquals(componentLogEntry.error.message, logEntry.ExceptionMessage__c); - System.assertEquals(componentLogEntry.error.stack, logEntry.ExceptionStackTrace__c); - System.assertEquals(ComponentLogger.EXCEPTION_TYPE_PREFIX + componentLogEntry.error.type, logEntry.ExceptionType__c); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + + ComponentLogger.saveComponentLogEntries(new List{ componentLogEntry }, null); + + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals('Component', publishedLogEntryEvent.OriginType__c); + System.assertEquals(componentLogEntry.loggingLevel, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(componentLogEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals(componentLogEntry.timestamp, publishedLogEntryEvent.Timestamp__c); + System.assertEquals(componentLogEntry.error.message, publishedLogEntryEvent.ExceptionMessage__c); + System.assertEquals(componentLogEntry.error.stack, publishedLogEntryEvent.ExceptionStackTrace__c); + System.assertEquals(ComponentLogger.EXCEPTION_TYPE_PREFIX + componentLogEntry.error.type, publishedLogEntryEvent.ExceptionType__c); } @IsTest static void it_should_set_log_scenario() { - System.assertEquals(0, [SELECT COUNT() FROM Log__c]); + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); Logger.getUserSettings().LoggingLevel__c = LoggingLevel.FINEST.name(); - - List componentLogEntries = new List(); ComponentLogger.ComponentLogEntry componentLogEntry = new ComponentLogger.ComponentLogEntry(); componentLogEntry.loggingLevel = LoggingLevel.INFO.name(); componentLogEntry.message = 'hello, world'; componentLogEntry.scenario = 'Some scenario'; componentLogEntry.timestamp = System.now(); - componentLogEntries.add(componentLogEntry); - - Test.startTest(); - ComponentLogger.saveComponentLogEntries(componentLogEntries, null); - Test.stopTest(); - - Log__c log = [SELECT Id, Scenario__c FROM Log__c]; - System.assertEquals(componentLogEntry.scenario, log.Scenario__c); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + + ComponentLogger.saveComponentLogEntries(new List{ componentLogEntry }, null); + + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals('Component', publishedLogEntryEvent.OriginType__c); + System.assertEquals(componentLogEntry.scenario, publishedLogEntryEvent.Scenario__c); } @IsTest static void it_should_parse_aura_component_stack_trace() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); String expectedComponentType = 'Aura'; String expectedComponentApiName = 'c/loggerAuraDemo'; String expectedComponentFunctionName = 'saveLogAuraExample'; - - List componentLogEntries = new List(); ComponentLogger.ComponentLogEntry componentLogEntry = new ComponentLogger.ComponentLogEntry(); componentLogEntry.loggingLevel = LoggingLevel.INFO.name(); componentLogEntry.message = 'hello, world'; componentLogEntry.stack = getMockAuraComponentStackTrace(); componentLogEntry.timestamp = System.now().addDays(-1 / 24); - componentLogEntries.add(componentLogEntry); - - Test.startTest(); - ComponentLogger.saveComponentLogEntries(componentLogEntries, null); - Test.stopTest(); - - List logEntries = [ - SELECT - Id, - LoggingLevel__c, - Message__c, - ComponentApiName__c, - ComponentFunctionName__c, - ComponentType__c, - OriginLocation__c, - OriginType__c, - Timestamp__c - FROM LogEntry__c - ]; - System.assertEquals(1, logEntries.size()); - - LogEntry__c logEntry = logEntries.get(0); - - System.assertEquals(componentLogEntry.loggingLevel, logEntry.LoggingLevel__c, logEntry); - System.assertEquals(componentLogEntry.message, logEntry.Message__c, logEntry); - System.assertEquals('Component', logEntry.OriginType__c, logEntry); - System.assertEquals(expectedComponentApiName + '.' + expectedComponentFunctionName, logEntry.OriginLocation__c, logEntry); - System.assertEquals(expectedComponentApiName, logEntry.ComponentApiName__c, logEntry); - System.assertEquals(expectedComponentFunctionName, logEntry.ComponentFunctionName__c, logEntry); - System.assertEquals(expectedComponentType, logEntry.ComponentType__c, logEntry); - System.assertEquals(componentLogEntry.timestamp, logEntry.Timestamp__c, logEntry); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + + ComponentLogger.saveComponentLogEntries(new List{ componentLogEntry }, null); + + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals('Component', publishedLogEntryEvent.OriginType__c); + System.assertEquals(componentLogEntry.loggingLevel, publishedLogEntryEvent.LoggingLevel__c, publishedLogEntryEvent); + System.assertEquals(componentLogEntry.message, publishedLogEntryEvent.Message__c, publishedLogEntryEvent); + System.assertEquals('Component', publishedLogEntryEvent.OriginType__c, publishedLogEntryEvent); + System.assertEquals(expectedComponentApiName + '.' + expectedComponentFunctionName, publishedLogEntryEvent.OriginLocation__c, publishedLogEntryEvent); + // TODO Move these asserts to LogEntryHandler_Tests + // System.assertEquals(expectedComponentApiName, publishedLogEntryEvent.ComponentApiName__c, publishedLogEntryEvent); + // System.assertEquals(expectedComponentFunctionName, publishedLogEntryEvent.ComponentFunctionName__c, publishedLogEntryEvent); + System.assertEquals(expectedComponentType, publishedLogEntryEvent.ComponentType__c, publishedLogEntryEvent); + System.assertEquals(componentLogEntry.timestamp, publishedLogEntryEvent.Timestamp__c, publishedLogEntryEvent); } @IsTest static void it_should_parse_web_component_stack_trace() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); String expectedComponentType = 'LWC'; String expectedComponentApiName = 'c/loggerLWCDemo'; String expectedComponentFunctionName = 'saveLogWebExample'; - - List componentLogEntries = new List(); ComponentLogger.ComponentLogEntry componentLogEntry = new ComponentLogger.ComponentLogEntry(); componentLogEntry.loggingLevel = LoggingLevel.INFO.name(); componentLogEntry.message = 'hello, world'; componentLogEntry.stack = getMockWebComponentStackTrace(); componentLogEntry.timestamp = System.now().addDays(-1 / 24); - componentLogEntries.add(componentLogEntry); - - Test.startTest(); - ComponentLogger.saveComponentLogEntries(componentLogEntries, null); - Test.stopTest(); - - List logEntries = [ - SELECT - Id, - LoggingLevel__c, - Message__c, - ComponentApiName__c, - ComponentFunctionName__c, - ComponentType__c, - OriginLocation__c, - OriginType__c, - Timestamp__c - FROM LogEntry__c - ]; - System.assertEquals(1, logEntries.size()); - - LogEntry__c logEntry = logEntries.get(0); - - System.assertEquals(componentLogEntry.loggingLevel, logEntry.LoggingLevel__c, logEntry); - System.assertEquals(componentLogEntry.message, logEntry.Message__c, logEntry); - System.assertEquals('Component', logEntry.OriginType__c, logEntry); - System.assertEquals(expectedComponentApiName + '.' + expectedComponentFunctionName, logEntry.OriginLocation__c, logEntry); - System.assertEquals(expectedComponentApiName, logEntry.ComponentApiName__c, logEntry); - System.assertEquals(expectedComponentFunctionName, logEntry.ComponentFunctionName__c, logEntry); - System.assertEquals(expectedComponentType, logEntry.ComponentType__c, logEntry); - System.assertEquals(componentLogEntry.timestamp, logEntry.Timestamp__c, logEntry); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + + ComponentLogger.saveComponentLogEntries(new List{ componentLogEntry }, null); + + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals('Component', publishedLogEntryEvent.OriginType__c); + System.assertEquals(componentLogEntry.loggingLevel, publishedLogEntryEvent.LoggingLevel__c, publishedLogEntryEvent); + System.assertEquals(componentLogEntry.message, publishedLogEntryEvent.Message__c, publishedLogEntryEvent); + System.assertEquals('Component', publishedLogEntryEvent.OriginType__c, publishedLogEntryEvent); + System.assertEquals(expectedComponentApiName + '.' + expectedComponentFunctionName, publishedLogEntryEvent.OriginLocation__c, publishedLogEntryEvent); + // TODO Move these asserts to LogEntryHandler_Tests + // System.assertEquals(expectedComponentApiName, publishedLogEntryEvent.ComponentApiName__c, publishedLogEntryEvent); + // System.assertEquals(expectedComponentFunctionName, publishedLogEntryEvent.ComponentFunctionName__c, publishedLogEntryEvent); + System.assertEquals(expectedComponentType, publishedLogEntryEvent.ComponentType__c, publishedLogEntryEvent); + System.assertEquals(componentLogEntry.timestamp, publishedLogEntryEvent.Timestamp__c, publishedLogEntryEvent); } private static String getMockAuraComponentStackTrace() { diff --git a/nebula-logger/core/tests/logger-engine/classes/FlowCollectionLogEntry_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/FlowCollectionLogEntry_Tests.cls index f2b4edcf7..a7906acc7 100644 --- a/nebula-logger/core/tests/logger-engine/classes/FlowCollectionLogEntry_Tests.cls +++ b/nebula-logger/core/tests/logger-engine/classes/FlowCollectionLogEntry_Tests.cls @@ -4,7 +4,7 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class FlowCollectionLogEntry_Tests { static FlowCollectionLogEntry createFlowCollectionLogEntry() { FlowCollectionLogEntry flowCollectionEntry = new FlowCollectionLogEntry(); @@ -17,311 +17,276 @@ private class FlowCollectionLogEntry_Tests { @IsTest static void it_should_save_entry_when_logging_level_met() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); User currentUser = new User( Id = UserInfo.getUserId(), FirstName = UserInfo.getFirstName(), LastName = UserInfo.getLastName(), Username = UserInfo.getUserName() ); - LoggingLevel userLoggingLevel = LoggingLevel.FINEST; LoggingLevel flowCollectionEntryLoggingLevel = LoggingLevel.DEBUG; System.assert(userLoggingLevel.ordinal() < flowCollectionEntryLoggingLevel.ordinal()); - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowCollectionLogEntry flowCollectionEntry = createFlowCollectionLogEntry(); flowCollectionEntry.loggingLevelName = flowCollectionEntryLoggingLevel.name(); flowCollectionEntry.records = new List{ currentUser }; - FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowCollectionEntry }); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowCollectionEntry }); System.assertEquals(1, Logger.getBufferSize()); - Logger.saveLog(); - Test.getEventBus().deliver(); - - Test.stopTest(); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); String expectedUserJson = JSON.serializePretty(new List{ currentUser }); - - LogEntry__c logEntry = [ - SELECT Id, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c, RecordId__c, RecordCollectionType__c, RecordJson__c, RecordSObjectType__c - FROM LogEntry__c - ORDER BY CreatedDate - LIMIT 1 - ]; - System.assertEquals(flowCollectionEntry.loggingLevelName, logEntry.LoggingLevel__c); - System.assertEquals(flowCollectionEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); - System.assertEquals(null, logEntry.RecordId__c); - System.assertEquals('List', logEntry.RecordCollectionType__c); - System.assertEquals('User', logEntry.RecordSObjectType__c); - System.assertEquals(expectedUserJson, logEntry.RecordJson__c); + System.assertEquals(flowCollectionEntry.loggingLevelName, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowCollectionEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); + System.assertEquals(null, publishedLogEntryEvent.RecordId__c); + System.assertEquals('List', publishedLogEntryEvent.RecordCollectionType__c); + System.assertEquals('User', publishedLogEntryEvent.RecordSObjectType__c); + System.assertEquals(expectedUserJson, publishedLogEntryEvent.RecordJson__c); } @IsTest static void it_should_auto_save_entry_when_saveLog_is_true() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); User currentUser = new User( Id = UserInfo.getUserId(), FirstName = UserInfo.getFirstName(), LastName = UserInfo.getLastName(), Username = UserInfo.getUserName() ); - LoggingLevel userLoggingLevel = LoggingLevel.FINEST; LoggingLevel flowCollectionEntryLoggingLevel = LoggingLevel.DEBUG; System.assert(userLoggingLevel.ordinal() < flowCollectionEntryLoggingLevel.ordinal()); - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowCollectionLogEntry flowCollectionEntry = createFlowCollectionLogEntry(); flowCollectionEntry.loggingLevelName = flowCollectionEntryLoggingLevel.name(); flowCollectionEntry.records = new List{ currentUser }; flowCollectionEntry.saveLog = true; - FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowCollectionEntry }); - Test.getEventBus().deliver(); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); - Test.stopTest(); + FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowCollectionEntry }); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); String expectedUserJson = JSON.serializePretty(new List{ currentUser }); - - LogEntry__c logEntry = [ - SELECT Id, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c, RecordId__c, RecordCollectionType__c, RecordJson__c, RecordSObjectType__c - FROM LogEntry__c - ORDER BY CreatedDate - LIMIT 1 - ]; - System.assertEquals(flowCollectionEntry.loggingLevelName, logEntry.LoggingLevel__c); - System.assertEquals(flowCollectionEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); - System.assertEquals(null, logEntry.RecordId__c); - System.assertEquals('List', logEntry.RecordCollectionType__c); - System.assertEquals('User', logEntry.RecordSObjectType__c); - System.assertEquals(expectedUserJson, logEntry.RecordJson__c); + System.assertEquals(flowCollectionEntry.loggingLevelName, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowCollectionEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); + System.assertEquals(null, publishedLogEntryEvent.RecordId__c); + System.assertEquals('List', publishedLogEntryEvent.RecordCollectionType__c); + System.assertEquals('User', publishedLogEntryEvent.RecordSObjectType__c); + System.assertEquals(expectedUserJson, publishedLogEntryEvent.RecordJson__c); } @IsTest static void it_should_auto_save_entry_with_save_method_when_saveMethodName_specified() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerDataStore.setMock(LoggerMockDataStore.getJobQueue()); User currentUser = new User( Id = UserInfo.getUserId(), FirstName = UserInfo.getFirstName(), LastName = UserInfo.getLastName(), Username = UserInfo.getUserName() ); - LoggingLevel userLoggingLevel = LoggingLevel.FINEST; LoggingLevel flowCollectionEntryLoggingLevel = LoggingLevel.DEBUG; System.assert(userLoggingLevel.ordinal() < flowCollectionEntryLoggingLevel.ordinal()); - Test.startTest(); System.assertEquals(0, Limits.getQueueableJobs(), 'Test should start with 0 queueable jobs used'); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowCollectionLogEntry flowCollectionEntry = createFlowCollectionLogEntry(); flowCollectionEntry.loggingLevelName = flowCollectionEntryLoggingLevel.name(); flowCollectionEntry.records = new List{ currentUser }; flowCollectionEntry.saveLog = true; flowCollectionEntry.saveMethodName = Logger.SaveMethod.QUEUEABLE.name(); - FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowCollectionEntry }); - Test.getEventBus().deliver(); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + System.assertEquals(0, LoggerMockDataStore.getJobQueue().getEnqueuedJobs().size()); - System.assertEquals(1, Limits.getQueueableJobs(), 'Log entries should have been saved using the QUEUEABLE save method'); - Test.stopTest(); + FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowCollectionEntry }); + System.assertEquals(1, LoggerMockDataStore.getJobQueue().getEnqueuedJobs().size()); + LoggerMockDataStore.getJobQueue().executeJobs(); + System.assertEquals(Logger.SaveMethod.QUEUEABLE.name(), Logger.lastSaveMethodNameUsed); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); String expectedUserJson = JSON.serializePretty(new List{ currentUser }); - - LogEntry__c logEntry = [ - SELECT Id, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c, RecordId__c, RecordCollectionType__c, RecordJson__c, RecordSObjectType__c - FROM LogEntry__c - ORDER BY CreatedDate - LIMIT 1 - ]; - System.assertEquals(flowCollectionEntry.loggingLevelName, logEntry.LoggingLevel__c); - System.assertEquals(flowCollectionEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); - System.assertEquals(null, logEntry.RecordId__c); - System.assertEquals('List', logEntry.RecordCollectionType__c); - System.assertEquals('User', logEntry.RecordSObjectType__c); - System.assertEquals(expectedUserJson, logEntry.RecordJson__c); + System.assertEquals(flowCollectionEntry.loggingLevelName, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowCollectionEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); + System.assertEquals(null, publishedLogEntryEvent.RecordId__c); + System.assertEquals('List', publishedLogEntryEvent.RecordCollectionType__c); + System.assertEquals('User', publishedLogEntryEvent.RecordSObjectType__c); + System.assertEquals(expectedUserJson, publishedLogEntryEvent.RecordJson__c); } @IsTest static void it_should_not_save_entry_when_logging_level_not_met() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); User currentUser = new User( Id = UserInfo.getUserId(), FirstName = UserInfo.getFirstName(), LastName = UserInfo.getLastName(), Username = UserInfo.getUserName() ); - LoggingLevel userLoggingLevel = LoggingLevel.ERROR; LoggingLevel flowCollectionEntryLoggingLevel = LoggingLevel.DEBUG; System.assert(userLoggingLevel.ordinal() > flowCollectionEntryLoggingLevel.ordinal()); - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowCollectionLogEntry flowCollectionEntry = createFlowCollectionLogEntry(); flowCollectionEntry.loggingLevelName = flowCollectionEntryLoggingLevel.name(); flowCollectionEntry.records = new List{ currentUser }; - FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowCollectionEntry }); - Test.getEventBus().deliver(); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowCollectionEntry }); System.assertEquals(0, Logger.getBufferSize()); + Logger.saveLog(); - Test.stopTest(); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); } @IsTest static void it_should_use_debug_as_default_level_when_faultMessage_is_null() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel expectedEntryLoggingLevel = LoggingLevel.DEBUG; - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = expectedEntryLoggingLevel.name(); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + FlowCollectionLogEntry flowCollectionEntry = createFlowCollectionLogEntry(); + System.assertEquals(null, flowCollectionEntry.faultMessage); + System.assertEquals(null, flowCollectionEntry.loggingLevelName); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); - FlowCollectionLogEntry flowEntry = createFlowCollectionLogEntry(); - System.assertEquals(null, flowEntry.faultMessage); - System.assertEquals(null, flowEntry.loggingLevelName); - - FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowEntry }); - + FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowCollectionEntry }); System.assertEquals(1, Logger.getBufferSize()); - Logger.saveLog(); - Test.getEventBus().deliver(); - - Test.stopTest(); - LogEntry__c logEntry = [ - SELECT - Id, - ExceptionMessage__c, - ExceptionType__c, - LoggingLevel__c, - Message__c, - OriginType__c, - OriginLocation__c, - RecordId__c, - RecordCollectionType__c, - RecordJson__c - FROM LogEntry__c - ORDER BY CreatedDate - LIMIT 1 - ]; - System.assertEquals(null, logEntry.ExceptionMessage__c); - System.assertEquals(null, logEntry.ExceptionType__c); - System.assertEquals(expectedEntryLoggingLevel.name(), logEntry.LoggingLevel__c); - System.assertEquals(flowEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(null, publishedLogEntryEvent.ExceptionMessage__c); + System.assertEquals(null, publishedLogEntryEvent.ExceptionType__c); + System.assertEquals(expectedEntryLoggingLevel.name(), publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowCollectionEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); } @IsTest static void it_should_use_error_as_default_level_when_faultMessage_is_not_null() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel expectedEntryLoggingLevel = LoggingLevel.ERROR; - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = LoggingLevel.FINEST.name(); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + FlowCollectionLogEntry flowCollectionEntry = createFlowCollectionLogEntry(); + flowCollectionEntry.faultMessage = 'Whoops, a Flow error has occurred.'; + System.assertEquals(null, flowCollectionEntry.loggingLevelName); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); - FlowCollectionLogEntry flowEntry = createFlowCollectionLogEntry(); - flowEntry.faultMessage = 'Whoops, a Flow error has occurred.'; - System.assertEquals(null, flowEntry.loggingLevelName); - - FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowEntry }); - + FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowCollectionEntry }); System.assertEquals(1, Logger.getBufferSize()); - Logger.saveLog(); - Test.getEventBus().deliver(); - - Test.stopTest(); - LogEntry__c logEntry = [ - SELECT - Id, - ExceptionMessage__c, - ExceptionType__c, - LoggingLevel__c, - Message__c, - OriginType__c, - OriginLocation__c, - RecordId__c, - RecordCollectionType__c, - RecordJson__c - FROM LogEntry__c - ORDER BY CreatedDate - LIMIT 1 - ]; - System.assertEquals(flowEntry.faultMessage, logEntry.ExceptionMessage__c); - System.assertEquals('Flow.FaultError', logEntry.ExceptionType__c); - System.assertEquals(expectedEntryLoggingLevel.name(), logEntry.LoggingLevel__c); - System.assertEquals(flowEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(flowCollectionEntry.faultMessage, publishedLogEntryEvent.ExceptionMessage__c); + System.assertEquals('Flow.FaultError', publishedLogEntryEvent.ExceptionType__c); + System.assertEquals(expectedEntryLoggingLevel.name(), publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowCollectionEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); } @IsTest static void it_should_set_log_scenario() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel userLoggingLevel = LoggingLevel.FINEST; - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - FlowCollectionLogEntry flowEntry = createFlowCollectionLogEntry(); - flowEntry.loggingLevelName = userLoggingLevel.name(); - flowEntry.scenario = 'Some scenario'; - FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowEntry }); - System.assertEquals(1, Logger.getBufferSize()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + FlowCollectionLogEntry flowCollectionEntry = createFlowCollectionLogEntry(); + flowCollectionEntry.loggingLevelName = userLoggingLevel.name(); + flowCollectionEntry.scenario = 'Some scenario'; + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowCollectionEntry }); + System.assertEquals(1, Logger.getBufferSize()); Logger.saveLog(); - Test.getEventBus().deliver(); - String transactionId = Logger.getTransactionId(); - - Test.stopTest(); - Log__c log = [SELECT Id, Scenario__c FROM Log__c WHERE TransactionId__c = :transactionId]; - System.assertEquals(flowEntry.scenario, log.Scenario__c); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(flowCollectionEntry.scenario, publishedLogEntryEvent.Scenario__c); } @IsTest static void it_should_add_tags_to_log_entry() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel userLoggingLevel = LoggingLevel.FINEST; LoggingLevel flowCollectionEntryLoggingLevel = LoggingLevel.DEBUG; System.assert(userLoggingLevel.ordinal() < flowCollectionEntryLoggingLevel.ordinal()); - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); List tags = new List{ 'first tag', 'SECOND TAG' }; FlowCollectionLogEntry flowCollectionEntry = createFlowCollectionLogEntry(); flowCollectionEntry.loggingLevelName = flowCollectionEntryLoggingLevel.name(); flowCollectionEntry.tagsString = String.join(tags, ', '); - FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowCollectionEntry }); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + FlowCollectionLogEntry.addFlowCollectionEntries(new List{ flowCollectionEntry }); System.assertEquals(1, Logger.getBufferSize()); - Logger.saveLog(); - Test.getEventBus().deliver(); - - Test.stopTest(); - LogEntry__c logEntry = [SELECT Id, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c FROM LogEntry__c ORDER BY CreatedDate LIMIT 1]; - System.assertEquals(flowCollectionEntry.loggingLevelName, logEntry.LoggingLevel__c); - System.assertEquals(flowCollectionEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); - - List logEntryTags = [SELECT Id, LogEntry__c, Tag__c, Tag__r.Name FROM LogEntryTag__c WHERE LogEntry__c = :logEntry.Id]; - System.assertEquals(tags.size(), logEntryTags.size(), logEntryTags); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(flowCollectionEntry.loggingLevelName, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowCollectionEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); + List publishedLogEntryEventTags = publishedLogEntryEvent.Tags__c.split('\n'); + System.assertEquals(tags.size(), publishedLogEntryEventTags.size(), publishedLogEntryEventTags); Set tagsSet = new Set(tags); - for (LogEntryTag__c logEntryTag : logEntryTags) { - System.assert(tagsSet.contains(logEntryTag.Tag__r.Name)); + for (String publishedTag : publishedLogEntryEventTags) { + publishedTag = publishedTag.trim(); + System.assert(tagsSet.contains(publishedTag), publishedTag + ' not found in expected tags set: ' + tagsSet); } } } diff --git a/nebula-logger/core/tests/logger-engine/classes/FlowLogEntry_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/FlowLogEntry_Tests.cls index ea0d642b7..984b5dea2 100644 --- a/nebula-logger/core/tests/logger-engine/classes/FlowLogEntry_Tests.cls +++ b/nebula-logger/core/tests/logger-engine/classes/FlowLogEntry_Tests.cls @@ -4,7 +4,7 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class FlowLogEntry_Tests { static FlowLogEntry createFlowLogEntry() { FlowLogEntry flowEntry = new FlowLogEntry(); @@ -17,236 +17,234 @@ private class FlowLogEntry_Tests { @IsTest static void it_should_save_entry_when_logging_level_met() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel userLoggingLevel = LoggingLevel.FINEST; LoggingLevel flowEntryLoggingLevel = LoggingLevel.DEBUG; System.assert(userLoggingLevel.ordinal() < flowEntryLoggingLevel.ordinal()); - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowLogEntry flowEntry = createFlowLogEntry(); flowEntry.loggingLevelName = flowEntryLoggingLevel.name(); - FlowLogEntry.addFlowEntries(new List{ flowEntry }); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + FlowLogEntry.addFlowEntries(new List{ flowEntry }); System.assertEquals(1, Logger.getBufferSize()); - Logger.saveLog(); - Test.getEventBus().deliver(); - - Test.stopTest(); - LogEntry__c logEntry = [SELECT Id, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c FROM LogEntry__c ORDER BY CreatedDate LIMIT 1]; - System.assertEquals(flowEntry.loggingLevelName, logEntry.LoggingLevel__c); - System.assertEquals(flowEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(flowEntry.loggingLevelName, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); } @IsTest static void it_should_auto_save_entry_when_saveLog_is_true() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel userLoggingLevel = LoggingLevel.FINEST; LoggingLevel flowEntryLoggingLevel = LoggingLevel.DEBUG; System.assert(userLoggingLevel.ordinal() < flowEntryLoggingLevel.ordinal()); - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowLogEntry flowEntry = createFlowLogEntry(); flowEntry.loggingLevelName = flowEntryLoggingLevel.name(); flowEntry.saveLog = true; + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + FlowLogEntry.addFlowEntries(new List{ flowEntry }); - Test.getEventBus().deliver(); - - Test.stopTest(); - - LogEntry__c logEntry = [ - SELECT Id, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c, RecordId__c, RecordJson__c - FROM LogEntry__c - ORDER BY CreatedDate - LIMIT 1 - ]; - System.assertEquals(flowEntry.loggingLevelName, logEntry.LoggingLevel__c); - System.assertEquals(flowEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); + + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(flowEntry.loggingLevelName, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); } @IsTest static void it_should_auto_save_entry_with_save_method_when_saveMethodName_specified() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerDataStore.setMock(LoggerMockDataStore.getJobQueue()); LoggingLevel userLoggingLevel = LoggingLevel.FINEST; LoggingLevel flowEntryLoggingLevel = LoggingLevel.DEBUG; System.assert(userLoggingLevel.ordinal() < flowEntryLoggingLevel.ordinal()); - - Test.startTest(); - System.assertEquals(0, Limits.getQueueableJobs(), 'Test should start with 0 queueable jobs used'); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowLogEntry flowEntry = createFlowLogEntry(); flowEntry.loggingLevelName = flowEntryLoggingLevel.name(); flowEntry.saveLog = true; flowEntry.saveMethodName = Logger.SaveMethod.QUEUEABLE.name(); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + System.assertEquals(0, LoggerMockDataStore.getJobQueue().getEnqueuedJobs().size()); + FlowLogEntry.addFlowEntries(new List{ flowEntry }); - Test.getEventBus().deliver(); - - System.assertEquals(1, Limits.getQueueableJobs(), 'Log entries should have been saved using the QUEUEABLE save method'); - Test.stopTest(); - - LogEntry__c logEntry = [ - SELECT Id, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c, RecordId__c, RecordJson__c - FROM LogEntry__c - ORDER BY CreatedDate - LIMIT 1 - ]; - System.assertEquals(flowEntry.loggingLevelName, logEntry.LoggingLevel__c); - System.assertEquals(flowEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); + System.assertEquals(1, LoggerMockDataStore.getJobQueue().getEnqueuedJobs().size()); + LoggerMockDataStore.getJobQueue().executeJobs(); + + System.assertEquals(Logger.SaveMethod.QUEUEABLE.name(), Logger.lastSaveMethodNameUsed); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(flowEntry.loggingLevelName, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); } @IsTest static void it_should_not_save_entry_when_logging_level_not_met() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel userLoggingLevel = LoggingLevel.ERROR; LoggingLevel flowEntryLoggingLevel = LoggingLevel.DEBUG; System.assert(userLoggingLevel.ordinal() > flowEntryLoggingLevel.ordinal()); - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowLogEntry flowEntry = createFlowLogEntry(); flowEntry.loggingLevelName = flowEntryLoggingLevel.name(); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + FlowLogEntry.addFlowEntries(new List{ flowEntry }); - Test.getEventBus().deliver(); + Logger.saveLog(); System.assertEquals(0, Logger.getBufferSize()); - - Test.stopTest(); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); } @IsTest static void it_should_use_debug_as_default_level_when_faultMessage_is_null() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel expectedEntryLoggingLevel = LoggingLevel.DEBUG; - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = expectedEntryLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowLogEntry flowEntry = createFlowLogEntry(); System.assertEquals(null, flowEntry.faultMessage); System.assertEquals(null, flowEntry.loggingLevelName); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); FlowLogEntry.addFlowEntries(new List{ flowEntry }); - System.assertEquals(1, Logger.getBufferSize()); - Logger.saveLog(); - Test.getEventBus().deliver(); - - Test.stopTest(); - - LogEntry__c logEntry = [ - SELECT Id, ExceptionMessage__c, ExceptionType__c, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c - FROM LogEntry__c - ORDER BY CreatedDate - LIMIT 1 - ]; - System.assertEquals(null, logEntry.ExceptionMessage__c); - System.assertEquals(null, logEntry.ExceptionType__c); - System.assertEquals(expectedEntryLoggingLevel.name(), logEntry.LoggingLevel__c); - System.assertEquals(flowEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); + + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(null, publishedLogEntryEvent.ExceptionMessage__c); + System.assertEquals(null, publishedLogEntryEvent.ExceptionType__c); + System.assertEquals(expectedEntryLoggingLevel.name(), publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); } @IsTest static void it_should_use_error_as_default_level_when_faultMessage_is_not_null() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel expectedEntryLoggingLevel = LoggingLevel.ERROR; - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = LoggingLevel.FINEST.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowLogEntry flowEntry = createFlowLogEntry(); flowEntry.faultMessage = 'Whoops, a Flow error has occurred.'; System.assertEquals(null, flowEntry.loggingLevelName); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); FlowLogEntry.addFlowEntries(new List{ flowEntry }); - System.assertEquals(1, Logger.getBufferSize()); - Logger.saveLog(); - Test.getEventBus().deliver(); - - Test.stopTest(); - - LogEntry__c logEntry = [ - SELECT Id, ExceptionMessage__c, ExceptionType__c, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c - FROM LogEntry__c - ORDER BY CreatedDate - LIMIT 1 - ]; - System.assertEquals(flowEntry.faultMessage, logEntry.ExceptionMessage__c); - System.assertEquals('Flow.FaultError', logEntry.ExceptionType__c); - System.assertEquals(expectedEntryLoggingLevel.name(), logEntry.LoggingLevel__c); - System.assertEquals(flowEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); + + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(flowEntry.faultMessage, publishedLogEntryEvent.ExceptionMessage__c); + System.assertEquals('Flow.FaultError', publishedLogEntryEvent.ExceptionType__c); + System.assertEquals(expectedEntryLoggingLevel.name(), publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); } @IsTest static void it_should_set_log_scenario() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel userLoggingLevel = LoggingLevel.FINEST; - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowLogEntry flowEntry = createFlowLogEntry(); flowEntry.loggingLevelName = userLoggingLevel.name(); flowEntry.scenario = 'Some scenario'; + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + FlowLogEntry.addFlowEntries(new List{ flowEntry }); System.assertEquals(1, Logger.getBufferSize()); - Logger.saveLog(); - Test.getEventBus().deliver(); - String transactionId = Logger.getTransactionId(); - Test.stopTest(); - - Log__c log = [SELECT Id, Scenario__c FROM Log__c WHERE TransactionId__c = :transactionId]; - System.assertEquals(flowEntry.scenario, log.Scenario__c); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(flowEntry.scenario, publishedLogEntryEvent.Scenario__c); } @IsTest static void it_should_add_tags_to_log_entry() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel userLoggingLevel = LoggingLevel.FINEST; LoggingLevel flowEntryLoggingLevel = LoggingLevel.DEBUG; System.assert(userLoggingLevel.ordinal() < flowEntryLoggingLevel.ordinal()); - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); List tags = new List{ 'first tag', 'SECOND TAG' }; FlowLogEntry flowEntry = createFlowLogEntry(); flowEntry.loggingLevelName = flowEntryLoggingLevel.name(); flowEntry.tagsString = String.join(tags, ', '); - FlowLogEntry.addFlowEntries(new List{ flowEntry }); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + FlowLogEntry.addFlowEntries(new List{ flowEntry }); System.assertEquals(1, Logger.getBufferSize()); - Logger.saveLog(); - Test.getEventBus().deliver(); - Test.stopTest(); - - LogEntry__c logEntry = [SELECT Id, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c FROM LogEntry__c ORDER BY CreatedDate LIMIT 1]; - System.assertEquals(flowEntry.loggingLevelName, logEntry.LoggingLevel__c); - System.assertEquals(flowEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); - - List logEntryTags = [SELECT Id, LogEntry__c, Tag__c, Tag__r.Name FROM LogEntryTag__c WHERE LogEntry__c = :logEntry.Id]; - System.assertEquals(tags.size(), logEntryTags.size(), logEntryTags); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(flowEntry.loggingLevelName, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); + List publishedLogEntryEventTags = publishedLogEntryEvent.Tags__c.split('\n'); + System.assertEquals(tags.size(), publishedLogEntryEventTags.size(), publishedLogEntryEventTags); Set tagsSet = new Set(tags); - for (LogEntryTag__c logEntryTag : logEntryTags) { - System.assert(tagsSet.contains(logEntryTag.Tag__r.Name)); + for (String publishedTag : publishedLogEntryEventTags) { + publishedTag = publishedTag.trim(); + System.assert(tagsSet.contains(publishedTag), publishedTag + ' not found in expected tags set: ' + tagsSet); } } } diff --git a/nebula-logger/core/tests/logger-engine/classes/FlowLogger_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/FlowLogger_Tests.cls index 467a4a7e9..c5bdb7525 100644 --- a/nebula-logger/core/tests/logger-engine/classes/FlowLogger_Tests.cls +++ b/nebula-logger/core/tests/logger-engine/classes/FlowLogger_Tests.cls @@ -4,91 +4,107 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class FlowLogger_Tests { @IsTest static void it_should_add_entry_to_logger_buffer() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel entryLoggingLevel = LoggingLevel.DEBUG; - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = entryLoggingLevel.name(); - - FlowLogger.LogEntry logEntry = new FlowLogger.LogEntry(); - logEntry.flowName = 'MyFlow'; - logEntry.message = 'hello from Flow'; - logEntry.loggingLevelName = entryLoggingLevel.name(); - logEntry.saveLog = false; - logEntry.timestamp = System.now(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); System.assertEquals(0, Logger.getBufferSize()); System.assertEquals(0, [SELECT COUNT() FROM LogEntry__c]); - - FlowLogger.addEntries(new List{ logEntry }); + FlowLogger.LogEntry flowEntry = new FlowLogger.LogEntry(); + flowEntry.flowName = 'MyFlow'; + flowEntry.message = 'hello from Flow'; + flowEntry.loggingLevelName = entryLoggingLevel.name(); + flowEntry.saveLog = false; + flowEntry.timestamp = System.now(); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + + FlowLogger.addEntries(new List{ flowEntry }); System.assertEquals(1, Logger.getBufferSize()); - Logger.saveLog(); - Test.getEventBus().deliver(); - - Test.stopTest(); - System.assertEquals(1, [SELECT COUNT() FROM LogEntry__c]); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(flowEntry.loggingLevelName, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); + System.assertEquals(flowEntry.timestamp, publishedLogEntryEvent.Timestamp__c); } @IsTest static void it_should_auto_save_entry_when_saveLog_is_true() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel entryLoggingLevel = LoggingLevel.DEBUG; - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = entryLoggingLevel.name(); - - FlowLogger.LogEntry logEntry = new FlowLogger.LogEntry(); - logEntry.flowName = 'MyFlow'; - logEntry.message = 'hello from Flow'; - logEntry.loggingLevelName = entryLoggingLevel.name(); - logEntry.saveLog = true; - logEntry.timestamp = System.now(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); System.assertEquals(0, Logger.getBufferSize()); System.assertEquals(0, [SELECT COUNT() FROM LogEntry__c]); + FlowLogger.LogEntry flowEntry = new FlowLogger.LogEntry(); + flowEntry.flowName = 'MyFlow'; + flowEntry.message = 'hello from Flow'; + flowEntry.loggingLevelName = entryLoggingLevel.name(); + flowEntry.saveLog = true; + flowEntry.timestamp = System.now(); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + + FlowLogger.addEntries(new List{ flowEntry }); - FlowLogger.addEntries(new List{ logEntry }); - Test.getEventBus().deliver(); System.assertEquals(0, Logger.getBufferSize()); - - Test.stopTest(); - - System.assertEquals(1, [SELECT COUNT() FROM LogEntry__c]); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(flowEntry.loggingLevelName, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); + System.assertEquals(flowEntry.timestamp, publishedLogEntryEvent.Timestamp__c); } @IsTest static void it_should_auto_save_entry_with_save_method_when_saveMethodName_specified() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerDataStore.setMock(LoggerMockDataStore.getJobQueue()); LoggingLevel entryLoggingLevel = LoggingLevel.DEBUG; - - Test.startTest(); System.assertEquals(0, Limits.getQueueableJobs(), 'Test should start with 0 queueable jobs used'); - Logger.getUserSettings().LoggingLevel__c = entryLoggingLevel.name(); - - FlowLogger.LogEntry logEntry = new FlowLogger.LogEntry(); - logEntry.flowName = 'MyFlow'; - logEntry.message = 'hello from Flow'; - logEntry.loggingLevelName = entryLoggingLevel.name(); - logEntry.saveLog = true; - logEntry.saveMethodName = Logger.SaveMethod.QUEUEABLE.name(); - logEntry.timestamp = System.now(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); System.assertEquals(0, Logger.getBufferSize()); System.assertEquals(0, [SELECT COUNT() FROM LogEntry__c]); - - FlowLogger.addEntries(new List{ logEntry }); - Test.getEventBus().deliver(); + FlowLogger.LogEntry flowEntry = new FlowLogger.LogEntry(); + flowEntry.flowName = 'MyFlow'; + flowEntry.message = 'hello from Flow'; + flowEntry.loggingLevelName = entryLoggingLevel.name(); + flowEntry.saveLog = true; + flowEntry.saveMethodName = Logger.SaveMethod.QUEUEABLE.name(); + flowEntry.timestamp = System.now(); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + + FlowLogger.addEntries(new List{ flowEntry }); + System.assertEquals(1, LoggerMockDataStore.getJobQueue().getEnqueuedJobs().size()); + LoggerMockDataStore.getJobQueue().executeJobs(); + + System.assertEquals(Logger.SaveMethod.QUEUEABLE.name(), Logger.lastSaveMethodNameUsed); System.assertEquals(0, Logger.getBufferSize()); - - System.assertEquals(1, Limits.getQueueableJobs(), 'Log entries should have been saved using the QUEUEABLE save method'); - Test.stopTest(); - - System.assertEquals(1, [SELECT COUNT() FROM LogEntry__c]); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(flowEntry.loggingLevelName, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); + System.assertEquals(flowEntry.timestamp, publishedLogEntryEvent.Timestamp__c); } } diff --git a/nebula-logger/core/tests/logger-engine/classes/FlowRecordLogEntry_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/FlowRecordLogEntry_Tests.cls index b19667cf4..ca06b3418 100644 --- a/nebula-logger/core/tests/logger-engine/classes/FlowRecordLogEntry_Tests.cls +++ b/nebula-logger/core/tests/logger-engine/classes/FlowRecordLogEntry_Tests.cls @@ -4,7 +4,7 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class FlowRecordLogEntry_Tests { static FlowRecordLogEntry createFlowRecordLogEntry() { FlowRecordLogEntry flowRecordEntry = new FlowRecordLogEntry(); @@ -17,285 +17,270 @@ private class FlowRecordLogEntry_Tests { @IsTest static void it_should_save_entry_when_logging_level_met() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); User currentUser = new User( Id = UserInfo.getUserId(), FirstName = UserInfo.getFirstName(), LastName = UserInfo.getLastName(), Username = UserInfo.getUserName() ); - LoggingLevel userLoggingLevel = LoggingLevel.FINEST; LoggingLevel flowRecordEntryLoggingLevel = LoggingLevel.DEBUG; System.assert(userLoggingLevel.ordinal() < flowRecordEntryLoggingLevel.ordinal()); - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowRecordLogEntry flowRecordEntry = createFlowRecordLogEntry(); flowRecordEntry.loggingLevelName = flowRecordEntryLoggingLevel.name(); flowRecordEntry.record = currentUser; - FlowRecordLogEntry.addFlowRecordEntries(new List{ flowRecordEntry }); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + FlowRecordLogEntry.addFlowRecordEntries(new List{ flowRecordEntry }); System.assertEquals(1, Logger.getBufferSize()); - Logger.saveLog(); - Test.getEventBus().deliver(); - - Test.stopTest(); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); String expectedUserJson = JSON.serializePretty(currentUser); - - LogEntry__c logEntry = [ - SELECT Id, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c, RecordId__c, RecordJson__c - FROM LogEntry__c - ORDER BY CreatedDate - LIMIT 1 - ]; - System.assertEquals(flowRecordEntry.loggingLevelName, logEntry.LoggingLevel__c); - System.assertEquals(flowRecordEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); - System.assertEquals(currentUser.Id, logEntry.RecordId__c); - System.assertEquals(expectedUserJson, logEntry.RecordJson__c); + System.assertEquals(flowRecordEntry.loggingLevelName, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowRecordEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); + System.assertEquals(currentUser.Id, publishedLogEntryEvent.RecordId__c); + System.assertEquals(expectedUserJson, publishedLogEntryEvent.RecordJson__c); } @IsTest static void it_should_auto_save_entry_with_save_method_when_saveMethodName_specified() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); + LoggerDataStore.setMock(LoggerMockDataStore.getJobQueue()); User currentUser = new User( Id = UserInfo.getUserId(), FirstName = UserInfo.getFirstName(), LastName = UserInfo.getLastName(), Username = UserInfo.getUserName() ); - LoggingLevel userLoggingLevel = LoggingLevel.FINEST; LoggingLevel flowRecordEntryLoggingLevel = LoggingLevel.DEBUG; System.assert(userLoggingLevel.ordinal() < flowRecordEntryLoggingLevel.ordinal()); - - Test.startTest(); System.assertEquals(0, Limits.getQueueableJobs(), 'Test should start with 0 queueable jobs used'); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowRecordLogEntry flowRecordEntry = createFlowRecordLogEntry(); flowRecordEntry.loggingLevelName = flowRecordEntryLoggingLevel.name(); flowRecordEntry.record = currentUser; flowRecordEntry.saveLog = true; flowRecordEntry.saveMethodName = Logger.SaveMethod.QUEUEABLE.name(); - FlowRecordLogEntry.addFlowRecordEntries(new List{ flowRecordEntry }); - Test.getEventBus().deliver(); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + System.assertEquals(0, LoggerMockDataStore.getJobQueue().getEnqueuedJobs().size()); - System.assertEquals(1, Limits.getQueueableJobs(), 'Log entries should have been saved using the QUEUEABLE save method'); - Test.stopTest(); + FlowRecordLogEntry.addFlowRecordEntries(new List{ flowRecordEntry }); + System.assertEquals(1, LoggerMockDataStore.getJobQueue().getEnqueuedJobs().size()); + LoggerMockDataStore.getJobQueue().executeJobs(); + System.assertEquals(Logger.SaveMethod.QUEUEABLE.name(), Logger.lastSaveMethodNameUsed); + System.assertEquals(1, LoggerMockDataStore.getJobQueue().getEnqueuedJobs().size()); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); String expectedUserJson = JSON.serializePretty(currentUser); - - LogEntry__c logEntry = [ - SELECT Id, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c, RecordId__c, RecordJson__c - FROM LogEntry__c - ORDER BY CreatedDate - LIMIT 1 - ]; - System.assertEquals(flowRecordEntry.loggingLevelName, logEntry.LoggingLevel__c); - System.assertEquals(flowRecordEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); - System.assertEquals(currentUser.Id, logEntry.RecordId__c); - System.assertEquals(expectedUserJson, logEntry.RecordJson__c); + System.assertEquals(flowRecordEntry.loggingLevelName, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowRecordEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); + System.assertEquals(currentUser.Id, publishedLogEntryEvent.RecordId__c); + System.assertEquals(expectedUserJson, publishedLogEntryEvent.RecordJson__c); } @IsTest static void it_should_auto_save_entry_when_saveLog_is_true() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); User currentUser = new User( Id = UserInfo.getUserId(), FirstName = UserInfo.getFirstName(), LastName = UserInfo.getLastName(), Username = UserInfo.getUserName() ); - LoggingLevel userLoggingLevel = LoggingLevel.FINEST; LoggingLevel flowRecordEntryLoggingLevel = LoggingLevel.DEBUG; System.assert(userLoggingLevel.ordinal() < flowRecordEntryLoggingLevel.ordinal()); - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowRecordLogEntry flowRecordEntry = createFlowRecordLogEntry(); flowRecordEntry.loggingLevelName = flowRecordEntryLoggingLevel.name(); flowRecordEntry.record = currentUser; flowRecordEntry.saveLog = true; - FlowRecordLogEntry.addFlowRecordEntries(new List{ flowRecordEntry }); - Test.getEventBus().deliver(); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); - Test.stopTest(); + FlowRecordLogEntry.addFlowRecordEntries(new List{ flowRecordEntry }); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); String expectedUserJson = JSON.serializePretty(currentUser); - - LogEntry__c logEntry = [ - SELECT Id, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c, RecordId__c, RecordJson__c - FROM LogEntry__c - ORDER BY CreatedDate - LIMIT 1 - ]; - System.assertEquals(flowRecordEntry.loggingLevelName, logEntry.LoggingLevel__c); - System.assertEquals(flowRecordEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); - System.assertEquals(currentUser.Id, logEntry.RecordId__c); - System.assertEquals(expectedUserJson, logEntry.RecordJson__c); + System.assertEquals(flowRecordEntry.loggingLevelName, publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowRecordEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); + System.assertEquals(currentUser.Id, publishedLogEntryEvent.RecordId__c); + System.assertEquals(expectedUserJson, publishedLogEntryEvent.RecordJson__c); } @IsTest static void it_should_not_save_entry_when_logging_level_not_met() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); User currentUser = new User( Id = UserInfo.getUserId(), FirstName = UserInfo.getFirstName(), LastName = UserInfo.getLastName(), Username = UserInfo.getUserName() ); - LoggingLevel userLoggingLevel = LoggingLevel.ERROR; LoggingLevel flowRecordEntryLoggingLevel = LoggingLevel.DEBUG; System.assert(userLoggingLevel.ordinal() > flowRecordEntryLoggingLevel.ordinal()); - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowRecordLogEntry flowRecordEntry = createFlowRecordLogEntry(); flowRecordEntry.loggingLevelName = flowRecordEntryLoggingLevel.name(); flowRecordEntry.record = currentUser; - FlowRecordLogEntry.addFlowRecordEntries(new List{ flowRecordEntry }); - Test.getEventBus().deliver(); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + FlowRecordLogEntry.addFlowRecordEntries(new List{ flowRecordEntry }); System.assertEquals(0, Logger.getBufferSize()); + Logger.saveLog(); - Test.stopTest(); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); } @IsTest static void it_should_use_debug_as_default_level_when_faultMessage_is_null() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel expectedEntryLoggingLevel = LoggingLevel.DEBUG; - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = expectedEntryLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowRecordLogEntry flowRecordEntry = createFlowRecordLogEntry(); System.assertEquals(null, flowRecordEntry.faultMessage); System.assertEquals(null, flowRecordEntry.loggingLevelName); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); FlowRecordLogEntry.addFlowRecordEntries(new List{ flowRecordEntry }); - System.assertEquals(1, Logger.getBufferSize()); - Logger.saveLog(); - Test.getEventBus().deliver(); - - Test.stopTest(); - LogEntry__c logEntry = [ - SELECT Id, ExceptionMessage__c, ExceptionType__c, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c, RecordId__c, RecordJson__c - FROM LogEntry__c - ORDER BY CreatedDate - LIMIT 1 - ]; - System.assertEquals(null, logEntry.ExceptionMessage__c); - System.assertEquals(null, logEntry.ExceptionType__c); - System.assertEquals(expectedEntryLoggingLevel.name(), logEntry.LoggingLevel__c); - System.assertEquals(flowRecordEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(null, publishedLogEntryEvent.ExceptionMessage__c); + System.assertEquals(null, publishedLogEntryEvent.ExceptionType__c); + System.assertEquals(expectedEntryLoggingLevel.name(), publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowRecordEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); } @IsTest static void it_should_use_error_as_default_level_when_faultMessage_is_not_null() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel expectedEntryLoggingLevel = LoggingLevel.ERROR; - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = LoggingLevel.FINEST.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); FlowRecordLogEntry flowRecordEntry = createFlowRecordLogEntry(); flowRecordEntry.faultMessage = 'Whoops, a Flow error has occurred.'; System.assertEquals(null, flowRecordEntry.loggingLevelName); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); FlowRecordLogEntry.addFlowRecordEntries(new List{ flowRecordEntry }); - System.assertEquals(1, Logger.getBufferSize()); - Logger.saveLog(); - Test.getEventBus().deliver(); - Test.stopTest(); - - LogEntry__c logEntry = [ - SELECT Id, ExceptionMessage__c, ExceptionType__c, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c, RecordId__c, RecordJson__c - FROM LogEntry__c - ORDER BY CreatedDate - LIMIT 1 - ]; - System.assertEquals(flowRecordEntry.faultMessage, logEntry.ExceptionMessage__c); - System.assertEquals('Flow.FaultError', logEntry.ExceptionType__c); - System.assertEquals(expectedEntryLoggingLevel.name(), logEntry.LoggingLevel__c); - System.assertEquals(flowRecordEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(flowRecordEntry.faultMessage, publishedLogEntryEvent.ExceptionMessage__c); + System.assertEquals('Flow.FaultError', publishedLogEntryEvent.ExceptionType__c); + System.assertEquals(expectedEntryLoggingLevel.name(), publishedLogEntryEvent.LoggingLevel__c); + System.assertEquals(flowRecordEntry.message, publishedLogEntryEvent.Message__c); + System.assertEquals('Flow', publishedLogEntryEvent.OriginType__c); } @IsTest static void it_should_set_log_scenario() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel userLoggingLevel = LoggingLevel.FINEST; - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - FlowRecordLogEntry flowEntry = createFlowRecordLogEntry(); - flowEntry.loggingLevelName = userLoggingLevel.name(); - flowEntry.scenario = 'Some scenario'; - FlowRecordLogEntry.addFlowRecordEntries(new List{ flowEntry }); - System.assertEquals(1, Logger.getBufferSize()); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + FlowRecordLogEntry flowRecordEntry = createFlowRecordLogEntry(); + flowRecordEntry.loggingLevelName = userLoggingLevel.name(); + flowRecordEntry.scenario = 'Some scenario'; + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + FlowRecordLogEntry.addFlowRecordEntries(new List{ flowRecordEntry }); + System.assertEquals(1, Logger.getBufferSize()); Logger.saveLog(); - Test.getEventBus().deliver(); - String transactionId = Logger.getTransactionId(); - Test.stopTest(); - - Log__c log = [SELECT Id, Scenario__c FROM Log__c WHERE TransactionId__c = :transactionId]; - System.assertEquals(flowEntry.scenario, log.Scenario__c); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + System.assertEquals(flowRecordEntry.scenario, publishedLogEntryEvent.Scenario__c); } @IsTest static void it_should_add_tags_to_log_entry() { + LoggerDataStore.setMock(LoggerMockDataStore.getEventBus()); LoggingLevel userLoggingLevel = LoggingLevel.FINEST; LoggingLevel flowRecordEntryLoggingLevel = LoggingLevel.DEBUG; System.assert(userLoggingLevel.ordinal() < flowRecordEntryLoggingLevel.ordinal()); - - Test.startTest(); - Logger.getUserSettings().LoggingLevel__c = userLoggingLevel.name(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); List tags = new List{ 'first tag', 'SECOND TAG' }; - FlowRecordLogEntry flowEntry = createFlowRecordLogEntry(); - flowEntry.loggingLevelName = flowRecordEntryLoggingLevel.name(); - flowEntry.tagsString = String.join(tags, ', '); - FlowRecordLogEntry.addFlowRecordEntries(new List{ flowEntry }); + FlowRecordLogEntry flowRecordEntry = createFlowRecordLogEntry(); + flowRecordEntry.loggingLevelName = flowRecordEntryLoggingLevel.name(); + flowRecordEntry.tagsString = String.join(tags, ', '); + System.assertEquals(0, Logger.saveLogCallCount); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(0, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + FlowRecordLogEntry.addFlowRecordEntries(new List{ flowRecordEntry }); System.assertEquals(1, Logger.getBufferSize()); - Logger.saveLog(); - Test.getEventBus().deliver(); - - Test.stopTest(); - LogEntry__c logEntry = [SELECT Id, LoggingLevel__c, Message__c, OriginType__c, OriginLocation__c FROM LogEntry__c ORDER BY CreatedDate LIMIT 1]; - System.assertEquals(flowEntry.loggingLevelName, logEntry.LoggingLevel__c); - System.assertEquals(flowEntry.message, logEntry.Message__c); - System.assertEquals('Flow', logEntry.OriginType__c); - - List logEntryTags = [SELECT Id, LogEntry__c, Tag__c, Tag__r.Name FROM LogEntryTag__c WHERE LogEntry__c = :logEntry.Id]; - System.assertEquals(tags.size(), logEntryTags.size(), logEntryTags); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(1, Logger.saveLogCallCount); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishCallCount()); + System.assertEquals(1, LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().size()); + LogEntryEvent__e publishedLogEntryEvent = (LogEntryEvent__e) LoggerMockDataStore.getEventBus().getPublishedPlatformEvents().get(0); + List publishedLogEntryEventTags = publishedLogEntryEvent.Tags__c.split('\n'); + System.assertEquals(tags.size(), publishedLogEntryEventTags.size(), publishedLogEntryEventTags); Set tagsSet = new Set(tags); - for (LogEntryTag__c logEntryTag : logEntryTags) { - System.assert(tagsSet.contains(logEntryTag.Tag__r.Name)); + for (String publishedTag : publishedLogEntryEventTags) { + publishedTag = publishedTag.trim(); + System.assert(tagsSet.contains(publishedTag), publishedTag + ' not found in expected tags set: ' + tagsSet); } } } diff --git a/nebula-logger/core/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls index 5c6f0e412..7b230d3c9 100644 --- a/nebula-logger/core/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls +++ b/nebula-logger/core/tests/logger-engine/classes/LogEntryEventBuilder_Tests.cls @@ -6,26 +6,8 @@ @SuppressWarnings( 'PMD.ApexDoc, PMD.ApexAssertionsShouldIncludeMessage, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount' ) -@IsTest +@IsTest(IsParallel=false) private class LogEntryEventBuilder_Tests { - static String getMessage() { - return 'Hello, world'; - } - - static LogMessage getLogMessage() { - return new LogMessage('The current date is {0}', System.today()); - } - - static LogEntryDataMaskRule__mdt getSocialSecurityNumberDataMaskRule() { - return new LogEntryDataMaskRule__mdt( - IsEnabled__c = true, - ApplyToMessage__c = true, - ApplyToRecordJson__c = true, - SensitiveDataRegEx__c = '(\\d{3})[- ]*(\\d{2})[- ]*(\\d{4})', - ReplacementRegEx__c = 'XXX-XX-$3' - ); - } - @IsTest static void it_should_short_circuit_when_disabled() { LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.DEBUG, false); @@ -136,48 +118,75 @@ private class LogEntryEventBuilder_Tests { } @IsTest - static void it_should_apply_data_mask_rule_to_message_when_enabled() { + static void it_should_not_apply_data_mask_rule_when_rule_disabled() { Logger.getUserSettings().IsDataMaskingEnabled__c = true; LogEntryDataMaskRule__mdt rule = getSocialSecurityNumberDataMaskRule(); - rule.ApplyToMessage__c = true; - rule.ApplyToRecordJson__c = false; - LogEntryEventBuilder.addMockDataMaskRule(rule); - + rule.IsEnabled__c = false; + LogEntryEventBuilder.setMockDataMaskRule(rule); String message = 'Something, something, and my social is 400 11 9999 in case you want to steal my identity'; - String expectedSanitizedMessage = 'Something, something, and my social is XXX-XX-9999 in case you want to steal my identity'; Account account = new Account(Name = message); String accountJson = JSON.serializePretty(account); - String expectedSanitizedAccountJson = JSON.serializePretty(new Account(Name = message)); + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); builder.setMessage(message).setRecord(account); - System.assertEquals(true, builder.getLogEntryEvent().MessageMasked__c); - System.assertNotEquals(message, builder.getLogEntryEvent().Message__c); - System.assertEquals(expectedSanitizedMessage, builder.getLogEntryEvent().Message__c); + System.assertEquals(false, builder.getLogEntryEvent().MessageMasked__c, builder.getLogEntryEvent().Message__c); + System.assertEquals(message, builder.getLogEntryEvent().Message__c); System.assertEquals(false, builder.getLogEntryEvent().RecordJsonMasked__c); System.assertEquals(accountJson, builder.getLogEntryEvent().RecordJson__c); - System.assertEquals(expectedSanitizedAccountJson, builder.getLogEntryEvent().RecordJson__c); } @IsTest - static void it_should_apply_data_mask_rule_to_record_json_when_enabled() { - Logger.getUserSettings().IsDataMaskingEnabled__c = true; + static void it_should_not_apply_data_mask_rule_when_disabled_for_user() { + Logger.getUserSettings().IsDataMaskingEnabled__c = false; LogEntryDataMaskRule__mdt rule = getSocialSecurityNumberDataMaskRule(); - rule.ApplyToMessage__c = false; - rule.ApplyToRecordJson__c = true; - LogEntryEventBuilder.addMockDataMaskRule(rule); - + rule.IsEnabled__c = true; + LogEntryEventBuilder.setMockDataMaskRule(rule); String message = 'Something, something, and my social is 400 11 9999 in case you want to steal my identity'; - String expectedSanitizedMessage = 'Something, something, and my social is XXX-XX-9999 in case you want to steal my identity'; Account account = new Account(Name = message); String accountJson = JSON.serializePretty(account); - String expectedSanitizedAccountJson = JSON.serializePretty(new Account(Name = expectedSanitizedMessage)); + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); builder.setMessage(message).setRecord(account); System.assertEquals(false, builder.getLogEntryEvent().MessageMasked__c); System.assertEquals(message, builder.getLogEntryEvent().Message__c); - System.assertNotEquals(expectedSanitizedMessage, builder.getLogEntryEvent().Message__c); + System.assertEquals(false, builder.getLogEntryEvent().RecordJsonMasked__c); + System.assertEquals(accountJson, builder.getLogEntryEvent().RecordJson__c); + } + + @IsTest + static void it_should_apply_data_mask_rule_to_message_when_enabled() { + Logger.getUserSettings().IsDataMaskingEnabled__c = true; + LogEntryDataMaskRule__mdt rule = getSocialSecurityNumberDataMaskRule(); + rule.IsEnabled__c = true; + LogEntryEventBuilder.setMockDataMaskRule(rule); + String sensitiveString = 'Something, something, and my social is 400 11 9999 in case you want to steal my identity'; + String expectedSanitizedString = 'Something, something, and my social is XXX-XX-9999 in case you want to steal my identity'; + + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); + builder.setMessage(sensitiveString); + + System.assertEquals(true, builder.getLogEntryEvent().MessageMasked__c); + System.assertNotEquals(sensitiveString, builder.getLogEntryEvent().Message__c); + System.assertEquals(expectedSanitizedString, builder.getLogEntryEvent().Message__c); + } + + @IsTest + static void it_should_apply_data_mask_rule_to_record_json_when_enabled() { + Logger.getUserSettings().IsDataMaskingEnabled__c = true; + LogEntryDataMaskRule__mdt rule = getSocialSecurityNumberDataMaskRule(); + rule.IsEnabled__c = true; + LogEntryEventBuilder.setMockDataMaskRule(rule); + String sensitiveString = 'Something, something, and my social is 400 11 9999 in case you want to steal my identity'; + String expectedSanitizedString = 'Something, something, and my social is XXX-XX-9999 in case you want to steal my identity'; + Account account = new Account(Name = sensitiveString); + String accountJson = JSON.serializePretty(account); + String expectedSanitizedAccountJson = JSON.serializePretty(new Account(Name = expectedSanitizedString)); + + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); + builder.setRecord(account); + System.assertEquals(true, builder.getLogEntryEvent().RecordJsonMasked__c); System.assertNotEquals(accountJson, builder.getLogEntryEvent().RecordJson__c); System.assertEquals(expectedSanitizedAccountJson, builder.getLogEntryEvent().RecordJson__c); @@ -187,64 +196,58 @@ private class LogEntryEventBuilder_Tests { static void it_should_apply_data_mask_rule_to_record_list_json_when_enabled() { Logger.getUserSettings().IsDataMaskingEnabled__c = true; LogEntryDataMaskRule__mdt rule = getSocialSecurityNumberDataMaskRule(); - rule.ApplyToMessage__c = false; - rule.ApplyToRecordJson__c = true; - LogEntryEventBuilder.addMockDataMaskRule(rule); + rule.IsEnabled__c = true; + LogEntryEventBuilder.setMockDataMaskRule(rule); - String message = 'Something, something, and my social is 400 11 9999 in case you want to steal my identity'; - String expectedSanitizedMessage = 'Something, something, and my social is XXX-XX-9999 in case you want to steal my identity'; - List accounts = new List{ new Account(Name = message) }; + String sensitiveString = 'Something, something, and my social is 400 11 9999 in case you want to steal my identity'; + String expectedSanitizedString = 'Something, something, and my social is XXX-XX-9999 in case you want to steal my identity'; + List accounts = new List{ new Account(Name = sensitiveString) }; String accountListJson = JSON.serializePretty(accounts); - String expectedSanitizedAccountListJson = JSON.serializePretty(new List{ new Account(Name = expectedSanitizedMessage) }); + String expectedSanitizedAccountListJson = JSON.serializePretty(new List{ new Account(Name = expectedSanitizedString) }); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - builder.setMessage(message).setRecord(accounts); + builder.setRecord(accounts); - System.assertEquals(false, builder.getLogEntryEvent().MessageMasked__c); - System.assertEquals(message, builder.getLogEntryEvent().Message__c); - System.assertNotEquals(expectedSanitizedMessage, builder.getLogEntryEvent().Message__c); System.assertEquals(true, builder.getLogEntryEvent().RecordJsonMasked__c); System.assertNotEquals(accountListJson, builder.getLogEntryEvent().RecordJson__c); System.assertEquals(expectedSanitizedAccountListJson, builder.getLogEntryEvent().RecordJson__c); } @IsTest - static void it_should_not_data_mask_rule_when_disabled_for_message_and_json() { + static void it_should_apply_data_mask_rule_to_http_request_body_when_enabled() { Logger.getUserSettings().IsDataMaskingEnabled__c = true; LogEntryDataMaskRule__mdt rule = getSocialSecurityNumberDataMaskRule(); - rule.ApplyToMessage__c = false; - rule.ApplyToRecordJson__c = false; - LogEntryEventBuilder.addMockDataMaskRule(rule); + rule.IsEnabled__c = true; + LogEntryEventBuilder.setMockDataMaskRule(rule); + String sensitiveString = 'Something, something, and my social is 400 11 9999 in case you want to steal my identity'; + String expectedSanitizedString = 'Something, something, and my social is XXX-XX-9999 in case you want to steal my identity'; + HttpRequest httpRequest = LoggerMockDataCreator.createHttpRequest(); + httpRequest.setBody(sensitiveString); - String message = 'Something, something, and my social is 400 11 9999 in case you want to steal my identity'; - Account account = new Account(Name = message); - String accountJson = JSON.serializePretty(account); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - builder.setMessage(message).setRecord(account); + builder.setHttpRequestDetails(httpRequest); - System.assertEquals(false, builder.getLogEntryEvent().MessageMasked__c); - System.assertEquals(message, builder.getLogEntryEvent().Message__c); - System.assertEquals(false, builder.getLogEntryEvent().RecordJsonMasked__c); - System.assertEquals(accountJson, builder.getLogEntryEvent().RecordJson__c); + System.assertEquals(true, builder.getLogEntryEvent().HttpRequestBodyMasked__c); + System.assertNotEquals(sensitiveString, builder.getLogEntryEvent().HttpRequestBody__c); + System.assertEquals(expectedSanitizedString, builder.getLogEntryEvent().HttpRequestBody__c); } @IsTest - static void it_should_not_data_mask_rule_when_disabled_for_user() { - Logger.getUserSettings().IsDataMaskingEnabled__c = false; + static void it_should_apply_data_mask_rule_to_http_response_body_when_enabled() { + Logger.getUserSettings().IsDataMaskingEnabled__c = true; LogEntryDataMaskRule__mdt rule = getSocialSecurityNumberDataMaskRule(); - rule.ApplyToMessage__c = true; - rule.ApplyToRecordJson__c = true; - LogEntryEventBuilder.addMockDataMaskRule(rule); + rule.IsEnabled__c = true; + LogEntryEventBuilder.setMockDataMaskRule(rule); + String sensitiveString = 'Something, something, and my social is 400 11 9999 in case you want to steal my identity'; + String expectedSanitizedString = 'Something, something, and my social is XXX-XX-9999 in case you want to steal my identity'; + HttpResponse httpResponse = LoggerMockDataCreator.createHttpResponse(); + httpResponse.setBody(sensitiveString); - String message = 'Something, something, and my social is 400 11 9999 in case you want to steal my identity'; - Account account = new Account(Name = message); - String accountJson = JSON.serializePretty(account); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - builder.setMessage(message).setRecord(account); + builder.setHttpResponseDetails(httpResponse); - System.assertEquals(false, builder.getLogEntryEvent().MessageMasked__c); - System.assertEquals(message, builder.getLogEntryEvent().Message__c); - System.assertEquals(false, builder.getLogEntryEvent().RecordJsonMasked__c); - System.assertEquals(accountJson, builder.getLogEntryEvent().RecordJson__c); + System.assertEquals(true, builder.getLogEntryEvent().HttpResponseBodyMasked__c); + System.assertNotEquals(sensitiveString, builder.getLogEntryEvent().HttpResponseBody__c); + System.assertEquals(expectedSanitizedString, builder.getLogEntryEvent().HttpResponseBody__c); } @IsTest @@ -295,379 +298,166 @@ private class LogEntryEventBuilder_Tests { } @IsTest - static void it_should_set_database_result_fields_for_successful_deleteResult() { - Log__c log = new Log__c(TransactionId__c = '1234'); - insert log; - - Database.DeleteResult deleteResult = Database.delete(log, false); - System.assertEquals(true, deleteResult.isSuccess()); + static void it_should_set_database_result_fields_for_deleteResult() { + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(true); + System.assertNotEquals(null, deleteResult); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); builder.setDatabaseResult(deleteResult); + System.assertEquals(1, builder.getLogEntryEvent().DatabaseResultCollectionSize__c); System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); System.assertEquals(JSON.serializePretty(deleteResult), builder.getLogEntryEvent().DatabaseResultJson__c); System.assertEquals(Database.DeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest - static void it_should_set_database_result_fields_for_failed_deleteResult() { - Log__c log = new Log__c(TransactionId__c = '1234'); - insert log; - // Delete the log twice to trigger a DeleteResult error - delete log; - Database.DeleteResult deleteResult = Database.delete(log, false); - System.assertEquals(false, deleteResult.isSuccess()); + static void it_should_set_database_result_fields_for_mergeResult() { + Database.MergeResult mergeResult = LoggerMockDataCreator.createDatabaseMergeResult(true); + System.assertNotEquals(null, mergeResult); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - builder.setDatabaseResult(deleteResult); + builder.setDatabaseResult(mergeResult); + System.assertEquals(1, builder.getLogEntryEvent().DatabaseResultCollectionSize__c); System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(deleteResult), builder.getLogEntryEvent().DatabaseResultJson__c); - System.assertEquals(Database.DeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(JSON.serializePretty(mergeResult), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } - // TODO only some standard objects can be merged - need to find a way to either mock or trigger a merge result that works in all orgs - // @IsTest - // static void it_should_set_database_result_fields_for_failed_mergeResult() { - // Database.MergeResult mergeResult = Database.merge(new Account(Name='Expcted'), new Account(Name='Failure'), false); - // System.assertEquals(false, mergeResult.isSuccess()); - - // LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - // Test.startTest(); - // builder.setDatabaseResult(mergeResult); - // Test.stopTest(); - - // LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - - // System.assertEquals(JSON.serializePretty(mergeResult), logEntryEvent.DatabaseResultJson__c); - // System.assertEquals(Database.MergeResult.class.getName(), logEntryEvent.DatabaseResultType__c); - // } - @IsTest - static void it_should_set_database_result_fields_for_successful_saveResult() { - Database.SaveResult saveResult = Database.insert(new Log__c(TransactionId__c = '1234'), false); - System.assertEquals(true, saveResult.isSuccess()); + static void it_should_set_database_result_fields_for_saveResult() { + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(true); + System.assertNotEquals(null, saveResult); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); builder.setDatabaseResult(saveResult); + System.assertEquals(1, builder.getLogEntryEvent().DatabaseResultCollectionSize__c); System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); System.assertEquals(JSON.serializePretty(saveResult), builder.getLogEntryEvent().DatabaseResultJson__c); System.assertEquals(Database.SaveResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest - static void it_should_set_database_result_fields_for_failed_saveResult() { - Database.SaveResult saveResult = Database.insert(new Account(), false); - System.assertEquals(false, saveResult.isSuccess()); - - LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - builder.setDatabaseResult(saveResult); - - System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(saveResult), builder.getLogEntryEvent().DatabaseResultJson__c); - System.assertEquals(Database.SaveResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); - } - - @IsTest - static void it_should_set_database_result_fields_for_successful_undeleteResult() { - Log__c log = new Log__c(TransactionId__c = '1234'); - insert log; - delete log; - - Database.UndeleteResult undeleteResult = Database.undelete(log.Id, false); - System.assertEquals(true, undeleteResult.isSuccess()); + static void it_should_set_database_result_fields_for_undeleteResult() { + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); + System.assertNotEquals(null, undeleteResult); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); builder.setDatabaseResult(undeleteResult); + System.assertEquals(1, builder.getLogEntryEvent().DatabaseResultCollectionSize__c); System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); System.assertEquals(JSON.serializePretty(undeleteResult), builder.getLogEntryEvent().DatabaseResultJson__c); System.assertEquals(Database.UndeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest - static void it_should_set_database_result_fields_for_failed_undeleteResult() { - Log__c log = new Log__c(TransactionId__c = '1234'); - insert log; - delete log; - // Hard delete to (later) cause an undelete error - Database.emptyRecycleBin(log); - - Database.UndeleteResult undeleteResult = Database.undelete(log.Id, false); - System.assertEquals(false, undeleteResult.isSuccess()); - - LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - builder.setDatabaseResult(undeleteResult); - - System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(undeleteResult), builder.getLogEntryEvent().DatabaseResultJson__c); - System.assertEquals(Database.UndeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); - } - - @IsTest - static void it_should_set_database_result_fields_for_successful_upsertResult_when_insert() { - // UpsertResult for a new record insert - Database.UpsertResult upsertResult = Database.upsert(new Log__c(TransactionId__c = '1234'), false); - System.assertEquals(true, upsertResult.isSuccess()); - - LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - builder.setDatabaseResult(upsertResult); - - System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(upsertResult), builder.getLogEntryEvent().DatabaseResultJson__c); - System.assertEquals(Database.UpsertResult.class.getName() + '.Insert', builder.getLogEntryEvent().DatabaseResultType__c); - } - - @IsTest - static void it_should_set_database_result_fields_for_failed_upsertResult_when_insert() { - // UpsertResult for a new record insert - Database.UpsertResult upsertResult = Database.upsert(new Account(), false); - System.assertEquals(false, upsertResult.isSuccess()); + static void it_should_set_database_result_fields_for_upsertResult_when_insert() { + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, true); + System.assertNotEquals(null, upsertResult); + System.assertEquals(true, upsertResult.isCreated()); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); builder.setDatabaseResult(upsertResult); + System.assertEquals(1, builder.getLogEntryEvent().DatabaseResultCollectionSize__c); System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); System.assertEquals(JSON.serializePretty(upsertResult), builder.getLogEntryEvent().DatabaseResultJson__c); System.assertEquals(Database.UpsertResult.class.getName() + '.Insert', builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest - static void it_should_set_database_result_fields_for_successful_upsertResult_when_update() { - // UpsertResult for an existing record update - Log__c log = new Log__c(TransactionId__c = '1234'); - insert log; - log.TransactionId__c = '9876'; - - Database.UpsertResult upsertResult = Database.upsert(log, false); - System.assertEquals(true, upsertResult.isSuccess()); + static void it_should_set_database_result_fields_for_upsertResult_when_update() { + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, false); + System.assertNotEquals(null, upsertResult); + System.assertEquals(false, upsertResult.isCreated()); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); builder.setDatabaseResult(upsertResult); + System.assertEquals(1, builder.getLogEntryEvent().DatabaseResultCollectionSize__c); System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); System.assertEquals(JSON.serializePretty(upsertResult), builder.getLogEntryEvent().DatabaseResultJson__c); System.assertEquals(Database.UpsertResult.class.getName() + '.Update', builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest - static void it_should_set_database_result_fields_for_failed_upsertResult_when_update() { - // UpsertResult for an existing record update - Log__c log = new Log__c(TransactionId__c = '1234'); - insert log; - - // Use a log entry this time to handle the upsert scenario - LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, Name = 'Test Log Entry'); - insert logEntry; - - // Set name field to a value too long for the field - Integer maxFieldLength = Schema.LogEntry__c.Name.getDescribe().getLength(); - logEntry.Name = '0'.repeat(maxFieldLength + 10); - - Database.UpsertResult upsertResult = Database.upsert(logEntry, false); - System.assertEquals(false, upsertResult.isSuccess()); - - LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - builder.setDatabaseResult(upsertResult); - - System.assertEquals('Single', builder.getLogEntryEvent().DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(upsertResult), builder.getLogEntryEvent().DatabaseResultJson__c); - System.assertEquals(Database.UpsertResult.class.getName() + '.Update', builder.getLogEntryEvent().DatabaseResultType__c); - } - - @IsTest - static void it_should_set_database_result_fields_for_list_of_successful_deleteResult() { - List logs = new List(); + static void it_should_set_database_result_fields_for_list_of_deleteResult() { + List deleteResults = new List(); for (Integer i = 0; i < 5; i++) { - Log__c log = new Log__c(TransactionId__c = '1234' + i); - logs.add(log); - } - insert logs; - - List deleteResults = Database.delete(logs, false); - for (Database.DeleteResult deleteResult : deleteResults) { - System.assertEquals(true, deleteResult.isSuccess()); + deleteResults.add(LoggerMockDataCreator.createDatabaseDeleteResult(false)); } LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); builder.setDatabaseResult(deleteResults); + System.assertEquals(deleteResults.size(), builder.getLogEntryEvent().DatabaseResultCollectionSize__c); System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); System.assertEquals(JSON.serializePretty(deleteResults), builder.getLogEntryEvent().DatabaseResultJson__c); System.assertEquals(Database.DeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest - static void it_should_set_database_result_fields_for_list_of_failed_deleteResult() { - List logs = new List(); + static void it_should_set_database_result_fields_for_list_of_mergeResult() { + List mergeResults = new List(); for (Integer i = 0; i < 5; i++) { - Log__c log = new Log__c(TransactionId__c = '1234' + i); - logs.add(log); - } - insert logs; - - // Delete the logs twice to trigger DeleteResult errors - delete logs; - - List deleteResults = Database.delete(logs, false); - for (Database.DeleteResult deleteResult : deleteResults) { - System.assertEquals(false, deleteResult.isSuccess()); + mergeResults.add(LoggerMockDataCreator.createDatabaseMergeResult(false)); } LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - builder.setDatabaseResult(deleteResults); + builder.setDatabaseResult(mergeResults); + System.assertEquals(mergeResults.size(), builder.getLogEntryEvent().DatabaseResultCollectionSize__c); System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(deleteResults), builder.getLogEntryEvent().DatabaseResultJson__c); - System.assertEquals(Database.DeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); + System.assertEquals(JSON.serializePretty(mergeResults), builder.getLogEntryEvent().DatabaseResultJson__c); + System.assertEquals(Database.MergeResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } - // TODO only some standard objects can be merged - need to find a way to either mock or trigger a merge result that works in all orgs - // @IsTest - // static void it_should_set_database_result_fields_for_list_of_failed_mergeResult() { - // Database.MergeResult mergeResult = Database.merge(new Account(Name='Expcted'), new Account(Name='Failure'), false); - // System.assertEquals(false, mergeResult.isSuccess()); - - // LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - - // Test.startTest(); - // builder.setDatabaseResult(mergeResult); - // Test.stopTest(); - - // LogEntryEvent__e logEntryEvent = builder.getLogEntryEvent(); - - // System.assertEquals(JSON.serializePretty(mergeResult), logEntryEvent.DatabaseResultJson__c); - // System.assertEquals(Database.MergeResult.class.getName(), logEntryEvent.DatabaseResultType__c); - // } - @IsTest - static void it_should_set_database_result_fields_for_list_of_successful_saveResult() { - List logs = new List(); + static void it_should_set_database_result_fields_for_list_of_saveResult() { + List saveResults = new List(); for (Integer i = 0; i < 5; i++) { - Log__c log = new Log__c(TransactionId__c = '1234' + i); - logs.add(log); - } - List saveResults = Database.insert(logs, false); - for (Database.SaveResult saveResult : saveResults) { - System.assertEquals(true, saveResult.isSuccess()); + saveResults.add(LoggerMockDataCreator.createDatabaseSaveResult(false)); } LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); builder.setDatabaseResult(saveResults); + System.assertEquals(saveResults.size(), builder.getLogEntryEvent().DatabaseResultCollectionSize__c); System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); System.assertEquals(JSON.serializePretty(saveResults), builder.getLogEntryEvent().DatabaseResultJson__c); System.assertEquals(Database.SaveResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest - static void it_should_set_database_result_fields_for_list_of_failed_saveResult() { - List accounts = new List(); + static void it_should_set_database_result_fields_for_list_of_undeleteResult() { + List undeleteResults = new List(); for (Integer i = 0; i < 5; i++) { - Account account = new Account(); - accounts.add(account); - } - List saveResults = Database.insert(accounts, false); - for (Database.SaveResult saveResult : saveResults) { - System.assertEquals(false, saveResult.isSuccess()); - } - - LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - builder.setDatabaseResult(saveResults); - - System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(saveResults), builder.getLogEntryEvent().DatabaseResultJson__c); - System.assertEquals(Database.SaveResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); - } - - @IsTest - static void it_should_set_database_result_fields_for_list_of_successful_undeleteResult() { - List logs = new List(); - for (Integer i = 0; i < 5; i++) { - Log__c log = new Log__c(TransactionId__c = '1234' + i); - logs.add(log); - } - insert logs; - delete logs; - - List undeleteResults = Database.undelete(logs, false); - for (Database.UndeleteResult undeleteResult : undeleteResults) { - System.assertEquals(true, undeleteResult.isSuccess()); + undeleteResults.add(LoggerMockDataCreator.createDatabaseUndeleteResult(false)); } LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); builder.setDatabaseResult(undeleteResults); + System.assertEquals(undeleteResults.size(), builder.getLogEntryEvent().DatabaseResultCollectionSize__c); System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); System.assertEquals(JSON.serializePretty(undeleteResults), builder.getLogEntryEvent().DatabaseResultJson__c); System.assertEquals(Database.UndeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); } @IsTest - static void it_should_set_database_result_fields_for_list_of_failed_undeleteResult() { - List logs = new List(); + static void it_should_set_database_result_fields_for_list_of_upsertResult() { + List upsertResults = new List(); for (Integer i = 0; i < 5; i++) { - Log__c log = new Log__c(TransactionId__c = '1234' + i); - logs.add(log); - } - insert logs; - delete logs; - // Hard delete to (later) cause an undelete error - Database.emptyRecycleBin(logs); - - List undeleteResults = Database.undelete(logs, false); - for (Database.UndeleteResult undeleteResult : undeleteResults) { - System.assertEquals(false, undeleteResult.isSuccess()); - } - - LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - builder.setDatabaseResult(undeleteResults); - - System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(undeleteResults), builder.getLogEntryEvent().DatabaseResultJson__c); - System.assertEquals(Database.UndeleteResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); - } - - @IsTest - static void it_should_set_database_result_fields_for_list_of_successful_upsertResult_when_insert() { - // UpsertResult for a new record insert - List logs = new List(); - for (Integer i = 0; i < 5; i++) { - Log__c log = new Log__c(TransactionId__c = '1234' + i); - logs.add(log); - } - List upsertResults = Database.upsert(logs, false); - for (Database.UpsertResult upsertResult : upsertResults) { - System.assertEquals(true, upsertResult.isSuccess()); - } - - LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); - builder.setDatabaseResult(upsertResults); - - System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); - System.assertEquals(JSON.serializePretty(upsertResults), builder.getLogEntryEvent().DatabaseResultJson__c); - System.assertEquals(Database.UpsertResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); - } - - @IsTest - static void it_should_set_database_result_fields_for_list_of_failed_upsertResult_when_insert() { - // UpsertResult for a new record insert - List accounts = new List(); - for (Integer i = 0; i < 5; i++) { - Account account = new Account(); - accounts.add(account); - } - List upsertResults = Database.upsert(accounts, false); - for (Database.UpsertResult upsertResult : upsertResults) { - System.assertEquals(false, upsertResult.isSuccess()); + upsertResults.add(LoggerMockDataCreator.createDatabaseUpsertResult(false, false)); } LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); builder.setDatabaseResult(upsertResults); + System.assertEquals(upsertResults.size(), builder.getLogEntryEvent().DatabaseResultCollectionSize__c); System.assertEquals('List', builder.getLogEntryEvent().DatabaseResultCollectionType__c); System.assertEquals(JSON.serializePretty(upsertResults), builder.getLogEntryEvent().DatabaseResultJson__c); System.assertEquals(Database.UpsertResult.class.getName(), builder.getLogEntryEvent().DatabaseResultType__c); @@ -685,6 +475,7 @@ private class LogEntryEventBuilder_Tests { Id currentUserId = UserInfo.getUserId(); builder.setRecordId(currentUserId); + System.assertEquals(1, builder.getLogEntryEvent().RecordCollectionSize__c); System.assertEquals('Single', builder.getLogEntryEvent().RecordCollectionType__c); System.assertEquals(currentUserId, builder.getLogEntryEvent().RecordId__c); System.assertEquals(null, builder.getLogEntryEvent().RecordJson__c); @@ -702,12 +493,12 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectType__c); System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectTypeNamespace__c); - Log__c log = new Log__c(TransactionId__c = '1234'); - insert log; - builder.setRecordId(log.Id); + Id mockLogId = LoggerMockDataCreator.createId(Schema.Log__c.SObjectType); + builder.setRecordId(mockLogId); + System.assertEquals(1, builder.getLogEntryEvent().RecordCollectionSize__c); System.assertEquals('Single', builder.getLogEntryEvent().RecordCollectionType__c); - System.assertEquals(log.Id, builder.getLogEntryEvent().RecordId__c); + System.assertEquals(mockLogId, builder.getLogEntryEvent().RecordId__c); System.assertEquals(null, builder.getLogEntryEvent().RecordJson__c); System.assertEquals('Custom Object', builder.getLogEntryEvent().RecordSObjectClassification__c); System.assertEquals(Log__c.SObjectType.getDescribe().getName(), builder.getLogEntryEvent().RecordSObjectType__c); @@ -722,13 +513,10 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectType__c); System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectTypeNamespace__c); - Test.startTest(); - LogStatus__mdt status = [SELECT Id, MasterLabel, DeveloperName FROM LogStatus__mdt LIMIT 1]; builder.setRecordId(status.Id); - Test.stopTest(); - + System.assertEquals(1, builder.getLogEntryEvent().RecordCollectionSize__c); System.assertEquals('Single', builder.getLogEntryEvent().RecordCollectionType__c); System.assertEquals(status.Id, builder.getLogEntryEvent().RecordId__c); System.assertEquals(null, builder.getLogEntryEvent().RecordJson__c); @@ -745,14 +533,11 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectType__c); System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectTypeNamespace__c); - Test.startTest(); - User nullUser; System.assertEquals(null, nullUser); builder.setRecordId(nullUser); - Test.stopTest(); - + System.assertEquals(1, builder.getLogEntryEvent().RecordCollectionSize__c); System.assertEquals('Single', builder.getLogEntryEvent().RecordCollectionType__c); System.assertEquals(null, builder.getLogEntryEvent().RecordId__c); System.assertEquals('null', builder.getLogEntryEvent().RecordJson__c); @@ -770,13 +555,10 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectType__c); System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectTypeNamespace__c); - Test.startTest(); - User currentUser = [SELECT Id, Name, ProfileId, Profile.Name, IsActive FROM User WHERE Id = :UserInfo.getUserId()]; builder.setRecordId(currentUser); - Test.stopTest(); - + System.assertEquals(1, builder.getLogEntryEvent().RecordCollectionSize__c); System.assertEquals('Single', builder.getLogEntryEvent().RecordCollectionType__c); System.assertEquals(currentUser.Id, builder.getLogEntryEvent().RecordId__c); System.assertEquals(JSON.serializePretty(currentUser), builder.getLogEntryEvent().RecordJson__c); @@ -794,14 +576,10 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectType__c); System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectTypeNamespace__c); - Test.startTest(); - - Log__c log = new Log__c(TransactionId__c = '1234'); - insert log; + Log__c log = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); builder.setRecordId(log); - Test.stopTest(); - + System.assertEquals(1, builder.getLogEntryEvent().RecordCollectionSize__c); System.assertEquals('Single', builder.getLogEntryEvent().RecordCollectionType__c); System.assertEquals(log.Id, builder.getLogEntryEvent().RecordId__c); System.assertEquals(JSON.serializePretty(log), builder.getLogEntryEvent().RecordJson__c); @@ -818,13 +596,11 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectType__c); System.assertEquals(null, builder.getLogEntryEvent().RecordSObjectTypeNamespace__c); - Test.startTest(); - LogStatus__mdt status = [SELECT Id, MasterLabel, DeveloperName FROM LogStatus__mdt LIMIT 1]; builder.setRecordId(status); - Test.stopTest(); - + System.assertEquals(1, builder.getLogEntryEvent().RecordCollectionSize__c); + System.assertEquals('Single', builder.getLogEntryEvent().RecordCollectionType__c); System.assertEquals(status.Id, builder.getLogEntryEvent().RecordId__c); System.assertEquals(JSON.serializePretty(status), builder.getLogEntryEvent().RecordJson__c); System.assertEquals('Custom Metadata Type Object', builder.getLogEntryEvent().RecordSObjectClassification__c); @@ -833,8 +609,8 @@ private class LogEntryEventBuilder_Tests { @IsTest static void it_should_skip_stripping_inaccessible_fields_for_aggregate_result() { - User standardUser = LoggerTestUtils.createUser(); - AggregateResult mockAggregateResult = LoggerTestUtils.createMockAggregateResult(); + User standardUser = LoggerMockDataCreator.createUser(); + AggregateResult mockAggregateResult = LoggerMockDataCreator.createAggregateResult(); LogEntryEventBuilder builder; System.runAs(standardUser) { @@ -847,8 +623,8 @@ private class LogEntryEventBuilder_Tests { @IsTest static void it_should_skip_stripping_inaccessible_fields_for_aggregate_results() { - User standardUser = LoggerTestUtils.createUser(); - List mockAggregateResults = new List{ LoggerTestUtils.createMockAggregateResult() }; + User standardUser = LoggerMockDataCreator.createUser(); + List mockAggregateResults = new List{ LoggerMockDataCreator.createAggregateResult() }; LogEntryEventBuilder builder; System.runAs(standardUser) { @@ -940,6 +716,80 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(User.SObjectType.getDescribe().getName(), builder.getLogEntryEvent().RecordSObjectType__c); } + @IsTest + static void it_should_skip_setting_http_request_fields_when_request_is_null() { + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); + System.assertEquals(null, builder.getLogEntryEvent().HttpRequestBody__c); + System.assertEquals(false, builder.getLogEntryEvent().HttpRequestCompressed__c); + System.assertEquals(null, builder.getLogEntryEvent().HttpRequestEndpoint__c); + System.assertEquals(null, builder.getLogEntryEvent().HttpRequestMethod__c); + HttpRequest request = null; + + builder.setHttpRequestDetails(request); + + System.assertEquals(null, builder.getLogEntryEvent().HttpRequestBody__c); + System.assertEquals(false, builder.getLogEntryEvent().HttpRequestCompressed__c); + System.assertEquals(null, builder.getLogEntryEvent().HttpRequestEndpoint__c); + System.assertEquals(null, builder.getLogEntryEvent().HttpRequestMethod__c); + } + + @IsTest + static void it_should_set_http_request_fields_when_request_is_populated() { + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); + System.assertEquals(null, builder.getLogEntryEvent().HttpRequestBody__c); + System.assertEquals(null, builder.getLogEntryEvent().HttpRequestEndpoint__c); + System.assertEquals(null, builder.getLogEntryEvent().HttpRequestMethod__c); + HttpRequest request = new HttpRequest(); + request.setBody('Hello, world!'); + request.setCompressed(true); + request.setEndpoint('https://fake.salesforce.com'); + request.setMethod('GET'); + + builder.setHttpRequestDetails(request); + + System.assertEquals(request.getBody(), builder.getLogEntryEvent().HttpRequestBody__c); + System.assertEquals(request.getCompressed(), builder.getLogEntryEvent().HttpRequestCompressed__c); + System.assertEquals(request.getEndpoint(), builder.getLogEntryEvent().HttpRequestEndpoint__c); + System.assertEquals(request.getMethod(), builder.getLogEntryEvent().HttpRequestMethod__c); + } + + @IsTest + static void it_should_skip_setting_http_response_fields_when_response_is_null() { + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); + System.assertEquals(null, builder.getLogEntryEvent().HttpRequestBody__c); + System.assertEquals(null, builder.getLogEntryEvent().HttpRequestEndpoint__c); + System.assertEquals(null, builder.getLogEntryEvent().HttpRequestMethod__c); + HttpResponse response = null; + + builder.setHttpResponseDetails(response); + + System.assertEquals(null, builder.getLogEntryEvent().HttpResponseBody__c); + System.assertEquals(null, builder.getLogEntryEvent().HttpResponseHeaderKeys__c); + System.assertEquals(null, builder.getLogEntryEvent().HttpResponseStatus__c); + System.assertEquals(null, builder.getLogEntryEvent().HttpResponseStatusCode__c); + } + + @IsTest + static void it_should_set_http_response_fields_when_populated() { + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); + System.assertEquals(null, builder.getLogEntryEvent().HttpRequestBody__c); + System.assertEquals(null, builder.getLogEntryEvent().HttpRequestEndpoint__c); + System.assertEquals(null, builder.getLogEntryEvent().HttpRequestMethod__c); + HttpResponse response = new HttpResponse(); + response.setBody('Hello, world!'); + response.setHeader('someKey', 'some string value'); + response.setHeader('anotherKey', 'an amazing example value, wow'); + response.setStatus('STATUS_GOOD_JOB_YOU_DID_IT'); + response.setStatusCode(201); + + builder.setHttpResponseDetails(response); + + System.assertEquals(response.getBody(), builder.getLogEntryEvent().HttpResponseBody__c); + System.assertEquals(String.join(response.getHeaderKeys(), '\n'), builder.getLogEntryEvent().HttpResponseHeaderKeys__c); + System.assertEquals(response.getStatus(), builder.getLogEntryEvent().HttpResponseStatus__c); + System.assertEquals(response.getStatusCode(), builder.getLogEntryEvent().HttpResponseStatusCode__c); + } + @IsTest static void it_should_set_tags_string_for_list_of_tags() { LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); @@ -948,19 +798,20 @@ private class LogEntryEventBuilder_Tests { List tags = new List{ 'some-tag', 'another One', 'here\'s one more!' }; builder.addTags(tags); + tags.sort(); String expectedTagsString = String.escapeSingleQuotes(String.join(tags, '\n')); System.assertEquals(expectedTagsString, builder.getLogEntryEvent().Tags__c); } @IsTest - static void it_should_deduplicate_tags() { + static void it_should_deduplicate_and_sort_tags() { LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); System.assertEquals(null, builder.getLogEntryEvent().Tags__c); List tags = new List{ 'duplicate-tag', 'duplicate-tag', 'another One' }; builder.addTags(tags); - String expectedTagsString = 'duplicate-tag\nanother One'; + String expectedTagsString = 'another One\nduplicate-tag'; System.assertEquals(expectedTagsString, builder.getLogEntryEvent().Tags__c); } @@ -998,6 +849,23 @@ private class LogEntryEventBuilder_Tests { System.assertEquals(anonymousApexStackTraceString, builder.getLogEntryEvent().StackTrace__c); } + @IsTest + static void it_should_deduplicate_sequential_lines_when_setting_stack_trace() { + String anonymousApexOriginLocation = 'AnonymousBlock'; + String deduplicatedStackTraceString = 'AnonymousBlock: line 9, column 1'; + String duplicatedStackTraceString = deduplicatedStackTraceString + '\n' + deduplicatedStackTraceString + '\n' + deduplicatedStackTraceString; + + LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.FINE, true); + builder.getLogEntryEvent().OriginLocation__c = null; + builder.getLogEntryEvent().StackTrace__c = null; + builder.parseStackTrace(duplicatedStackTraceString); + + System.assertNotEquals(null, builder.getLogEntryEvent().OriginLocation__c); + System.assertEquals(anonymousApexOriginLocation, builder.getLogEntryEvent().OriginLocation__c); + System.assertNotEquals(null, builder.getLogEntryEvent().StackTrace__c); + System.assertEquals(deduplicatedStackTraceString, builder.getLogEntryEvent().StackTrace__c); + } + @IsTest static void it_should_not_set_stack_trace_and_origin_location_for_invalid_stack_trace_string() { final String invalidStackTrace = '()'; @@ -1027,9 +895,9 @@ private class LogEntryEventBuilder_Tests { @IsTest static void it_should_set_detailed_fields() { // Get expected data - Organization organization = LoggerTestUtils.getOrganization(); - String organizationEnvironmentType = LoggerTestUtils.getOrganizationEnvironmentType(); - User user = LoggerTestUtils.getCurrentUser(); + Organization organization = LoggerMockDataCreator.getOrganization(); + String organizationEnvironmentType = LoggerMockDataCreator.getOrganizationEnvironmentType(); + User user = LoggerMockDataCreator.getUser(); LogEntryEventBuilder builder = new LogEntryEventBuilder(LoggingLevel.INFO, true); @@ -1054,7 +922,7 @@ private class LogEntryEventBuilder_Tests { @IsTest static void it_should_use_configured_log_entry_event_fields_for_debug_string() { - LoggerParameter.setMockParameter( + LoggerParameter.setMock( new LoggerParameter__mdt(DeveloperName = 'SystemDebugMessageFormat', Value__c = '{OriginLocation__c}\n{Message__c}: {LoggingLevel__c}') ); @@ -1072,6 +940,23 @@ private class LogEntryEventBuilder_Tests { ); } + static String getMessage() { + return 'Hello, world'; + } + + static LogMessage getLogMessage() { + return new LogMessage('The current date is {0}', System.today()); + } + + static LogEntryDataMaskRule__mdt getSocialSecurityNumberDataMaskRule() { + return new LogEntryDataMaskRule__mdt( + DeveloperName = 'SocialSecurityNumber', + IsEnabled__c = true, + SensitiveDataRegEx__c = '(\\d{3})[- ]*(\\d{2})[- ]*(\\d{4})', + ReplacementRegEx__c = 'XXX-XX-$3' + ); + } + private class DebugStringExample { public final String loggingString = 'Inside DebugStringExample.myMethod !'; public LogEntryEventBuilder myMethod() { diff --git a/nebula-logger/core/tests/logger-engine/classes/LogMessage_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/LogMessage_Tests.cls index a7454f265..bf77ee293 100644 --- a/nebula-logger/core/tests/logger-engine/classes/LogMessage_Tests.cls +++ b/nebula-logger/core/tests/logger-engine/classes/LogMessage_Tests.cls @@ -4,12 +4,13 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class LogMessage_Tests { - public class CustomLogMessage extends LogMessage { + private static final String CUSTOM_MESSAGE_PREFIX = 'Just confirming that CustomLogMessage class is used'; + private class CustomLogMessage extends LogMessage { private String inputString; public CustomLogMessage(String inputString) { - this.inputString = inputString; + this.inputString = CUSTOM_MESSAGE_PREFIX + inputString; } public override String getMessage() { return inputString; @@ -18,14 +19,10 @@ private class LogMessage_Tests { @IsTest static void it_should_support_extending_LogMessage_class() { - String expectedMessage = 'The current time is: ' + System.now(); + String originalMessage = CUSTOM_MESSAGE_PREFIX + 'The current time is: ' + System.now(); + String expectedMessage = CUSTOM_MESSAGE_PREFIX + originalMessage; - Test.startTest(); - - CustomLogMessage customLogMessage = new CustomLogMessage(expectedMessage); - String returnedMessage = customLogMessage.getMessage(); - - Test.stopTest(); + String returnedMessage = new CustomLogMessage(originalMessage).getMessage(); System.assertEquals(expectedMessage, returnedMessage); } @@ -36,9 +33,7 @@ private class LogMessage_Tests { List arguments = new List{ System.now() }; String expectedMessage = String.format(unformattedMessage, arguments); - Test.startTest(); String returnedMessage = new LogMessage(unformattedMessage, arguments).getMessage(); - Test.stopTest(); System.assertEquals(expectedMessage, returnedMessage); } @@ -49,9 +44,7 @@ private class LogMessage_Tests { Datetime argument1 = System.now(); String expectedMessage = String.format(unformattedMessage, new List{ argument1 }); - Test.startTest(); String returnedMessage = new LogMessage(unformattedMessage, argument1).getMessage(); - Test.stopTest(); System.assertEquals(expectedMessage, returnedMessage); } @@ -63,9 +56,7 @@ private class LogMessage_Tests { Date argument2 = System.today(); String expectedMessage = String.format(unformattedMessage, new List{ argument1, argument2 }); - Test.startTest(); String returnedMessage = new LogMessage(unformattedMessage, argument1, argument2).getMessage(); - Test.stopTest(); System.assertEquals(expectedMessage, returnedMessage); } @@ -78,9 +69,7 @@ private class LogMessage_Tests { User argument3 = new User(Id = UserInfo.getUserId()); String expectedMessage = String.format(unformattedMessage, new List{ argument1, argument2, argument3 }); - Test.startTest(); String returnedMessage = new LogMessage(unformattedMessage, argument1, argument2, argument3).getMessage(); - Test.stopTest(); System.assertEquals(expectedMessage, returnedMessage); } diff --git a/nebula-logger/core/tests/logger-engine/classes/LoggerDataStore_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/LoggerDataStore_Tests.cls new file mode 100644 index 000000000..be2a9f514 --- /dev/null +++ b/nebula-logger/core/tests/logger-engine/classes/LoggerDataStore_Tests.cls @@ -0,0 +1,608 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +// TODO switch to using standard object(s) available in all orgs (instead of Log__c) so this can be split off as a separate repo +// Possible objects to use: User, Group (Queue) and QueueSObject (none support undelete though), and not sure if it's possible +// to test platform events/EventBus using only standard objects +@SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions') +@IsTest(IsParallel=true) +private class LoggerDataStore_Tests { + // Database DML tests + @IsTest + static void it_should_delete_record() { + Log__c log = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); + insert log; + System.assertEquals(1, Limits.getDmlStatements()); + System.assertEquals(1, Limits.getDmlRows()); + + Database.DeleteResult result = LoggerDataStore.getDatabase().deleteRecord(log); + + System.assertEquals(2, Limits.getDmlStatements()); + System.assertEquals(2, Limits.getDmlRows()); + System.assertEquals(true, result.isSuccess()); + Log__c persistedLog = [SELECT Id, IsDeleted FROM Log__c WHERE Id = :log.Id ALL ROWS]; + System.assertEquals(true, persistedLog.IsDeleted); + } + + @IsTest + static void it_should_delete_record_list() { + List logsToDelete = new List(); + logsToDelete.add((Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord()); + logsToDelete.add((Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord()); + insert logsToDelete; + System.assertEquals(1, Limits.getDmlStatements()); + System.assertEquals(2, Limits.getDmlRows()); + + List results = LoggerDataStore.getDatabase().deleteRecords(logsToDelete); + + System.assertEquals(2, Limits.getDmlStatements()); + System.assertEquals(4, Limits.getDmlRows()); + System.assertEquals(logsToDelete.size(), results.size()); + for (Database.DeleteResult result : results) { + System.assertEquals(true, result.isSuccess()); + } + List persistedLogs = [SELECT Id, IsDeleted FROM Log__c WHERE Id IN :logsToDelete ALL ROWS]; + System.assertEquals(logsToDelete.size(), persistedLogs.size()); + for (Log__c persistedLog : persistedLogs) { + System.assertEquals(true, persistedLog.IsDeleted); + } + } + + @IsTest + static void it_should_partially_delete_record_list_when_allOrNone_is_false() { + List logsToDelete = new List(); + logsToDelete.add((Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord()); + logsToDelete.add((Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord()); + insert logsToDelete; + // Delete one of the logs first to cause a failure in the delete DML statement + delete logsToDelete.get(0); + System.assertEquals(2, Limits.getDmlStatements()); + System.assertEquals(3, Limits.getDmlRows()); + + List results = LoggerDataStore.getDatabase().deleteRecords(logsToDelete, false); + + System.assertEquals(3, Limits.getDmlStatements()); + System.assertEquals(5, Limits.getDmlRows()); + System.assertEquals(logsToDelete.size(), results.size()); + System.assertEquals(false, results.get(0).isSuccess()); + System.assertEquals(true, results.get(1).isSuccess()); + List persistedLogs = [SELECT Id, IsDeleted FROM Log__c WHERE Id IN :logsToDelete ALL ROWS]; + System.assertEquals(logsToDelete.size(), persistedLogs.size()); + for (Log__c persistedLog : persistedLogs) { + System.assertEquals(true, persistedLog.IsDeleted); + } + } + + @IsTest + static void it_should_hard_delete_record() { + Log__c log = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); + log.TransactionId__c = '999'; + insert log; + System.assertEquals(1, Limits.getDmlStatements()); + System.assertEquals(1, Limits.getDmlRows()); + + Database.DeleteResult result = LoggerDataStore.getDatabase().hardDeleteRecord(log); + + System.assertEquals(3, Limits.getDmlStatements()); + System.assertEquals(3, Limits.getDmlRows()); + System.assertEquals(true, result.isSuccess()); + // Frustratingly, there's not a way to ensure that Database.emptyRecycleBin() was called and + // the supposedly-hard-deleted records are still returned in SOQL, so at least verify that the + // record has IsDeleted = true for now. This can probably be tested better with a @TestVisible property later. + Log__c persistedLog = [SELECT Id, IsDeleted FROM Log__c WHERE Id = :log.Id ALL ROWS]; + System.assertEquals(true, persistedLog.IsDeleted); + } + + @IsTest + static void it_should_hard_delete_record_list() { + List logsToDelete = new List(); + logsToDelete.add((Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord()); + logsToDelete.add((Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord()); + insert logsToDelete; + System.assertEquals(1, Limits.getDmlStatements()); + System.assertEquals(2, Limits.getDmlRows()); + + List results = LoggerDataStore.getDatabase().hardDeleteRecords(logsToDelete); + + System.assertEquals(3, Limits.getDmlStatements()); + System.assertEquals(6, Limits.getDmlRows()); + System.assertEquals(logsToDelete.size(), results.size()); + for (Database.DeleteResult result : results) { + System.assertEquals(true, result.isSuccess()); + } + // Frustratingly, there's not a way to ensure that Database.emptyRecycleBin() was called and + // the supposedly-hard-deleted records are still returned in SOQL, so at least verify that the + // record has IsDeleted = true for now. This can probably be tested better with a @TestVisible property later. + List persistedLogs = [SELECT Id, IsDeleted FROM Log__c WHERE Id IN :logsToDelete ALL ROWS]; + System.assertEquals(logsToDelete.size(), persistedLogs.size()); + for (Log__c persistedLog : persistedLogs) { + System.assertEquals(true, persistedLog.IsDeleted); + } + } + + @IsTest + static void it_should_insert_record() { + Log__c log = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); + log.TransactionId__c = '1234'; + System.assertEquals(0, Limits.getDmlStatements()); + System.assertEquals(0, Limits.getDmlRows()); + + Database.SaveResult result = LoggerDataStore.getDatabase().insertRecord(log); + + System.assertEquals(1, Limits.getDmlStatements()); + System.assertEquals(1, Limits.getDmlRows()); + System.assertNotEquals(null, log.Id); + System.assertEquals(true, result.isSuccess()); + Log__c persistedLog = [SELECT Id, TransactionId__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(log.TransactionId__c, persistedLog.TransactionId__c); + } + + @IsTest + static void it_should_insert_record_list() { + List logsToInsert = new List(); + logsToInsert.add((Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord()); + logsToInsert.add((Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord()); + System.assertEquals(0, Limits.getDmlStatements()); + System.assertEquals(0, Limits.getDmlRows()); + + List results = LoggerDataStore.getDatabase().insertRecords(logsToInsert); + + System.assertEquals(1, Limits.getDmlStatements()); + System.assertEquals(2, Limits.getDmlRows()); + System.assertEquals(logsToInsert.size(), results.size()); + for (Database.SaveResult result : results) { + System.assertEquals(true, result.isSuccess()); + } + List persistedLogs = [SELECT Id, TransactionId__c FROM Log__c WHERE Id IN :logsToInsert]; + System.assertEquals(logsToInsert.size(), persistedLogs.size()); + } + + @IsTest + static void it_should_partially_insert_record_list_when_allOrNone_is_false() { + Log__c existingRecord = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); + insert existingRecord; + List logsToInsert = new List(); + logsToInsert.add((Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord()); + logsToInsert.add(existingRecord); + System.assertEquals(1, Limits.getDmlStatements()); + System.assertEquals(1, Limits.getDmlRows()); + + List results = LoggerDataStore.getDatabase().insertRecords(logsToInsert, false); + + System.assertEquals(2, Limits.getDmlStatements()); + System.assertEquals(3, Limits.getDmlRows()); + System.assertEquals(logsToInsert.size(), results.size()); + System.assertEquals(true, results.get(0).isSuccess()); + System.assertEquals(false, results.get(1).isSuccess()); + List persistedLogs = [SELECT Id, TransactionId__c FROM Log__c WHERE Id IN :logsToInsert]; + System.assertEquals(2, persistedLogs.size()); + } + + @IsTest + static void it_should_partially_insert_record_list_when_allOrNone_is_false_in_dml_options() { + Log__c existingRecord = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); + insert existingRecord; + List logsToInsert = new List(); + logsToInsert.add((Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord()); + logsToInsert.add(existingRecord); + Database.DmlOptions dmlOptions = new Database.DmlOptions(); + dmlOptions.OptAllOrNone = false; + System.assertEquals(1, Limits.getDmlStatements()); + System.assertEquals(1, Limits.getDmlRows()); + + List results = LoggerDataStore.getDatabase().insertRecords(logsToInsert, dmlOptions); + + System.assertEquals(2, Limits.getDmlStatements()); + System.assertEquals(3, Limits.getDmlRows()); + System.assertEquals(logsToInsert.size(), results.size()); + System.assertEquals(true, results.get(0).isSuccess()); + System.assertEquals(false, results.get(1).isSuccess()); + List persistedLogs = [SELECT Id, TransactionId__c FROM Log__c WHERE Id IN :logsToInsert]; + System.assertEquals(2, persistedLogs.size()); + } + + @IsTest + static void it_should_undelete_record() { + Log__c log = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); + insert log; + delete log; + log = [SELECT Id, IsDeleted FROM Log__c WHERE Id = :log.Id ALL ROWS]; + System.assertEquals(true, log.IsDeleted); + System.assertEquals(2, Limits.getDmlStatements()); + System.assertEquals(2, Limits.getDmlRows()); + + Database.UndeleteResult result = LoggerDataStore.getDatabase().undeleteRecord(log); + + System.assertEquals(3, Limits.getDmlStatements()); + System.assertEquals(3, Limits.getDmlRows()); + System.assertEquals(true, result.isSuccess()); + Log__c persistedLog = [SELECT Id, IsDeleted FROM Log__c WHERE Id = :log.Id ALL ROWS]; + System.assertEquals(false, persistedLog.IsDeleted); + } + + @IsTest + static void it_should_undelete_records() { + List logsToUndelete = new List(); + logsToUndelete.add((Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord()); + logsToUndelete.add((Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord()); + insert logsToUndelete; + delete logsToUndelete; + logsToUndelete = [SELECT Id, IsDeleted FROM Log__c WHERE Id IN :logsToUndelete ALL ROWS]; + for (Log__c deletedLog : logsToUndelete) { + System.assertEquals(true, deletedLog.IsDeleted); + } + System.assertEquals(2, Limits.getDmlStatements()); + System.assertEquals(4, Limits.getDmlRows()); + + List results = LoggerDataStore.getDatabase().undeleteRecords(logsToUndelete); + + System.assertEquals(3, Limits.getDmlStatements()); + System.assertEquals(6, Limits.getDmlRows()); + System.assertEquals(logsToUndelete.size(), results.size()); + for (Database.UndeleteResult result : results) { + System.assertEquals(true, result.isSuccess()); + } + List persistedLogs = [SELECT Id, IsDeleted FROM Log__c WHERE Id IN :logsToUndelete ALL ROWS]; + System.assertEquals(logsToUndelete.size(), persistedLogs.size()); + for (Log__c persistedLog : persistedLogs) { + System.assertEquals(false, persistedLog.IsDeleted); + } + } + + @IsTest + static void it_should_partially_undelete_records_when_allOrNone_is_false() { + List logsToUndelete = new List(); + logsToUndelete.add((Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord()); + logsToUndelete.add((Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord()); + insert logsToUndelete; + delete logsToUndelete.get(0); + logsToUndelete = [SELECT Id, IsDeleted FROM Log__c WHERE Id IN :logsToUndelete ALL ROWS]; + System.assertEquals(true, logsToUndelete.get(0).IsDeleted); + System.assertEquals(false, logsToUndelete.get(1).IsDeleted); + System.assertEquals(2, Limits.getDmlStatements()); + System.assertEquals(3, Limits.getDmlRows()); + + List results = LoggerDataStore.getDatabase().undeleteRecords(logsToUndelete, false); + + System.assertEquals(3, Limits.getDmlStatements()); + System.assertEquals(5, Limits.getDmlRows()); + System.assertEquals(logsToUndelete.size(), results.size()); + System.assertEquals(true, results.get(0).isSuccess()); + System.assertEquals(false, results.get(1).isSuccess()); + List persistedLogs = [SELECT Id, IsDeleted FROM Log__c WHERE Id IN :logsToUndelete ALL ROWS]; + System.assertEquals(logsToUndelete.size(), persistedLogs.size()); + for (Log__c persistedLog : persistedLogs) { + System.assertEquals(false, persistedLog.IsDeleted); + } + } + + @IsTest + static void it_should_update_record() { + String originalScenario = 'Some scenario'; + String updatedScenario = 'Another, different scenario'; + List logsToUpdate = new List(); + logsToUpdate.add((Log__c) LoggerMockDataCreator.createDataBuilder(new Log__c(Scenario__c = originalScenario)).populateRequiredFields().getRecord()); + logsToUpdate.add((Log__c) LoggerMockDataCreator.createDataBuilder(new Log__c(Scenario__c = originalScenario)).populateRequiredFields().getRecord()); + insert logsToUpdate; + logsToUpdate = [SELECT Id, Scenario__c FROM Log__c WHERE Id IN :logsToUpdate]; + for (Log__c logToUpdate : logsToUpdate) { + System.assertEquals(originalScenario, logToUpdate.Scenario__c); + logToUpdate.Scenario__c = updatedScenario; + } + System.assertEquals(1, Limits.getDmlStatements()); + System.assertEquals(2, Limits.getDmlRows()); + + List results = LoggerDataStore.getDatabase().updateRecords(logsToUpdate); + + System.assertEquals(2, Limits.getDmlStatements()); + System.assertEquals(4, Limits.getDmlRows()); + System.assertEquals(logsToUpdate.size(), results.size()); + for (Database.SaveResult result : results) { + System.assertEquals(true, result.isSuccess()); + } + List persistedLogs = [SELECT Id, Scenario__c FROM Log__c WHERE Id IN :logsToUpdate ALL ROWS]; + System.assertEquals(logsToUpdate.size(), persistedLogs.size()); + for (Log__c persistedLog : persistedLogs) { + System.assertEquals(updatedScenario, persistedLog.Scenario__c); + } + } + + @IsTest + static void it_should_update_record_list() { + String originalScenario = 'Some scenario'; + String updatedScenario = 'Another, different scenario'; + Log__c log = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); + log.Scenario__c = originalScenario; + insert log; + log = [SELECT Id, Scenario__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(originalScenario, log.Scenario__c); + log.Scenario__c = updatedScenario; + System.assertEquals(1, Limits.getDmlStatements()); + System.assertEquals(1, Limits.getDmlRows()); + + Database.SaveResult result = LoggerDataStore.getDatabase().updateRecord(log); + + System.assertEquals(2, Limits.getDmlStatements()); + System.assertEquals(2, Limits.getDmlRows()); + System.assertEquals(true, result.isSuccess()); + Log__c persistedLog = [SELECT Id, Scenario__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(updatedScenario, persistedLog.Scenario__c); + } + + @IsTest + static void it_should_partially_update_record_list_when_allOrNone_is_false() { + String originalScenario = 'Some scenario'; + String updatedScenario = 'Another, different scenario'; + List logsToUpdate = new List(); + logsToUpdate.add((Log__c) LoggerMockDataCreator.createDataBuilder(new Log__c(Scenario__c = originalScenario)).populateRequiredFields().getRecord()); + insert logsToUpdate; + logsToUpdate.add((Log__c) LoggerMockDataCreator.createDataBuilder(new Log__c(Scenario__c = originalScenario)).populateRequiredFields().getRecord()); + for (Log__c log : logsToUpdate) { + log.Scenario__c = updatedScenario; + } + System.assertEquals(1, Limits.getDmlStatements()); + System.assertEquals(1, Limits.getDmlRows()); + + List results = LoggerDataStore.getDatabase().updateRecords(logsToUpdate, false); + + System.assertEquals(2, Limits.getDmlStatements()); + System.assertEquals(3, Limits.getDmlRows()); + System.assertEquals(logsToUpdate.size(), results.size()); + System.assertEquals(true, results.get(0).isSuccess()); + System.assertEquals(false, results.get(1).isSuccess()); + List persistedLogs = [SELECT Id, Scenario__c FROM Log__c WHERE Id IN :logsToUpdate]; + System.assertEquals(1, persistedLogs.size()); + System.assertEquals(updatedScenario, persistedLogs.get(0).Scenario__c); + } + + @IsTest + static void it_should_partially_update_record_list_when_allOrNone_is_false_in_dml_options() { + String originalScenario = 'Some scenario'; + String updatedScenario = 'Another, different scenario'; + List logsToUpdate = new List(); + logsToUpdate.add((Log__c) LoggerMockDataCreator.createDataBuilder(new Log__c(Scenario__c = originalScenario)).populateRequiredFields().getRecord()); + insert logsToUpdate; + logsToUpdate.add((Log__c) LoggerMockDataCreator.createDataBuilder(new Log__c(Scenario__c = originalScenario)).populateRequiredFields().getRecord()); + for (Log__c log : logsToUpdate) { + log.Scenario__c = updatedScenario; + } + Database.DmlOptions dmlOptions = new Database.DmlOptions(); + dmlOptions.OptAllOrNone = false; + System.assertEquals(1, Limits.getDmlStatements()); + System.assertEquals(1, Limits.getDmlRows()); + + List results = LoggerDataStore.getDatabase().updateRecords(logsToUpdate, dmlOptions); + + System.assertEquals(2, Limits.getDmlStatements()); + System.assertEquals(3, Limits.getDmlRows()); + System.assertEquals(logsToUpdate.size(), results.size()); + System.assertEquals(true, results.get(0).isSuccess()); + System.assertEquals(false, results.get(1).isSuccess()); + List persistedLogs = [SELECT Id, Scenario__c FROM Log__c WHERE Id IN :logsToUpdate]; + System.assertEquals(1, persistedLogs.size()); + System.assertEquals(updatedScenario, persistedLogs.get(0).Scenario__c); + } + + @IsTest + static void it_should_upsert_record() { + String originalScenario = 'Some scenario'; + String updatedScenario = 'Another, different scenario'; + Log__c log = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); + log.Scenario__c = originalScenario; + log.TransactionId__c = '1234'; + insert log; + log = [SELECT Id, Scenario__c, TransactionId__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(originalScenario, log.Scenario__c); + log.Scenario__c = updatedScenario; + Id originalLogId = log.Id; + log.Id = null; + System.assertEquals(null, log.Id); + System.assertNotEquals(null, log.TransactionId__c); + System.assertEquals(1, Limits.getDmlStatements()); + System.assertEquals(1, Limits.getDmlRows()); + + Database.UpsertResult result = LoggerDataStore.getDatabase().upsertRecord(log, Schema.Log__c.TransactionId__c); + + System.assertEquals(2, Limits.getDmlStatements()); + System.assertEquals(2, Limits.getDmlRows()); + System.assertEquals(false, result.isCreated()); + System.assertEquals(true, result.isSuccess()); + Log__c persistedLog = [SELECT Id, Scenario__c, TransactionId__c FROM Log__c WHERE TransactionId__c = :log.TransactionId__c]; + System.assertEquals(originalLogId, persistedLog.Id); + System.assertEquals(updatedScenario, persistedLog.Scenario__c); + } + + @IsTest + static void it_should_upsert_record_list() { + String originalScenario = 'Some scenario'; + String updatedScenario = 'Another, different scenario'; + List logsToUpsert = new List(); + logsToUpsert.add( + (Log__c) LoggerMockDataCreator.createDataBuilder(new Log__c(Scenario__c = originalScenario, TransactionId__c = '1234')) + .populateRequiredFields() + .getRecord() + ); + logsToUpsert.add( + (Log__c) LoggerMockDataCreator.createDataBuilder(new Log__c(Scenario__c = originalScenario, TransactionId__c = '5678')) + .populateRequiredFields() + .getRecord() + ); + insert logsToUpsert; + logsToUpsert = [SELECT Id, Scenario__c, TransactionId__c FROM Log__c WHERE Id IN :logsToUpsert]; + for (Log__c logToUpdate : logsToUpsert) { + System.assertEquals(originalScenario, logToUpdate.Scenario__c); + logToUpdate.Scenario__c = updatedScenario; + } + System.assertEquals(1, Limits.getDmlStatements()); + System.assertEquals(2, Limits.getDmlRows()); + + List results = LoggerDataStore.getDatabase().upsertRecords(logsToUpsert, Schema.Log__c.TransactionId__c); + + System.assertEquals(2, Limits.getDmlStatements()); + System.assertEquals(4, Limits.getDmlRows()); + System.assertEquals(logsToUpsert.size(), results.size()); + for (Database.UpsertResult result : results) { + System.assertEquals(true, result.isSuccess()); + } + List persistedLogs = [SELECT Id, Scenario__c FROM Log__c WHERE Id IN :logsToUpsert]; + System.assertEquals(logsToUpsert.size(), persistedLogs.size()); + for (Log__c persistedLog : persistedLogs) { + System.assertEquals(updatedScenario, persistedLog.Scenario__c); + } + } + + @IsTest + static void it_should_partially_upsert_record_list_when_allOrNone_is_false() { + String originalScenario = 'Some scenario'; + String updatedScenario = 'Another, different scenario'; + List logsToUpsert = new List(); + logsToUpsert.add( + (Log__c) LoggerMockDataCreator.createDataBuilder(new Log__c(Scenario__c = originalScenario, TransactionId__c = '1234')) + .populateRequiredFields() + .getRecord() + ); + logsToUpsert.add( + (Log__c) LoggerMockDataCreator.createDataBuilder(new Log__c(Scenario__c = originalScenario, TransactionId__c = '5678')) + .populateRequiredFields() + .getRecord() + ); + insert logsToUpsert; + logsToUpsert = [SELECT Id, Scenario__c, TransactionId__c FROM Log__c WHERE Id IN :logsToUpsert]; + for (Log__c logToUpdate : logsToUpsert) { + System.assertEquals(originalScenario, logToUpdate.Scenario__c); + logToUpdate.Scenario__c = updatedScenario; + } + logsToUpsert.get(1).TransactionId__c = null; // This will cause an error since the upsert is on TransactionId__c + System.assertEquals(1, Limits.getDmlStatements()); + System.assertEquals(2, Limits.getDmlRows()); + + List results = LoggerDataStore.getDatabase().upsertRecords(logsToUpsert, Schema.Log__c.TransactionId__c, false); + + System.assertEquals(2, Limits.getDmlStatements()); + System.assertEquals(4, Limits.getDmlRows()); + System.assertEquals(logsToUpsert.size(), results.size()); + System.assertEquals(true, results.get(0).isSuccess()); + System.assertEquals(false, results.get(1).isSuccess()); + List persistedLogs = [SELECT Id, Scenario__c FROM Log__c WHERE Id IN :logsToUpsert]; + System.assertEquals(2, persistedLogs.size()); + System.assertEquals(updatedScenario, persistedLogs.get(0).Scenario__c); + System.assertEquals(originalScenario, persistedLogs.get(1).Scenario__c); + } + + // Event Bus tests + @IsTest + static void it_should_publish_record() { + LogEntryEvent__e logEntryEvent = (LOgEntryEvent__e) LoggerMockDataCreator.createDataBuilder(Schema.LogEntryEvent__e.SObjectType) + .populateRequiredFields() + .getRecord(); + System.assertEquals(0, Limits.getPublishImmediateDml()); + + Database.SaveResult result = LoggerDataStore.getEventBus().publishRecord(logEntryEvent); + + System.assertEquals(1, Limits.getPublishImmediateDml(), result); + System.assertEquals(true, result.isSuccess()); + } + + @IsTest + static void it_should_publish_record_list() { + List logEntryEventsToPublish = new List(); + logEntryEventsToPublish.add( + (LogEntryEvent__e) LoggerMockDataCreator.createDataBuilder(Schema.LogEntryEvent__e.SObjectType).populateRequiredFields().getRecord() + ); + logEntryEventsToPublish.add( + (LogEntryEvent__e) LoggerMockDataCreator.createDataBuilder(Schema.LogEntryEvent__e.SObjectType).populateRequiredFields().getRecord() + ); + System.assertEquals(0, Limits.getPublishImmediateDml()); + + List results = LoggerDataStore.getEventBus().publishRecords(logEntryEventsToPublish); + + System.assertEquals(1, Limits.getPublishImmediateDml(), results); + System.assertEquals(logEntryEventsToPublish.size(), results.size()); + for (Database.SaveResult result : results) { + System.assertEquals(true, result.isSuccess()); + } + } + + // Queueable tests + @IsTest + static void it_should_enqueue_job() { + System.assertEquals(0, Limits.getQueueableJobs()); + + LoggerDataStore.getJobQueue().enqueueJob(new MockQueueable()); + + System.assertEquals(1, Limits.getQueueableJobs()); + } + + // Mocking tests + @IsTest + static void it_should_support_overriding_database_instance() { + MockDatabase mockDatabaseInstance = new MockDatabase(); + System.assertEquals(0, mockDatabaseInstance.callCount); + LoggerDataStore.setMock(mockDatabaseInstance); + System.assertEquals(mockDatabaseInstance, LoggerDataStore.getDatabase()); + + LoggerDataStore.getDatabase().updateRecord(new User(Id = UserInfo.getUserId())); + + System.assertEquals(1, mockDatabaseInstance.callCount); + } + + @IsTest + static void it_should_support_overriding_event_bus_instance() { + MockEventBus mockEventBusInstance = new MockEventBus(); + System.assertEquals(0, mockEventBusInstance.callCount); + LoggerDataStore.setMock(mockEventBusInstance); + System.assertEquals(mockEventBusInstance, LoggerDataStore.getEventBus()); + + LoggerDataStore.getEventBus().publishRecord(new User()); // Not an actual platform event, but for mocking/test purposes, User is fine + + System.assertEquals(1, mockEventBusInstance.callCount); + } + + @IsTest + static void it_should_support_overriding_job_queue_instance() { + MockJobQueue mockJobQueueInstance = new MockJobQueue(); + System.assertEquals(0, mockJobQueueInstance.callCount); + LoggerDataStore.setMock(mockJobQueueInstance); + System.assertEquals(mockJobQueueInstance, LoggerDataStore.getJobQueue()); + + LoggerDataStore.getJobQueue().enqueueJob(new MockQueueable()); + + System.assertEquals(1, mockJobQueueInstance.callCount); + } + + private class MockDatabase extends LoggerDataStore.Database { + public Integer callCount = 0; + + public override Database.SaveResult updateRecord(SObject record) { + this.callCount++; + return LoggerMockDataCreator.createDatabaseSaveResult(true, record.Id); + } + } + + private class MockEventBus extends LoggerDataStore.EventBus { + public Integer callCount = 0; + + public override Database.SaveResult publishRecord(SObject platformEvent) { + this.callCount++; + return LoggerMockDataCreator.createDatabaseSaveResult(true, platformEvent.Id); + } + } + + private class MockJobQueue extends LoggerDataStore.JobQueue { + public Integer callCount = 0; + + public override Id enqueueJob(Queueable queueableJob) { + this.callCount++; + return LoggerMockDataCreator.createId(Schema.AsyncApexJob.SObjectType); + } + } + + private class MockQueueable implements Queueable { + public Integer callCount = 0; + public void execute(System.QueueableContext queueableContext) { + this.callCount++; + } + } +} diff --git a/nebula-logger/core/tests/logger-engine/classes/LoggerDataStore_Tests.cls-meta.xml b/nebula-logger/core/tests/logger-engine/classes/LoggerDataStore_Tests.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/core/tests/logger-engine/classes/LoggerDataStore_Tests.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/core/tests/logger-engine/classes/LoggerSObjectHandler_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/LoggerSObjectHandler_Tests.cls new file mode 100644 index 000000000..aa8cdd7fc --- /dev/null +++ b/nebula-logger/core/tests/logger-engine/classes/LoggerSObjectHandler_Tests.cls @@ -0,0 +1,416 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @description Test class for LoggerSObjectHandler, the trigger-handler framework used by Nebula Logger. + * To demonstrate that the framework is standalone/would work with any SObject, these test methods + * all use mock implementations of the handler, using the `User` SObject + */ +@SuppressWarnings('PMD.ApexDoc, PMD.ApexAssertionsShouldIncludeMessage, PMD.MethodNamingConventions') +@IsTest(IsParallel=true) +private class LoggerSObjectHandler_Tests { + private static final String FAKE_PROFILE_NAME = 'Some String'; + + @IsTest + static void it_should_return_configured_sobject_handler() { + Schema.SObjectType sobjectType = new MockSObjectHandler().getSObjectType(); + LoggerSObjectHandler.setMock( + new LoggerSObjectHandler__mdt( + IsEnabled__c = true, + SObjectHandlerApexClass__c = MockSObjectHandler.class.getName(), + SObjectType__c = sobjectType.getDescribe().getName() + ) + ); + + LoggerSObjectHandler configuredInstance = LoggerSObjectHandler.getHandler(sobjectType); + + System.assertEquals( + true, + configuredInstance instanceof MockSObjectHandler, + 'The returned handler should be an instance of the configured class, MockSObjectHandler' + ); + } + + @IsTest + static void it_should_return_default_sobject_handler_implementation_when_no_configuration_provided() { + Schema.SObjectType sobjectType = new MockDefaultImplementationSObjectHandler().getSObjectType(); + LoggerSObjectHandler defaultImplementation = new MockDefaultImplementationSObjectHandler(); + + LoggerSObjectHandler configuredInstance = LoggerSObjectHandler.getHandler(sobjectType, defaultImplementation); + + System.assertEquals( + true, + configuredInstance instanceof MockDefaultImplementationSObjectHandler, + 'The returned handler should be an instance of the default implementation class, MockDefaultImplementationSObjectHandler' + ); + } + + @IsTest + static void it_should_override_triggerable_context() { + MockSObjectHandler mockHandler = new MockSObjectHandler(Schema.User.SObjectType); + LoggerTriggerableContext originalContext = mockHandler.input; + LoggerTriggerableContext customContext = new LoggerTriggerableContext( + Schema.User.SObjectType, + TriggerOperation.BEFORE_INSERT, + new List{ new User(Id = UserInfo.getUserId(), Email = UserInfo.getUserEmail()) } + ); + System.assertNotEquals(originalContext, customContext); + + mockHandler.overrideTriggerableContext(customContext); + + System.assertNotEquals(originalContext, mockHandler.input); + System.assertEquals(customContext, mockHandler.input); + } + + @IsTest + static void it_should_not_run_when_disabled_via_logger_parameter() { + User mockUser = (User) LoggerMockDataCreator.createUser(); + mockUser.Id = LoggerMockDataCreator.createId(Schema.User.SObjectType); + List records = new List{ mockUser }; + MockSObjectHandler mockHandler = new MockSObjectHandler(Schema.User.SObjectType); + mockHandler.handlerConfiguration = new LoggerSObjectHandler__mdt(IsEnabled__c = false); + mockHandler.triggerOperationType = TriggerOperation.BEFORE_INSERT; + mockHandler.triggerNew = records; + mockHandler.triggerNewMap = null; + mockHandler.triggerOldMap = null; + + mockHandler.execute(); + + System.assertEquals(0, mockHandler.executionCount, mockHandler); + } + + @IsTest + static void it_should_not_run_when_disabled_via_private_method() { + User mockUser = (User) LoggerMockDataCreator.createUser(); + mockUser.Id = LoggerMockDataCreator.createId(Schema.User.SObjectType); + List records = new List{ mockUser }; + MockSObjectHandler mockHandler = new MockSObjectHandler(Schema.User.SObjectType); + mockHandler.handlerConfiguration = new LoggerSObjectHandler__mdt(IsEnabled__c = true); + mockHandler.triggerOperationType = TriggerOperation.BEFORE_INSERT; + mockHandler.triggerNew = records; + mockHandler.triggerNewMap = null; + mockHandler.triggerOldMap = null; + + LoggerSObjectHandler.shouldExecute(false); + mockHandler.execute(); + + System.assertEquals(0, mockHandler.executionCount, mockHandler); + } + + @IsTest + static void it_should_run_before_insert_method() { + User mockUser = (User) LoggerMockDataCreator.createUser(); + mockUser.Id = LoggerMockDataCreator.createId(Schema.User.SObjectType); + List records = new List{ mockUser }; + MockSObjectHandler mockHandler = new MockSObjectHandler(Schema.User.SObjectType); + mockHandler.triggerOperationType = TriggerOperation.BEFORE_INSERT; + mockHandler.triggerNew = records; + mockHandler.triggerNewMap = null; + mockHandler.triggerOldMap = null; + + mockHandler.execute(); + + System.assertEquals(1, mockHandler.executionCount); + System.assertEquals(TriggerOperation.BEFORE_INSERT, mockHandler.executedTriggerOperationType); + System.assertEquals(mockHandler.triggerNew, mockHandler.executedTriggerNew); + System.assertEquals(null, mockHandler.executedTriggerNewMap); + System.assertEquals(null, mockHandler.executedTriggerOldMap); + } + + @IsTest + static void it_should_run_before_update_method() { + User mockUser = (User) LoggerMockDataCreator.createUser(); + mockUser.Id = LoggerMockDataCreator.createId(Schema.User.SObjectType); + List records = new List{ mockUser }; + MockSObjectHandler mockHandler = new MockSObjectHandler(Schema.User.SObjectType); + mockHandler.triggerOperationType = TriggerOperation.BEFORE_UPDATE; + mockHandler.triggerNew = null; + mockHandler.triggerNewMap = new Map(records); + mockHandler.triggerOldMap = new Map(records); + + mockHandler.execute(); + + System.assertEquals(1, mockHandler.executionCount); + System.assertEquals(TriggerOperation.BEFORE_UPDATE, mockHandler.executedTriggerOperationType); + System.assertEquals(null, mockHandler.executedTriggerNew); + System.assertEquals(mockHandler.triggerNewMap, mockHandler.executedTriggerNewMap); + System.assertEquals(mockHandler.triggerOldMap, mockHandler.executedTriggerOldMap); + } + + @IsTest + static void it_should_run_before_delete_method() { + User mockUser = (User) LoggerMockDataCreator.createUser(); + mockUser.Id = LoggerMockDataCreator.createId(Schema.User.SObjectType); + List records = new List{ mockUser }; + MockSObjectHandler mockHandler = new MockSObjectHandler(Schema.User.SObjectType); + mockHandler.triggerOperationType = TriggerOperation.BEFORE_DELETE; + mockHandler.triggerNew = null; + mockHandler.triggerNewMap = new Map(records); + mockHandler.triggerOldMap = null; + + mockHandler.execute(); + + System.assertEquals(1, mockHandler.executionCount); + System.assertEquals(TriggerOperation.BEFORE_DELETE, mockHandler.executedTriggerOperationType); + System.assertEquals(null, mockHandler.executedTriggerNew); + System.assertEquals(mockHandler.triggerNewMap, mockHandler.executedTriggerNewMap); + System.assertEquals(null, mockHandler.executedTriggerOldMap); + } + + @IsTest + static void it_should_run_after_insert_methods() { + // To handle AFTER_INSERT on LogEntryEvent__e, LoggerSObjectHandler has 2 methods - one with + // a list of SObject records (triggerNew), and another with a map of SObject records (triggerNewMap) + User mockUser = (User) LoggerMockDataCreator.createUser(); + mockUser.Id = LoggerMockDataCreator.createId(Schema.User.SObjectType); + List records = new List{ mockUser }; + MockSObjectHandler mockHandler = new MockSObjectHandler(Schema.User.SObjectType); + mockHandler.triggerOperationType = TriggerOperation.AFTER_INSERT; + mockHandler.triggerNew = records; + mockHandler.triggerNewMap = new Map(records); + mockHandler.triggerOldMap = null; + + mockHandler.execute(); + + System.assertEquals(2, mockHandler.executionCount); + System.assertEquals(TriggerOperation.AFTER_INSERT, mockHandler.executedTriggerOperationType); + System.assertEquals(mockHandler.triggerNew, mockHandler.executedTriggerNew); + System.assertEquals(mockHandler.triggerNewMap, mockHandler.executedTriggerNewMap); + System.assertEquals(null, mockHandler.executedTriggerOldMap); + } + + @IsTest + static void it_should_run_after_update_method() { + User mockUser = (User) LoggerMockDataCreator.createUser(); + mockUser.Id = LoggerMockDataCreator.createId(Schema.User.SObjectType); + List records = new List{ mockUser }; + MockSObjectHandler mockHandler = new MockSObjectHandler(Schema.User.SObjectType); + mockHandler.triggerOperationType = TriggerOperation.AFTER_UPDATE; + mockHandler.triggerNew = null; + mockHandler.triggerNewMap = new Map(records); + mockHandler.triggerOldMap = new Map(records); + + mockHandler.execute(); + + System.assertEquals(1, mockHandler.executionCount); + System.assertEquals(TriggerOperation.AFTER_UPDATE, mockHandler.executedTriggerOperationType); + System.assertEquals(null, mockHandler.executedTriggerNew); + System.assertEquals(mockHandler.triggerNewMap, mockHandler.executedTriggerNewMap); + System.assertEquals(mockHandler.triggerOldMap, mockHandler.executedTriggerOldMap); + } + + @IsTest + static void it_should_run_after_delete_method() { + User mockUser = (User) LoggerMockDataCreator.createUser(); + mockUser.Id = LoggerMockDataCreator.createId(Schema.User.SObjectType); + List records = new List{ mockUser }; + MockSObjectHandler mockHandler = new MockSObjectHandler(Schema.User.SObjectType); + mockHandler.triggerOperationType = TriggerOperation.AFTER_DELETE; + mockHandler.triggerNew = null; + mockHandler.triggerNewMap = new Map(records); + mockHandler.triggerOldMap = null; + + mockHandler.execute(); + + System.assertEquals(1, mockHandler.executionCount); + System.assertEquals(TriggerOperation.AFTER_DELETE, mockHandler.executedTriggerOperationType); + System.assertEquals(null, mockHandler.executedTriggerNew); + System.assertEquals(mockHandler.triggerNewMap, mockHandler.executedTriggerNewMap); + System.assertEquals(null, mockHandler.executedTriggerOldMap); + } + + @IsTest + static void it_should_run_after_undelete_method() { + User mockUser = (User) LoggerMockDataCreator.createUser(); + mockUser.Id = LoggerMockDataCreator.createId(Schema.User.SObjectType); + List records = new List{ mockUser }; + MockSObjectHandler mockHandler = new MockSObjectHandler(Schema.User.SObjectType); + mockHandler.triggerOperationType = TriggerOperation.AFTER_UNDELETE; + mockHandler.triggerNew = null; + mockHandler.triggerNewMap = new Map(records); + mockHandler.triggerOldMap = null; + + mockHandler.execute(); + + System.assertEquals(1, mockHandler.executionCount); + System.assertEquals(TriggerOperation.AFTER_UNDELETE, mockHandler.executedTriggerOperationType); + System.assertEquals(null, mockHandler.executedTriggerNew); + System.assertEquals(mockHandler.triggerNewMap, mockHandler.executedTriggerNewMap); + System.assertEquals(null, mockHandler.executedTriggerOldMap); + } + + @IsTest + static void it_should_gracefully_skip_non_existent_apex_plugin() { + User mockUser = (User) LoggerMockDataCreator.createUser(); + mockUser.Id = LoggerMockDataCreator.createId(Schema.User.SObjectType); + List records = new List{ mockUser }; + MockSObjectHandler mockHandler = new MockSObjectHandler(Schema.User.SObjectType); + mockHandler.triggerOperationType = TriggerOperation.BEFORE_INSERT; + mockHandler.triggerNew = records; + mockHandler.triggerNewMap = null; + mockHandler.triggerOldMap = null; + LoggerPlugin__mdt pluginConfiguration = new LoggerPlugin__mdt( + DeveloperName = 'Mock_Plugin', + IsEnabled__c = true, + SObjectHandlerApexClass__c = 'Some_Fake_Apex_Class' + ); + mockHandler.getPluginConfigurations().add(pluginConfiguration); + + mockHandler.execute(); + + System.assertEquals(1, mockHandler.executionCount); + System.assertEquals(1, mockHandler.getPluginConfigurations().size(), mockHandler.getPluginConfigurations()); + System.assertEquals(0, mockHandler.getExecutedApexPlugins().size(), mockHandler.getExecutedApexPlugins()); + } + + @IsTest + static void it_should_execute_apex_plugin() { + User mockUser = (User) LoggerMockDataCreator.createUser(); + mockUser.Id = LoggerMockDataCreator.createId(Schema.User.SObjectType); + List records = new List{ mockUser }; + MockSObjectHandler mockHandler = new MockSObjectHandler(Schema.User.SObjectType); + mockHandler.triggerOperationType = TriggerOperation.BEFORE_INSERT; + mockHandler.triggerNew = records; + mockHandler.triggerNewMap = null; + mockHandler.triggerOldMap = null; + LoggerPlugin__mdt mockPluginConfiguration = new LoggerPlugin__mdt( + DeveloperName = 'ExampleApexPlugin', + IsEnabled__c = true, + SObjectHandlerApexClass__c = MockTriggerablePlugin.class.getName() + ); + mockHandler.getPluginConfigurations().add(mockPluginConfiguration); + + mockHandler.execute(); + + System.assertEquals(1, mockHandler.executionCount); + System.assertEquals(1, mockHandler.getPluginConfigurations().size(), mockHandler.getPluginConfigurations()); + System.assertEquals(1, mockHandler.getExecutedApexPlugins().size(), mockHandler.getExecutedApexPlugins()); + MockTriggerablePlugin executedApexPlugin = (MockTriggerablePlugin) mockHandler.getExecutedApexPlugins().get(0); + System.assertEquals(mockPluginConfiguration, executedApexPlugin.configuration); + System.assertEquals(mockHandler.input, executedApexPlugin.input); + } + + @IsTest + static void it_should_gracefully_skip_non_existent_flow_plugin() { + User mockUser = (User) LoggerMockDataCreator.createUser(); + mockUser.Id = LoggerMockDataCreator.createId(Schema.User.SObjectType); + List records = new List{ mockUser }; + MockSObjectHandler mockHandler = new MockSObjectHandler(Schema.User.SObjectType); + mockHandler.triggerOperationType = TriggerOperation.BEFORE_INSERT; + mockHandler.triggerNew = records; + mockHandler.triggerNewMap = null; + mockHandler.triggerOldMap = null; + LoggerPlugin__mdt pluginConfiguration = new LoggerPlugin__mdt( + DeveloperName = 'Mock_Plugin', + IsEnabled__c = true, + SObjectHandlerFlowName__c = 'Some_Fake_Flow' + ); + mockHandler.getPluginConfigurations().add(pluginConfiguration); + + mockHandler.execute(); + + System.assertEquals(1, mockHandler.executionCount); + System.assertEquals(1, mockHandler.getPluginConfigurations().size(), mockHandler.getPluginConfigurations()); + System.assertEquals(0, mockHandler.getExecutedApexPlugins().size(), mockHandler.getExecutedApexPlugins()); + } + + public class MockDefaultImplementationSObjectHandler extends LoggerSObjectHandler { + public override SObjectType getSObjectType() { + return Schema.User.SObjectType; + } + } + + public class MockSObjectHandler extends LoggerSObjectHandler { + public Integer executionCount = 0; + public TriggerOperation executedTriggerOperationType; + public List executedTriggerNew; + public Map executedTriggerNewMap; + public Map executedTriggerOldMap; + + private Schema.SObjectType sobjectType; + + public MockSObjectHandler() { + this.sobjectType = Schema.User.SObjectType; + } + + public MockSObjectHandler(Schema.SObjectType sobjectType) { + this.sobjectType = sobjectType; + } + + public override SObjectType getSObjectType() { + return this.sobjectType; + } + + protected override void executeBeforeInsert(List triggerNew) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.BEFORE_INSERT; + this.executedTriggerNew = triggerNew; + super.executeBeforeInsert(triggerNew); + } + + protected override void executeBeforeUpdate(Map triggerNewMap, Map triggerOldMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.BEFORE_UPDATE; + this.executedTriggerNewMap = triggerNewMap; + this.executedTriggerOldMap = triggerOldMap; + super.executeBeforeUpdate(triggerNewMap, triggerOldMap); + } + + protected override void executeBeforeDelete(Map triggerNewMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.BEFORE_DELETE; + this.executedTriggerNewMap = triggerNewMap; + super.executeBeforeDelete(triggerNewMap); + } + + protected override void executeAfterInsert(List triggerNew) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.AFTER_INSERT; + this.executedTriggerNew = triggerNew; + super.executeAfterInsert(triggerNew); + } + + protected override void executeAfterInsert(Map triggerNewMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.AFTER_INSERT; + this.executedTriggerNewMap = triggerNewMap; + super.executeAfterInsert(triggerNewMap); + } + + protected override void executeAfterUpdate(Map triggerNewMap, Map triggerOldMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.AFTER_UPDATE; + this.executedTriggerNewMap = triggerNewMap; + this.executedTriggerOldMap = triggerOldMap; + super.executeAfterUpdate(triggerNewMap, triggerOldMap); + } + + protected override void executeAfterDelete(Map triggerNewMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.AFTER_DELETE; + this.executedTriggerNewMap = triggerNewMap; + super.executeAfterDelete(triggerNewMap); + } + + protected override void executeAfterUndelete(Map triggerNewMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.AFTER_UNDELETE; + this.executedTriggerNewMap = triggerNewMap; + super.executeAfterUndelete(triggerNewMap); + } + } + + public class MockTriggerablePlugin implements LoggerPlugin.Triggerable { + public Boolean hasExecuted { get; private set; } + public LoggerPlugin__mdt configuration { get; private set; } + public LoggerTriggerableContext input { get; private set; } + + public void execute(LoggerPlugin__mdt configuration, LoggerTriggerableContext input) { + this.hasExecuted = true; + this.configuration = configuration; + this.input = input; + } + } +} diff --git a/nebula-logger/core/tests/logger-engine/classes/LoggerSObjectHandler_Tests.cls-meta.xml b/nebula-logger/core/tests/logger-engine/classes/LoggerSObjectHandler_Tests.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/core/tests/logger-engine/classes/LoggerSObjectHandler_Tests.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/core/tests/logger-engine/classes/LoggerTriggerableContext_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/LoggerTriggerableContext_Tests.cls new file mode 100644 index 000000000..663397480 --- /dev/null +++ b/nebula-logger/core/tests/logger-engine/classes/LoggerTriggerableContext_Tests.cls @@ -0,0 +1,97 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @description Test class for LoggerTriggerableContext, part of the trigger-handler framework used by Nebula Logger. + * To demonstrate that the framework is standalone/would work with any SObject, these test methods + * all use mock records for the User SObject + */ +@SuppressWarnings('PMD.MethodNamingConventions') +@IsTest(IsParallel=true) +private class LoggerTriggerableContext_Tests { + // Based on the trigger variables provided by the platform, currently only the TriggerOperations + // BEFORE_INSERT, BEFORE_UPDATE and BEFORE_DELETE need to be tested - other operations & permutations + // will have the same parameters as one of these three scenarios + + @IsTest + static void it_constructs_instance_when_before_insert_operation() { + Schema.SObjectType sobjectType = Schema.User.SObjectType; + TriggerOperation triggerOperationType = TriggerOperation.BEFORE_INSERT; + List newUsers = new List(); + for (Integer i = 0; i < 3; i++) { + newUsers.add((User) LoggerMockDataCreator.createUser()); + } + + LoggerTriggerableContext context = new LoggerTriggerableContext(sobjectType, triggerOperationType, newUsers, null, null); + + System.assertEquals(sobjectType, context.sobjectType); + System.assertEquals(sobjectType.getDescribe().getName(), context.sobjectTypeName); + System.assertEquals(triggerOperationType, context.triggerOperationType); + System.assertEquals(newUsers, context.triggerNew); + System.assertEquals(null, context.triggerNewMap); + System.assertEquals(null, context.triggerOldMap); + System.assertEquals(newUsers.size(), context.triggerRecords.size()); + for (Integer i = 0; i < newUsers.size(); i++) { + System.assertEquals(newUsers.get(i), context.triggerRecords.get(i).triggerRecordNew); + System.assertEquals(null, context.triggerRecords.get(i).triggerRecordOld); + } + } + + @IsTest + static void it_constructs_instance_when_before_update_operation() { + Schema.SObjectType sobjectType = Schema.User.SObjectType; + TriggerOperation triggerOperationType = TriggerOperation.BEFORE_UPDATE; + List updatedUsers = new List(); + for (Integer i = 0; i < 3; i++) { + User user = (User) LoggerMockDataCreator.createUser(); + user.Id = LoggerMockDataCreator.createId(Schema.User.SObjectType); + updatedUsers.add(user); + } + Map newUsersMap = new Map(updatedUsers.clone()); + Map oldUsersMap = new Map(updatedUsers.clone()); + + LoggerTriggerableContext context = new LoggerTriggerableContext(sobjectType, triggerOperationType, updatedUsers, newUsersMap, oldUsersMap); + + System.assertEquals(sobjectType, context.sobjectType); + System.assertEquals(sobjectType.getDescribe().getName(), context.sobjectTypeName); + System.assertEquals(triggerOperationType, context.triggerOperationType); + System.assertEquals(updatedUsers, context.triggerNew); + System.assertEquals(newUsersMap, context.triggerNewMap); + System.assertEquals(oldUsersMap, context.triggerOldMap); + System.assertEquals(updatedUsers.size(), context.triggerRecords.size()); + for (Integer i = 0; i < updatedUsers.size(); i++) { + User user = updatedUsers.get(i); + System.assertEquals(user, context.triggerRecords.get(i).triggerRecordNew); + System.assertEquals(oldUsersMap.get(user.Id), context.triggerRecords.get(i).triggerRecordOld); + } + } + + @IsTest + static void it_constructs_instance_when_before_delete_operation() { + Schema.SObjectType sobjectType = Schema.User.SObjectType; + TriggerOperation triggerOperationType = TriggerOperation.BEFORE_DELETE; + Map deletedLogsMap = new Map(); + for (Integer i = 0; i < 3; i++) { + User user = (User) LoggerMockDataCreator.createDataBuilder(sobjectType).populateMockId().populateRequiredFields().getRecord(); + user.Id = LoggerMockDataCreator.createId(Schema.User.SObjectType); + deletedLogsMap.put(user.Id, user); + } + + LoggerTriggerableContext context = new LoggerTriggerableContext(sobjectType, triggerOperationType, null, null, deletedLogsMap); + + System.assertEquals(sobjectType, context.sobjectType); + System.assertEquals(sobjectType.getDescribe().getName(), context.sobjectTypeName); + System.assertEquals(triggerOperationType, context.triggerOperationType); + System.assertEquals(null, context.triggerNew); + System.assertEquals(null, context.triggerNewMap); + System.assertEquals(deletedLogsMap, context.triggerOldMap); + System.assertEquals(deletedLogsMap.size(), context.triggerRecords.size()); + for (Integer i = 0; i < deletedLogsMap.size(); i++) { + User deletedLog = deletedLogsMap.values().get(i); + System.assertEquals(null, context.triggerRecords.get(i).triggerRecordNew); + System.assertEquals(deletedLog, context.triggerRecords.get(i).triggerRecordOld); + } + } +} diff --git a/nebula-logger/core/tests/logger-engine/classes/LoggerTriggerableContext_Tests.cls-meta.xml b/nebula-logger/core/tests/logger-engine/classes/LoggerTriggerableContext_Tests.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/core/tests/logger-engine/classes/LoggerTriggerableContext_Tests.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/core/tests/logger-engine/classes/Logger_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/Logger_Tests.cls index 3b8487d71..98252de77 100644 --- a/nebula-logger/core/tests/logger-engine/classes/Logger_Tests.cls +++ b/nebula-logger/core/tests/logger-engine/classes/Logger_Tests.cls @@ -3,219 +3,36 @@ // See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // //------------------------------------------------------------------------------------------------// -@SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount, PMD.NcssTypeCount') +@IsTest(IsParallel=false) private class Logger_Tests { - // Helper classes - private class SuccessCalloutMock implements HttpCalloutMock { - public HttpResponse respond(HttpRequest request) { - HttpResponse response = new HttpResponse(); - response.setBody(request.getBody()); - response.setStatusCode(200); - return response; - } - } - - private class FailureCalloutMock implements HttpCalloutMock { - public HttpResponse respond(HttpRequest request) { - HttpResponse response = new HttpResponse(); - response.setBody(request.getBody()); - response.setStatusCode(400); - return response; - } - } - - // Helper methods - static void setUserLoggingLevel(LoggingLevel loggingLevel) { - Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); - } - - static String getMessage() { - return 'Hello, world'; - } - - static LogMessage getLogMessage() { - return new LogMessage('The current user is {0}', getRecord()); - } - - static SObject getRecord() { - return new User( - Id = UserInfo.getUserId(), - ProfileId = UserInfo.getProfileId(), - Username = UserInfo.getUserName(), - UserRoleId = UserInfo.getUserRoleId() - ); - } - - static Exception getException() { - return new DmlException('Example DML Exception'); - } - - static Database.DeleteResult getDeleteResult(Boolean isSuccess) { - Log__c log = new Log__c(TransactionId__c = '1234'); - insert log; - - if (isSuccess == false) { - // Delete the log twice to trigger a DeleteResult error - delete log; - } - - Database.DeleteResult deleteResult = Database.delete(log, false); - System.assertEquals(isSuccess, deleteResult.isSuccess()); - - return deleteResult; - } - - static List getDeleteResultList() { - List logs = new List(); - for (Integer i = 0; i < 3; i++) { - Log__c log = new Log__c(TransactionId__c = '1234' + i); - logs.add(log); - } - insert logs; - - return Database.delete(logs, false); - } - - // TODO only some standard objects can be merged - need to find a way to either mock or trigger a merge result that works in all orgs - // static Database.MergeResult getMergeResult(Boolean isSuccess) { } - - static Database.SaveResult getSaveResult(Boolean isSuccess) { - Database.SaveResult saveResult; - - if (isSuccess == false) { - saveResult = Database.insert(new Account(), false); - } else { - saveResult = Database.insert(new Log__c(TransactionId__c = '1234'), false); - } - System.assertEquals(isSuccess, saveResult.isSuccess()); - return saveResult; - } - - static List getSaveResultList() { - List logs = new List(); - for (Integer i = 0; i < 3; i++) { - Log__c log = new Log__c(TransactionId__c = '1234' + i); - logs.add(log); - } - - return Database.insert(logs, false); - } - - static Database.UpsertResult getUpsertResult(Boolean isSuccess, Boolean isInsert) { - Database.UpsertResult upsertResult; - - if (isSuccess == false && isInsert == true) { - upsertResult = Database.upsert(new Account(), false); - } else if (isSuccess == true && isInsert == true) { - upsertResult = Database.upsert(new Log__c(TransactionId__c = '1234'), false); - } else if (isSuccess == true && isInsert == false) { - Log__c log = new Log__c(TransactionId__c = '1234'); - insert log; - log.TransactionId__c = '9876'; - - upsertResult = Database.upsert(log, false); - } else if (isSuccess == false && isInsert == false) { - Log__c log = new Log__c(TransactionId__c = '1234'); - insert log; - - // Use a log entry this time to handle the upsert scenario - LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, Name = 'Test Log Entry'); - insert logEntry; - - // Set name field to a value too long for the field - Integer maxFieldLength = Schema.LogEntry__c.Name.getDescribe().getLength(); - logEntry.Name = '0'.repeat(maxFieldLength + 10); - - upsertResult = Database.upsert(logEntry, false); - } - System.assertEquals(isSuccess, upsertResult.isSuccess()); - System.assertEquals(isInsert, upsertResult.isCreated()); - return upsertResult; - } - - static List getUpsertResultList() { - List logs = new List(); - for (Integer i = 0; i < 3; i++) { - Log__c log = new Log__c(TransactionId__c = '1234' + i); - logs.add(log); - } - - return Database.upsert(logs, false); - } - - static Database.UndeleteResult getUndeleteResult(Boolean isSuccess) { - Database.UndeleteResult undeleteResult; - - Log__c log = new Log__c(TransactionId__c = '1234'); - insert log; - delete log; - - if (isSuccess == false) { - // Hard delete to cause an undelete error - Database.emptyRecycleBin(log); - - undeleteResult = Database.undelete(log.Id, false); - } else { - undeleteResult = Database.undelete(log.Id, false); - } - System.assertEquals(isSuccess, undeleteResult.isSuccess()); - return undeleteResult; - } + @IsTest + static void it_should_return_version_number() { + String expectedVersionNumber = Logger.CURRENT_VERSION_NUMBER; - static List getUndeleteResultList() { - List logs = new List(); - for (Integer i = 0; i < 3; i++) { - Log__c log = new Log__c(TransactionId__c = '1234' + i); - logs.add(log); - } - insert logs; - delete logs; + String returnedVersionNumber = Logger.getVersionNumber(); - return Database.undelete(logs, false); + System.assertEquals(expectedVersionNumber, returnedVersionNumber); } - static String getOriginLocation() { - String originLocation; - for (String currentStackTraceLine : new DmlException().getStackTraceString().split('\n')) { - if (currentStackTraceLine.contains('Logger_Tests.getOriginLocation')) { - continue; - } - if (currentStackTraceLine.contains('.LogEntryEventBuilder.')) { - continue; - } - if (currentStackTraceLine.contains('.Logger.')) { - continue; - } - originLocation = currentStackTraceLine.substringBefore(':'); - if (originLocation.startsWith('Class.')) { - originLocation = originLocation.substringAfter('Class.'); - } - break; - } + @IsTest + static void it_should_return_namespace_prefix() { + String className = Logger_Tests.class.getName(); + String expectedNamespacePrefix = className.contains('.') ? className.substringBefore('.') : ''; - return originLocation; - } + String returnedNamespacePrefix = Logger.getNamespacePrefix(); - @TestSetup - static void setup() { - LoggerSettings__c settings = LoggerSettings__c.getInstance(); - settings.IsEnabled__c = true; - settings.LoggingLevel__c = LoggingLevel.DEBUG.name(); - upsert settings; + System.assertEquals(expectedNamespacePrefix, returnedNamespacePrefix); } @IsTest static void it_should_use_in_memory_default_settings_when_not_configured() { - delete [SELECT Id FROM LoggerSettings__c]; - List existingSettings = [SELECT Id FROM LoggerSettings__c]; - System.assertEquals(0, existingSettings.size()); LoggerSettings__c expectedSettings = (LoggerSettings__c) LoggerSettings__c.SObjectType.newSObject(null, true); expectedSettings.SetupOwnerId = UserInfo.getUserId(); LoggerSettings__c returnedSettings = Logger.getUserSettings(); - existingSettings = [SELECT Id FROM LoggerSettings__c]; + List existingSettings = [SELECT Id FROM LoggerSettings__c]; System.assertEquals(0, existingSettings.size(), 'LoggerSettings__c record should not have been saved'); System.assertEquals(expectedSettings, returnedSettings); System.assertEquals(null, returnedSettings.Id); @@ -223,9 +40,6 @@ private class Logger_Tests { @IsTest static void it_should_use_org_default_settings_when_configured() { - delete [SELECT Id FROM LoggerSettings__c]; - List existingSettings = [SELECT Id FROM LoggerSettings__c]; - System.assertEquals(0, existingSettings.size()); LoggerSettings__c expectedSettings = LoggerSettings__c.getOrgDefaults(); expectedSettings.LoggingLevel__c = LoggingLevel.FINEST.name(); insert expectedSettings; @@ -235,7 +49,7 @@ private class Logger_Tests { LoggerSettings__c returnedSettings = Logger.getUserSettings(); - existingSettings = [SELECT Id FROM LoggerSettings__c]; + List existingSettings = [SELECT Id FROM LoggerSettings__c]; System.assertEquals(1, existingSettings.size(), 'LoggerSettings__c org defaults should have been saved'); System.assertEquals(expectedSettings, returnedSettings); System.assertEquals(null, returnedSettings.Id); @@ -243,9 +57,6 @@ private class Logger_Tests { @IsTest static void it_should_use_profile_settings_when_configured() { - delete [SELECT Id FROM LoggerSettings__c]; - List existingSettings = [SELECT Id FROM LoggerSettings__c]; - System.assertEquals(0, existingSettings.size()); insert LoggerSettings__c.getOrgDefaults(); LoggerSettings__c expectedSettings = LoggerSettings__c.getOrgDefaults(); expectedSettings.Id = null; @@ -258,7 +69,7 @@ private class Logger_Tests { LoggerSettings__c returnedSettings = Logger.getUserSettings(); - existingSettings = [SELECT Id FROM LoggerSettings__c]; + List existingSettings = [SELECT Id FROM LoggerSettings__c]; System.assertEquals(2, existingSettings.size(), 'LoggerSettings__c org defaults and profile settings should have been saved'); System.assertEquals(expectedSettings, returnedSettings); System.assertEquals(null, returnedSettings.Id); @@ -266,9 +77,6 @@ private class Logger_Tests { @IsTest static void it_should_use_user_settings_when_configured() { - delete [SELECT Id FROM LoggerSettings__c]; - List existingSettings = [SELECT Id FROM LoggerSettings__c]; - System.assertEquals(0, existingSettings.size()); insert LoggerSettings__c.getOrgDefaults(); LoggerSettings__c profileSettings = LoggerSettings__c.getOrgDefaults(); profileSettings.Id = null; @@ -284,7 +92,7 @@ private class Logger_Tests { LoggerSettings__c returnedSettings = Logger.getUserSettings(); - existingSettings = [SELECT Id FROM LoggerSettings__c]; + List existingSettings = [SELECT Id FROM LoggerSettings__c]; System.assertEquals(3, existingSettings.size(), 'LoggerSettings__c org defaults, profile settings, and user settings should have been saved'); System.assertEquals(expectedSettings, returnedSettings); System.assertEquals(expectedSettings.Id, returnedSettings.Id); @@ -337,7 +145,7 @@ private class Logger_Tests { } Logger.saveLog(); System.assertEquals(transactionScenarioName, Logger.getScenario()); - Test.getEventBus().deliver(); + System.Test.getEventBus().deliver(); Log__c log = [SELECT Id, Scenario__c FROM Log__c WHERE TransactionId__c = :transactionId]; System.assertEquals(transactionScenarioName, log.Scenario__c, 'Scenario__c was not properly set on the Log__c record'); @@ -354,7 +162,7 @@ private class Logger_Tests { } Logger.saveLog(); System.assertEquals(transactionScenarioName, Logger.getScenario()); - Test.getEventBus().deliver(); + System.Test.getEventBus().deliver(); Log__c log = [SELECT Id, Scenario__c FROM Log__c WHERE TransactionId__c = :transactionId]; System.assertEquals(transactionScenarioName, log.Scenario__c, 'Scenario__c was not properly set on the Log__c record'); @@ -375,7 +183,7 @@ private class Logger_Tests { } Logger.saveLog(); System.assertEquals(transactionScenarioName, Logger.getScenario()); - Test.getEventBus().deliver(); + System.Test.getEventBus().deliver(); Log__c log = [SELECT Id, Scenario__c FROM Log__c WHERE TransactionId__c = :transactionId]; System.assertEquals(transactionScenarioName, log.Scenario__c, 'Scenario__c was not properly set on the Log__c record'); @@ -398,7 +206,7 @@ private class Logger_Tests { Logger.setScenario(lastTransactionScenarioName); Logger.saveLog(); System.assertEquals(lastTransactionScenarioName, Logger.getScenario()); - Test.getEventBus().deliver(); + System.Test.getEventBus().deliver(); Log__c log = [SELECT Id, Scenario__c FROM Log__c WHERE TransactionId__c = :transactionId]; System.assertEquals(lastTransactionScenarioName, log.Scenario__c, 'Scenario__c was not properly set on the Log__c record'); @@ -644,19 +452,18 @@ private class Logger_Tests { Logger.saveLog(); - Test.getEventBus().deliver(); + System.Test.getEventBus().deliver(); Test.stopTest(); countOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; System.assertEquals(logEntriesToCreate, countOfLogEntries); - System.assertEquals(1, Limits.getDmlStatements()); } @IsTest static void it_should_save_accurate_timestamp_when_logging_user_has_different_time_zone() { User automatedProcessUser = [SELECT Id, TimeZoneSidKey FROM User WHERE Name = 'Automated Process' AND Profile.Name = NULL]; - User testStandardUser = LoggerTestUtils.createUser(); + User testStandardUser = LoggerMockDataCreator.createUser(); // Make sure that the test user has a different time zone from the automated process user if (automatedProcessUser.TimeZoneSidKey == testStandardUser.TimeZoneSidKey) { @@ -683,7 +490,7 @@ private class Logger_Tests { System.assertEquals(1, Logger.getBufferSize()); Logger.saveLog(); - Test.getEventBus().deliver(); + System.Test.getEventBus().deliver(); } LogEntry__c logEntry = [SELECT Id, Timestamp__c FROM LogEntry__c]; @@ -715,7 +522,7 @@ private class Logger_Tests { Logger.getUserSettings().IsSavingEnabled__c = false; - System.assertEquals(Logger.SaveMethod.EVENT_BUS, Logger.transactionSaveMethod); + System.assertEquals(Logger.SaveMethod.EVENT_BUS, Logger.getSaveMethod()); Logger.debug('test log entry'); Logger.debug('another test log entry'); @@ -745,7 +552,7 @@ private class Logger_Tests { Logger.getUserSettings().DefaultSaveMethod__c = 'EVENT_BUS'; - System.assertEquals(Logger.SaveMethod.EVENT_BUS, Logger.transactionSaveMethod); + System.assertEquals(Logger.SaveMethod.EVENT_BUS, Logger.getSaveMethod()); Logger.debug('test log entry'); Logger.debug('another test log entry'); @@ -832,7 +639,7 @@ private class Logger_Tests { Test.startTest(); - System.assertEquals(Logger.SaveMethod.QUEUEABLE, Logger.transactionSaveMethod); + System.assertEquals(Logger.SaveMethod.QUEUEABLE, Logger.getSaveMethod()); Logger.debug('test log entry'); Logger.debug('another test log entry'); @@ -873,7 +680,7 @@ private class Logger_Tests { System.assertEquals(0, Limits.getCallouts()); System.assertEquals(0, Limits.getDmlStatements()); - Test.getEventBus().deliver(); + System.Test.getEventBus().deliver(); Test.stopTest(); @@ -904,7 +711,7 @@ private class Logger_Tests { System.assertEquals(0, Limits.getCallouts()); System.assertEquals(0, Limits.getDmlStatements()); - Test.getEventBus().deliver(); + System.Test.getEventBus().deliver(); Test.stopTest(); @@ -914,7 +721,7 @@ private class Logger_Tests { @IsTest static void it_should_save_via_rest_api_when_defaulted() { - Test.setMock(HttpCalloutMock.class, new SuccessCalloutMock()); + Test.setMock(HttpCalloutMock.class, LoggerMockDataCreator.createHttpCallout().setStatusCode(200)); Integer countOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; System.assertEquals(0, countOfLogEntries); @@ -923,7 +730,7 @@ private class Logger_Tests { Logger.getUserSettings().DefaultSaveMethod__c = 'REST'; - System.assertEquals(Logger.SaveMethod.REST, Logger.transactionSaveMethod); + System.assertEquals(Logger.SaveMethod.REST, Logger.getSaveMethod()); Logger.debug('test log entry'); Logger.debug('another test log entry'); @@ -943,7 +750,7 @@ private class Logger_Tests { @IsTest static void it_should_save_via_rest_api_when_specified_via_settings() { - Test.setMock(HttpCalloutMock.class, new SuccessCalloutMock()); + Test.setMock(HttpCalloutMock.class, LoggerMockDataCreator.createHttpCallout().setStatusCode(200)); Integer countOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; System.assertEquals(0, countOfLogEntries); @@ -968,7 +775,7 @@ private class Logger_Tests { @IsTest static void it_should_save_via_rest_api_when_specified_via_setSaveMethod() { - Test.setMock(HttpCalloutMock.class, new SuccessCalloutMock()); + Test.setMock(HttpCalloutMock.class, LoggerMockDataCreator.createHttpCallout().setStatusCode(200)); Integer countOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; System.assertEquals(0, countOfLogEntries); @@ -996,7 +803,7 @@ private class Logger_Tests { @IsTest static void it_should_throw_exception_when_save_via_rest_api_fails() { - Test.setMock(HttpCalloutMock.class, new FailureCalloutMock()); + Test.setMock(HttpCalloutMock.class, LoggerMockDataCreator.createHttpCallout().setStatusCode(400)); Integer countOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; System.assertEquals(0, countOfLogEntries); @@ -1025,89 +832,156 @@ private class Logger_Tests { @IsTest static void it_should_save_via_synchronous_dml_when_defaulted() { - Integer countOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; - System.assertEquals(0, countOfLogEntries); - - setUserLoggingLevel(LoggingLevel.DEBUG); - - Logger.getUserSettings().DefaultSaveMethod__c = 'SYNCHRONOUS_DML'; - - System.assertEquals(Logger.SaveMethod.SYNCHRONOUS_DML, Logger.transactionSaveMethod); - - Logger.debug('test log entry'); - Logger.debug('another test log entry'); - - System.assertEquals(0, Limits.getCallouts()); - + LoggerSObjectHandler.setMock( + new LoggerSObjectHandler__mdt( + DeveloperName = 'Mock_Log_Entry_Event_Config', + IsEnabled__c = true, + SObjectHandlerApexClass__c = MockSObjectHandler.class.getName(), + SObjectType__c = Schema.LogEntryEvent__e.SObjectType.getDescribe().getName() + ) + ); + Logger.getUserSettings().DefaultSaveMethod__c = Logger.SaveMethod.SYNCHRONOUS_DML.name(); + Logger.getUserSettings().LoggingLevel__c = LoggingLevel.DEBUG.name(); + System.assertEquals(LoggingLevel.DEBUG, Logger.getUserLoggingLevel()); + System.assertEquals(Logger.SaveMethod.SYNCHRONOUS_DML, Logger.getSaveMethod()); + List logEntryEvents = new List(); + logEntryEvents.add(Logger.debug('test log entry').getLogEntryEvent()); + logEntryEvents.add(Logger.debug('another test log entry').getLogEntryEvent()); Test.startTest(); - - Logger.saveLog(); System.assertEquals(0, Limits.getPublishImmediateDml()); System.assertEquals(0, Limits.getQueueableJobs()); System.assertEquals(0, Limits.getCallouts()); - System.assertNotEquals(0, Limits.getDmlStatements()); + System.assertEquals(logEntryEvents.size(), Logger.getBufferSize()); - // Requery & assert before Test.stopTest() since this is supposed to save synchronously - countOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; - System.assertEquals(2, countOfLogEntries); + Logger.saveLog(); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(0, Limits.getPublishImmediateDml()); + System.assertEquals(0, Limits.getQueueableJobs()); + System.assertEquals(0, Limits.getCallouts()); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); + MockSObjectHandler mockLogEntryEventBeforeInsertHandler = (MockSObjectHandler) LoggerSObjectHandler.getExecutedHandlers() + .get(Schema.LogEntryEvent__e.SObjectType) + .get(0); + // System.assertEquals(1, mockLogEntryEventBeforeInsertHandler.executionCount); + System.assertEquals(TriggerOperation.BEFORE_INSERT, mockLogEntryEventBeforeInsertHandler.executedTriggerOperationType); + System.assertEquals(logEntryEvents.size(), mockLogEntryEventBeforeInsertHandler.executedTriggerNew.size()); + System.assertEquals(logEntryEvents.get(0), mockLogEntryEventBeforeInsertHandler.executedTriggerNew.get(0)); + System.assertEquals(logEntryEvents.get(1), mockLogEntryEventBeforeInsertHandler.executedTriggerNew.get(1)); + MockSObjectHandler mockLogEntryEventAfterInsertHandler = (MockSObjectHandler) LoggerSObjectHandler.getExecutedHandlers() + .get(Schema.LogEntryEvent__e.SObjectType) + .get(1); + // System.assertEquals(1, mockLogEntryEventAfterInsertHandler.executionCount); + System.assertEquals(TriggerOperation.AFTER_INSERT, mockLogEntryEventAfterInsertHandler.executedTriggerOperationType); + System.assertEquals(logEntryEvents.size(), mockLogEntryEventAfterInsertHandler.executedTriggerNew.size()); + System.assertEquals(logEntryEvents.get(0), mockLogEntryEventAfterInsertHandler.executedTriggerNew.get(0)); + System.assertEquals(logEntryEvents.get(1), mockLogEntryEventAfterInsertHandler.executedTriggerNew.get(1)); Test.stopTest(); } @IsTest static void it_should_save_via_synchronous_dml_when_specified_via_settings() { - Integer countOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; - System.assertEquals(0, countOfLogEntries); - - setUserLoggingLevel(LoggingLevel.DEBUG); - - Logger.debug('test log entry'); - Logger.debug('another test log entry'); - - System.assertEquals(0, Limits.getCallouts()); - + LoggerSObjectHandler.setMock( + new LoggerSObjectHandler__mdt( + DeveloperName = 'Mock_Log_Entry_Event_Config', + IsEnabled__c = true, + SObjectHandlerApexClass__c = MockSObjectHandler.class.getName(), + SObjectType__c = Schema.LogEntryEvent__e.SObjectType.getDescribe().getName() + ) + ); + List logEntryEvents = new List(); + logEntryEvents.add(Logger.debug('test log entry').getLogEntryEvent()); + logEntryEvents.add(Logger.debug('another test log entry').getLogEntryEvent()); Test.startTest(); - - Logger.saveLog(Logger.SaveMethod.SYNCHRONOUS_DML); System.assertEquals(0, Limits.getPublishImmediateDml()); System.assertEquals(0, Limits.getQueueableJobs()); System.assertEquals(0, Limits.getCallouts()); - System.assertNotEquals(0, Limits.getDmlStatements()); + System.assertEquals(logEntryEvents.size(), Logger.getBufferSize()); - // Requery & assert before Test.stopTest() since this is supposed to save synchronously - countOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; - System.assertEquals(2, countOfLogEntries); + Logger.getUserSettings().DefaultSaveMethod__c = Logger.SaveMethod.SYNCHRONOUS_DML.name(); + System.assertEquals(Logger.SaveMethod.SYNCHRONOUS_DML, Logger.getSaveMethod()); + Logger.saveLog(); + System.assertEquals(0, Logger.getBufferSize()); + System.assertEquals(0, Limits.getPublishImmediateDml()); + System.assertEquals(0, Limits.getQueueableJobs()); + System.assertEquals(0, Limits.getCallouts()); + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); + MockSObjectHandler mockLogEntryEventBeforeInsertHandler = (MockSObjectHandler) LoggerSObjectHandler.getExecutedHandlers() + .get(Schema.LogEntryEvent__e.SObjectType) + .get(0); + // System.assertEquals(1, mockLogEntryEventBeforeInsertHandler.executionCount); + System.assertEquals(TriggerOperation.BEFORE_INSERT, mockLogEntryEventBeforeInsertHandler.executedTriggerOperationType); + System.assertEquals(logEntryEvents.size(), mockLogEntryEventBeforeInsertHandler.executedTriggerNew.size()); + System.assertEquals(logEntryEvents.get(0), mockLogEntryEventBeforeInsertHandler.executedTriggerNew.get(0)); + System.assertEquals(logEntryEvents.get(1), mockLogEntryEventBeforeInsertHandler.executedTriggerNew.get(1)); + MockSObjectHandler mockLogEntryEventAfterInsertHandler = (MockSObjectHandler) LoggerSObjectHandler.getExecutedHandlers() + .get(Schema.LogEntryEvent__e.SObjectType) + .get(1); + // System.assertEquals(1, mockLogEntryEventAfterInsertHandler.executionCount); + System.assertEquals(TriggerOperation.AFTER_INSERT, mockLogEntryEventAfterInsertHandler.executedTriggerOperationType); + System.assertEquals(logEntryEvents.size(), mockLogEntryEventAfterInsertHandler.executedTriggerNew.size()); + System.assertEquals(logEntryEvents.get(0), mockLogEntryEventAfterInsertHandler.executedTriggerNew.get(0)); + System.assertEquals(logEntryEvents.get(1), mockLogEntryEventAfterInsertHandler.executedTriggerNew.get(1)); Test.stopTest(); } @IsTest static void it_should_save_via_synchronous_dml_when_specified_via_setSaveMethod() { - Integer countOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; - System.assertEquals(0, countOfLogEntries); - - setUserLoggingLevel(LoggingLevel.DEBUG); - - Logger.debug('test log entry'); - Logger.debug('another test log entry'); - - System.assertEquals(0, Limits.getCallouts()); - + LoggerSObjectHandler.setMock( + new LoggerSObjectHandler__mdt( + DeveloperName = 'Mock_Log_Entry_Event_Config', + IsEnabled__c = true, + SObjectHandlerApexClass__c = MockSObjectHandler.class.getName(), + SObjectType__c = Schema.LogEntryEvent__e.SObjectType.getDescribe().getName() + ) + ); + List logEntryEvents = new List(); + logEntryEvents.add(Logger.debug('test log entry').getLogEntryEvent()); + logEntryEvents.add(Logger.debug('another test log entry').getLogEntryEvent()); Test.startTest(); + System.assertEquals(0, Limits.getPublishImmediateDml()); + System.assertEquals(0, Limits.getQueueableJobs()); + System.assertEquals(0, Limits.getCallouts()); + System.assertEquals(logEntryEvents.size(), Logger.getBufferSize()); Logger.SaveMethod expectedSaveMethod = Logger.SaveMethod.SYNCHRONOUS_DML; Logger.setSaveMethod(expectedSaveMethod); System.assertEquals(expectedSaveMethod, Logger.getSaveMethod()); Logger.saveLog(); + System.assertEquals(0, Limits.getPublishImmediateDml()); System.assertEquals(0, Limits.getQueueableJobs()); System.assertEquals(0, Limits.getCallouts()); - System.assertNotEquals(0, Limits.getDmlStatements()); - - // Requery & assert before Test.stopTest() since this is supposed to save synchronously - countOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; - System.assertEquals(2, countOfLogEntries); - + System.assertEquals( + 2, + LoggerSObjectHandler.getExecutedHandlers().get(Schema.LogEntryEvent__e.SObjectType).size(), + 'Handler class should have executed two times - once for BEFORE_INSERT and once for AFTER_INSERT' + ); + MockSObjectHandler mockLogEntryEventBeforeInsertHandler = (MockSObjectHandler) LoggerSObjectHandler.getExecutedHandlers() + .get(Schema.LogEntryEvent__e.SObjectType) + .get(0); + // System.assertEquals(1, mockLogEntryEventBeforeInsertHandler.executionCount); + System.assertEquals(TriggerOperation.BEFORE_INSERT, mockLogEntryEventBeforeInsertHandler.executedTriggerOperationType); + System.assertEquals(logEntryEvents.size(), mockLogEntryEventBeforeInsertHandler.executedTriggerNew.size()); + System.assertEquals(logEntryEvents.get(0), mockLogEntryEventBeforeInsertHandler.executedTriggerNew.get(0)); + System.assertEquals(logEntryEvents.get(1), mockLogEntryEventBeforeInsertHandler.executedTriggerNew.get(1)); + MockSObjectHandler mockLogEntryEventAfterInsertHandler = (MockSObjectHandler) LoggerSObjectHandler.getExecutedHandlers() + .get(Schema.LogEntryEvent__e.SObjectType) + .get(1); + // System.assertEquals(1, mockLogEntryEventAfterInsertHandler.executionCount); + System.assertEquals(TriggerOperation.AFTER_INSERT, mockLogEntryEventAfterInsertHandler.executedTriggerOperationType); + System.assertEquals(logEntryEvents.size(), mockLogEntryEventAfterInsertHandler.executedTriggerNew.size()); + System.assertEquals(logEntryEvents.get(0), mockLogEntryEventAfterInsertHandler.executedTriggerNew.get(0)); + System.assertEquals(logEntryEvents.get(1), mockLogEntryEventAfterInsertHandler.executedTriggerNew.get(1)); Test.stopTest(); } @@ -1232,7 +1106,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(true); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(true); Test.startTest(); @@ -1256,7 +1130,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(false); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(false); Test.startTest(); @@ -1304,7 +1178,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(true); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(true); Test.startTest(); @@ -1328,7 +1202,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(false); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(false); Test.startTest(); @@ -1376,7 +1250,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(true); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -1400,7 +1274,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(false); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -1448,7 +1322,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, true); Test.startTest(); @@ -1472,7 +1346,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(false, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(false, true); Test.startTest(); @@ -1496,7 +1370,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, false); Test.startTest(); @@ -1520,7 +1394,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(false, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(false, false); Test.startTest(); @@ -1748,7 +1622,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(true); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(true); Test.startTest(); @@ -1772,7 +1646,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(false); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(false); Test.startTest(); @@ -1796,7 +1670,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(true); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(true); Test.startTest(); @@ -1820,7 +1694,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(false); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(false); Test.startTest(); @@ -1844,7 +1718,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(true); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -1868,7 +1742,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(false); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -1892,7 +1766,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, true); Test.startTest(); @@ -1916,7 +1790,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(false, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(false, true); Test.startTest(); @@ -1940,7 +1814,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, false); Test.startTest(); @@ -1964,7 +1838,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(false, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(false, false); Test.startTest(); @@ -2263,7 +2137,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(true); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(true); Test.startTest(); @@ -2287,7 +2161,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(false); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(false); Test.startTest(); @@ -2311,7 +2185,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(true); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(true); Test.startTest(); @@ -2335,7 +2209,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(false); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(false); Test.startTest(); @@ -2359,7 +2233,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(true); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -2383,7 +2257,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(false); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -2407,7 +2281,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, true); Test.startTest(); @@ -2431,7 +2305,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(false, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(false, true); Test.startTest(); @@ -2455,7 +2329,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, false); Test.startTest(); @@ -2479,7 +2353,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(false, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(false, false); Test.startTest(); @@ -2683,7 +2557,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(true); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(true); Test.startTest(); @@ -2707,7 +2581,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(false); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(false); Test.startTest(); @@ -2731,7 +2605,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(true); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(true); Test.startTest(); @@ -2755,7 +2629,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(false); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(false); Test.startTest(); @@ -2779,7 +2653,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(true); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -2803,7 +2677,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(false); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -2827,7 +2701,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, true); Test.startTest(); @@ -2851,7 +2725,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(false, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(false, true); Test.startTest(); @@ -2875,7 +2749,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, false); Test.startTest(); @@ -2899,7 +2773,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(false, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(false, false); Test.startTest(); @@ -3103,7 +2977,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(true); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(true); Test.startTest(); @@ -3127,7 +3001,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(true); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(true); Test.startTest(); @@ -3151,7 +3025,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(true); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -3175,7 +3049,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, true); Test.startTest(); @@ -3199,7 +3073,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, false); Test.startTest(); @@ -3410,7 +3284,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(true); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(true); Test.startTest(); @@ -3434,7 +3308,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(true); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(true); Test.startTest(); @@ -3458,7 +3332,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(true); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -3482,7 +3356,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, true); Test.startTest(); @@ -3506,7 +3380,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, false); Test.startTest(); @@ -3717,7 +3591,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(true); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(true); Test.startTest(); @@ -3741,7 +3615,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(true); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(true); Test.startTest(); @@ -3765,7 +3639,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(true); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -3789,7 +3663,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, true); Test.startTest(); @@ -3813,7 +3687,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, false); Test.startTest(); @@ -4024,7 +3898,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(true); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(true); Test.startTest(); @@ -4048,7 +3922,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(true); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(true); Test.startTest(); @@ -4072,7 +3946,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(true); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -4096,7 +3970,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, true); Test.startTest(); @@ -4120,7 +3994,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, false); Test.startTest(); @@ -4331,7 +4205,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(true); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(true); Test.startTest(); @@ -4355,7 +4229,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(true); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(true); Test.startTest(); @@ -4379,7 +4253,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(true); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -4403,7 +4277,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, true); Test.startTest(); @@ -4427,7 +4301,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, false); Test.startTest(); @@ -4638,7 +4512,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(true); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(true); Test.startTest(); @@ -4662,7 +4536,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(true); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(true); Test.startTest(); @@ -4686,7 +4560,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(true); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -4710,7 +4584,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, true); Test.startTest(); @@ -4734,7 +4608,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, false); Test.startTest(); @@ -4945,7 +4819,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(true); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(true); Test.startTest(); @@ -4969,7 +4843,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(true); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(true); Test.startTest(); @@ -4993,7 +4867,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(true); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -5017,7 +4891,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, true); Test.startTest(); @@ -5041,7 +4915,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, false); Test.startTest(); @@ -5252,7 +5126,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(true); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(true); Test.startTest(); @@ -5276,7 +5150,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(true); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(true); Test.startTest(); @@ -5300,7 +5174,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(true); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -5324,7 +5198,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, true); Test.startTest(); @@ -5348,7 +5222,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, false); Test.startTest(); @@ -5559,7 +5433,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(true); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(true); Test.startTest(); @@ -5583,7 +5457,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(true); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(true); Test.startTest(); @@ -5607,7 +5481,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(true); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -5631,7 +5505,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, true); Test.startTest(); @@ -5655,7 +5529,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, false); Test.startTest(); @@ -5866,7 +5740,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.DeleteResult deleteResult = getDeleteResult(true); + Database.DeleteResult deleteResult = LoggerMockDataCreator.createDatabaseDeleteResult(true); Test.startTest(); @@ -5890,7 +5764,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.SaveResult saveResult = getSaveResult(true); + Database.SaveResult saveResult = LoggerMockDataCreator.createDatabaseSaveResult(true); Test.startTest(); @@ -5914,7 +5788,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UndeleteResult undeleteResult = getUndeleteResult(true); + Database.UndeleteResult undeleteResult = LoggerMockDataCreator.createDatabaseUndeleteResult(true); Test.startTest(); @@ -5938,7 +5812,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, true); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, true); Test.startTest(); @@ -5962,7 +5836,7 @@ private class Logger_Tests { setUserLoggingLevel(loggingLevel); System.assertEquals(0, Logger.getBufferSize()); - Database.UpsertResult upsertResult = getUpsertResult(true, false); + Database.UpsertResult upsertResult = LoggerMockDataCreator.createDatabaseUpsertResult(true, false); Test.startTest(); @@ -6346,4 +6220,160 @@ private class Logger_Tests { System.assertEquals(log.Id, returnedLog.Id); } // End tests for utility methods + + // Helper methods + static void setUserLoggingLevel(LoggingLevel loggingLevel) { + Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); + } + + static String getMessage() { + return 'Hello, world'; + } + + static LogMessage getLogMessage() { + return new LogMessage('The current user is {0}', getRecord()); + } + + static SObject getRecord() { + return new User( + Id = UserInfo.getUserId(), + ProfileId = UserInfo.getProfileId(), + Username = UserInfo.getUserName(), + UserRoleId = UserInfo.getUserRoleId() + ); + } + + static Exception getException() { + return new DmlException('Example DML Exception'); + } + + static List getDeleteResultList() { + List deleteResults = new List(); + for (Integer i = 0; i < 3; i++) { + deleteResults.add(LoggerMockDataCreator.createDatabaseDeleteResult(true)); + } + return deleteResults; + } + + // TODO only some standard objects can be merged - need to find a way to either mock or trigger a merge result that works in all orgs + // static Database.MergeResult getMergeResult(Boolean isSuccess) { } + + static List getSaveResultList() { + List saveResults = new List(); + for (Integer i = 0; i < 3; i++) { + saveResults.add(LoggerMockDataCreator.createDatabaseSaveResult(true)); + } + return saveResults; + } + + static List getUpsertResultList() { + List upsertresults = new List(); + for (Integer i = 0; i < 3; i++) { + upsertresults.add(LoggerMockDataCreator.createDatabaseUpsertResult(true, true)); + } + return upsertresults; + } + + static List getUndeleteResultList() { + List undeleteResults = new List(); + for (Integer i = 0; i < 3; i++) { + undeleteResults.add(LoggerMockDataCreator.createDatabaseUndeleteResult(true)); + } + return undeleteResults; + } + + static String getOriginLocation() { + String originLocation; + for (String currentStackTraceLine : new DmlException().getStackTraceString().split('\n')) { + if (currentStackTraceLine.contains('Logger_Tests.getOriginLocation')) { + continue; + } + if (currentStackTraceLine.contains('.LogEntryEventBuilder.')) { + continue; + } + if (currentStackTraceLine.contains('.Logger.')) { + continue; + } + originLocation = currentStackTraceLine.substringBefore(':'); + if (originLocation.startsWith('Class.')) { + originLocation = originLocation.substringAfter('Class.'); + } + break; + } + + return originLocation; + } + + public class MockSObjectHandler extends LoggerSObjectHandler { + public Integer executionCount = 0; + public TriggerOperation executedTriggerOperationType; + public List executedTriggerNew; + public Map executedTriggerNewMap; + public Map executedTriggerOldMap; + + private Schema.SObjectType sobjectType; + + public MockSObjectHandler() { + this.sobjectType = Schema.LogEntryEvent__e.SObjectType; + } + + public override SObjectType getSObjectType() { + return this.sobjectType; + } + + public MockSObjectHandler setSObjectType(Schema.SObjectType sobjectType) { + this.sobjectType = sobjectType; + return this; + } + + protected override void executeBeforeInsert(List triggerNew) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.BEFORE_INSERT; + this.executedTriggerNew = triggerNew; + } + + protected override void executeBeforeUpdate(Map triggerNewMap, Map triggerOldMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.BEFORE_UPDATE; + this.executedTriggerNewMap = triggerNewMap; + this.executedTriggerOldMap = triggerOldMap; + } + + protected override void executeBeforeDelete(Map triggerNewMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.BEFORE_DELETE; + this.executedTriggerNewMap = triggerNewMap; + } + + protected override void executeAfterInsert(List triggerNew) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.AFTER_INSERT; + this.executedTriggerNew = triggerNew; + } + + protected override void executeAfterInsert(Map triggerNewMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.AFTER_INSERT; + this.executedTriggerNewMap = triggerNewMap; + } + + protected override void executeAfterUpdate(Map triggerNewMap, Map triggerOldMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.AFTER_UPDATE; + this.executedTriggerNewMap = triggerNewMap; + this.executedTriggerOldMap = triggerOldMap; + } + + protected override void executeAfterDelete(Map triggerNewMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.AFTER_DELETE; + this.executedTriggerNewMap = triggerNewMap; + } + + protected override void executeAfterUndelete(Map triggerNewMap) { + this.executionCount++; + this.executedTriggerOperationType = TriggerOperation.AFTER_UNDELETE; + this.executedTriggerNewMap = triggerNewMap; + } + } } diff --git a/nebula-logger/core/tests/logger-engine/testSuites/LoggerEngine.testSuite-meta.xml b/nebula-logger/core/tests/logger-engine/testSuites/LoggerEngine.testSuite-meta.xml index 37e1afad5..abe4a81d8 100644 --- a/nebula-logger/core/tests/logger-engine/testSuites/LoggerEngine.testSuite-meta.xml +++ b/nebula-logger/core/tests/logger-engine/testSuites/LoggerEngine.testSuite-meta.xml @@ -6,6 +6,9 @@ FlowLogger_Tests FlowRecordLogEntry_Tests LogEntryEventBuilder_Tests + LoggerDataStore_Tests + LoggerSObjectHandler_Tests + LoggerTriggerableContext_Tests Logger_Tests LogMessage_Tests diff --git a/nebula-logger/core/tests/logger-engine/utilities/LoggerMockDataStore.cls b/nebula-logger/core/tests/logger-engine/utilities/LoggerMockDataStore.cls new file mode 100644 index 000000000..0f24e5608 --- /dev/null +++ b/nebula-logger/core/tests/logger-engine/utilities/LoggerMockDataStore.cls @@ -0,0 +1,220 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @group Test Utilities + * @description Utility class used to mock any data-related operations for the database, event bus, and queueable jobs. + * These methods are generic, and should work in any Salesforce org. + * These methods can be used when writing Apex tests for plugins. + * @see LoggerDataStore + * @see LoggerMockDataCreator + * @see LoggerTestConfigurator + */ +@SuppressWarnings('PMD.ApexDoc, PMD.EmptyStatementBlock') +@IsTest +public without sharing class LoggerMockDataStore { + private static final Map> SOBJECT_TYPE_TO_ALL_FIELDS = new Map>(); + private static final Map> SOBJECT_TYPE_TO_REQUIRED_FIELDS = new Map>(); + private static final Map> SOBJECT_TYPE_TO_STRING_FIELDS = new Map>(); + + private static final MockDatabase MOCK_DATABASE_INSTANCE = new MockDatabase(); + private static final MockEventBus MOCK_EVENT_BUS_INSTANCE = new MockEventBus(); + private static final MockJobQueue MOCK_JOB_QUEUE_INSTANCE = new MockJobQueue(); + + public static MockDatabase getDatabase() { + return MOCK_DATABASE_INSTANCE; + } + + public static MockEventBus getEventBus() { + return MOCK_EVENT_BUS_INSTANCE; + } + + public static MockJobQueue getJobQueue() { + return MOCK_JOB_QUEUE_INSTANCE; + } + + public class MockDatabase extends LoggerDataStore.Database { + private MockDatabase() { + } + + public override List insertRecords(List records) { + List mockSaveResults = new List(); + if (records == null || records.isEmpty() == true) { + return mockSaveResults; + } + + // TODO call LoggerSObjectHandler instance using BEFORE_INSERT + // TODO Set mock ID on records + // TODO call LoggerSObjectHandler instance using AFTER_INSERT + for (SObject record : records) { + validateBeforeSave(record, true); + } + + Schema.SObjectType sobjectType = records.get(0).getSObjectType(); + + LoggerTriggerableContext beforeInsertInput = new LoggerTriggerableContext(sobjectType, TriggerOperation.BEFORE_INSERT, records); + LoggerSObjectHandler beforeInsertHandler = LoggerSObjectHandler.getHandler(sobjectType); + beforeInsertHandler?.overrideTriggerableContext(beforeInsertInput).execute(); + + LoggerTriggerableContext afterInsertInput = new LoggerTriggerableContext(sobjectType, TriggerOperation.AFTER_INSERT, records); + LoggerSObjectHandler afterInsertHandler = LoggerSObjectHandler.getHandler(sobjectType); + afterInsertHandler?.overrideTriggerableContext(afterInsertInput).execute(); + + return mockSaveResults; + } + } + + public class MockEventBus extends LoggerDataStore.EventBus { + private List publishedPlatformEvents; + private Integer publishCount; + private MockEventBus() { + this.publishedPlatformEvents = new List(); + this.publishCount = 0; + } + + public Integer getPublishCallCount() { + return this.publishCount; + } + + public List getPublishedPlatformEvents() { + return this.publishedPlatformEvents; + } + + public override Database.SaveResult publishRecord(SObject platformEvent) { + return this.publishRecords(new List{ platformEvent }).get(0); + } + + public override List publishRecords(List platformEvents) { + this.publishCount++; + this.publishedPlatformEvents.addAll(platformEvents); + + List mockSaveResults = new List(); + for (SObject platformEvent : platformEvents) { + mockSaveResults.add(validateBeforeSave(platformEvent, false)); + } + return mockSaveResults; + } + + public void deliver() { + if (this.publishedPlatformEvents.isEmpty() == true) { + return; + } + + Schema.SObjectType sobjectType = this.publishedPlatformEvents.get(0).getSObjectType(); + this.deliver(sobjectType); + } + + public void deliver(Schema.SObjectType sobjectType) { + if (sobjectType == null) { + return; + } + + this.deliver(LoggerSObjectHandler.getHandler(sobjectType)); + } + + public void deliver(LoggerSObjectHandler sobjectHandlerInstance) { + LoggerTriggerableContext platformEventsTriggerContext = new LoggerTriggerableContext( + sobjectHandlerInstance.getSObjectType(), + TriggerOperation.AFTER_INSERT, + this.publishedPlatformEvents + ); + sobjectHandlerInstance?.overrideTriggerableContext(platformEventsTriggerContext).execute(); + } + } + + public class MockJobQueue extends LoggerDataStore.JobQueue { + private List enqueuedJobs; + private Integer publishCount; + private MockJobQueue() { + this.enqueuedJobs = new List(); + } + + public List getEnqueuedJobs() { + return this.enqueuedJobs; + } + + public override Id enqueueJob(Queueable queueableJob) { + this.enqueuedJobs.add(queueableJob); + + return LoggerMockDataCreator.createId(Schema.AsyncApexJob.SObjectType); + } + + public void executeJobs() { + for (Queueable job : this.enqueuedJobs) { + job.execute(null); // TODO create mock instance for System.QueueableContext queueableContext + } + } + } + + private static Database.SaveResult validateBeforeSave(SObject record, Boolean populateMockId) { + // TODO Add checks to ensure: + // 1. All required fields are populated + // 2. All string fields are <= max field length + // 3. Any restricted picklists have a valid value set + Boolean recordIsValid = true; + loadFields(record.getSObjectType()); + validateRequiredFieldsArePopulated(record); + validateStringFieldsAreNotTooLong(record); + + if (recordIsValid == true && populateMockId == true) { + record.Id = LoggerMockDataCreator.createId(record.getSObjectType()); + } + return LoggerMockDataCreator.createDatabaseSaveResult(recordIsValid, record.Id); + } + + private static void validateRequiredFieldsArePopulated(SObject record) { + Schema.SObjectType sobjectType = record.getSObjectType(); + for (Schema.SObjectField requiredField : SOBJECT_TYPE_TO_REQUIRED_FIELDS.get(sobjectType)) { + if (requiredField.getDescribe().getSoapType() == Schema.SoapType.BOOLEAN) { + continue; + } + + Boolean recordHasField = record.getPopulatedFieldsAsMap().containsKey(requiredField.getDescribe().getName()); + Boolean recordHasFieldValue = record.get(requiredField) != null; + if (recordHasField == false || recordHasFieldValue == false) { + SObjectException ex = new SObjectException(); + ex.setMessage('The field ' + requiredField + ' is required on record: ' + JSON.serializePretty(record)); + throw ex; + } + } + } + + private static void validateStringFieldsAreNotTooLong(SObject record) { + Schema.SObjectType sobjectType = record.getSObjectType(); + for (Schema.SObjectField stringField : SOBJECT_TYPE_TO_STRING_FIELDS.get(sobjectType)) { + Boolean isFieldValueTooLong = ((String) record.get(stringField))?.length() > stringField.getDescribe().getLength(); + if (isFieldValueTooLong == true) { + SObjectException ex = new SObjectException(); + ex.setMessage('The field value for ' + stringField + ' is too long: ' + record.get(stringField)); + throw ex; + } + } + } + + private static void loadFields(Schema.SObjectType sobjectType) { + if (SOBJECT_TYPE_TO_ALL_FIELDS.containsKey(sobjectType) == true && SOBJECT_TYPE_TO_REQUIRED_FIELDS.containsKey(sobjectType) == true) { + return; + } + + SOBJECT_TYPE_TO_ALL_FIELDS.put(sobjectType, new List()); + SOBJECT_TYPE_TO_REQUIRED_FIELDS.put(sobjectType, new List()); + SOBJECT_TYPE_TO_STRING_FIELDS.put(sobjectType, new List()); + for (Schema.SObjectField field : sobjectType.getDescribe().fields.getMap().values()) { + if (field.getDescribe().isCreateable() == false) { + continue; + } + + SOBJECT_TYPE_TO_ALL_FIELDS.get(sobjectType).add(field); + if (field.getDescribe().getSoapType() == Schema.SoapType.STRING) { + SOBJECT_TYPE_TO_STRING_FIELDS.get(sobjectType).add(field); + } + + if (field.getDescribe().isNillable() == false) { + // If a field is not nillable & it is createable, then it's required + SOBJECT_TYPE_TO_REQUIRED_FIELDS.get(sobjectType).add(field); + } + } + } +} diff --git a/nebula-logger/core/tests/logger-engine/utilities/LoggerMockDataStore.cls-meta.xml b/nebula-logger/core/tests/logger-engine/utilities/LoggerMockDataStore.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/core/tests/logger-engine/utilities/LoggerMockDataStore.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/core/tests/plugin-framework/classes/LoggerSObjectHandlerPlugin_Tests.cls b/nebula-logger/core/tests/plugin-framework/classes/LoggerSObjectHandlerPlugin_Tests.cls deleted file mode 100644 index 18ca544ad..000000000 --- a/nebula-logger/core/tests/plugin-framework/classes/LoggerSObjectHandlerPlugin_Tests.cls +++ /dev/null @@ -1,43 +0,0 @@ -//------------------------------------------------------------------------------------------------// -// This file is part of the Nebula Logger project, released under the MIT License. // -// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // -//------------------------------------------------------------------------------------------------// - -@SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest -private class LoggerSObjectHandlerPlugin_Tests { - private static final String PLUGIN_LOG_STATUS = 'On Hold'; - - public class ExamplePlugin extends LoggerSObjectHandlerPlugin { - public override void execute( - TriggerOperation triggerOperationType, - List triggerNew, - Map triggerNewMap, - List triggerOld, - Map triggerOldMap - ) { - switch on triggerOperationType { - when BEFORE_INSERT { - for (Log__c log : (List) triggerNew) { - log.Status__c = PLUGIN_LOG_STATUS; - } - } - } - } - } - - @IsTest - static void it_should_execute_plugin_logic() { - Log__c log = new Log__c(TransactionId__c = '1234'); - System.assertEquals(null, log.Status__c); - - Test.startTest(); - - ExamplePlugin plugin = new ExamplePlugin(); - plugin.execute(triggerOperation.BEFORE_INSERT, new List{ log }, null, null, null); - - Test.stopTest(); - - System.assertEquals(PLUGIN_LOG_STATUS, log.Status__c); - } -} diff --git a/nebula-logger/core/tests/plugin-framework/testSuites/LoggerPluginFramework.testSuite-meta.xml b/nebula-logger/core/tests/plugin-framework/testSuites/LoggerPluginFramework.testSuite-meta.xml deleted file mode 100644 index a771fcaeb..000000000 --- a/nebula-logger/core/tests/plugin-framework/testSuites/LoggerPluginFramework.testSuite-meta.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - LoggerParameter_Tests - LoggerSObjectHandlerPlugin_Tests - diff --git a/nebula-logger/extra-tests/flows/LogHandler_Tests_Flow.flow-meta.xml b/nebula-logger/extra-tests/flows/LogHandler_Tests_Flow.flow-meta.xml deleted file mode 100644 index 8ea80e029..000000000 --- a/nebula-logger/extra-tests/flows/LogHandler_Tests_Flow.flow-meta.xml +++ /dev/null @@ -1,213 +0,0 @@ - - - - Log_user_after_updating - - 176 - 638 - FlowRecordLogEntry - apex - - T__record - User - - CurrentTransaction - - loggingLevelName - - INFO - - - - saveLog - - true - - - - tagsString - - flow tag - - - - flowName - - LogHandler_Tests_Flow - - - - message - - Logging user after updating - - - - record - - Get_current_user - - - true - - - Log_user_before_updating - - 176 - 278 - FlowRecordLogEntry - apex - - Update_user_s_first_name - - - T__record - User - - CurrentTransaction - - loggingLevelName - - INFO - - - - tagsString - - flow tag - - - - flowName - - LogHandler_Tests_Flow - - - - message - - Logging user before updating - - - - record - - Get_current_user - - - true - - 54.0 - - Update_user_s_first_name - - 176 - 398 - - Get_current_user.FirstName - Assign - - Logger-Flow-Test - - - - Save_current_user - - - An additional Flow used test dynamically running Flow plugins from LoggerSObjectHandler - LogHandler_Tests_Flow {!$Flow.CurrentDateTime} - - - BuilderType - - LightningFlowBuilder - - - - CanvasMode - - AUTO_LAYOUT_CANVAS - - - - OriginBuilderType - - LightningFlowBuilder - - - AutoLaunchedFlow - - Get_current_user - - 176 - 158 - false - - Log_user_before_updating - - and - - Id - EqualTo - - $User.Id - - - true - User - true - - - Save_current_user - - 176 - 518 - - Log_user_after_updating - - Get_current_user - - DefaultMode - - 50 - 0 - - Get_current_user - - - Active - - Used by test class to verify that the Flow ran successfully - ranSuccessfully - Boolean - false - false - true - - false - - - - records - SObject - true - true - false - Log__c - - - triggerOld - SObject - true - true - false - Log__c - - - triggerOperationType - String - false - true - false - - diff --git a/nebula-logger/extra-tests/flows/MockLogBatchPurgerPlugin.flow-meta.xml b/nebula-logger/extra-tests/flows/MockLogBatchPurgerPlugin.flow-meta.xml new file mode 100644 index 000000000..6a204ed9b --- /dev/null +++ b/nebula-logger/extra-tests/flows/MockLogBatchPurgerPlugin.flow-meta.xml @@ -0,0 +1,70 @@ + + + 54.0 + + Assign_example_value_0 + + 176 + 158 + + someExampleVariable + Assign + + Hello, world + + + + Example Flow used to test plugin functionality within Nebula Logger's batch cleanup job, LogBatchPurger + Mock Log Batch Purger Plugin {!$Flow.CurrentDateTime} + + + BuilderType + + LightningFlowBuilder + + + + CanvasMode + + AUTO_LAYOUT_CANVAS + + + + OriginBuilderType + + LightningFlowBuilder + + + AutoLaunchedFlow + + 50 + 0 + + Assign_example_value_0 + + + Draft + + pluginConfiguration + SObject + false + true + true + LoggerPlugin__mdt + + + pluginInput + LoggerBatchableContext + Apex + false + true + true + + + someExampleVariable + String + false + false + true + + diff --git a/nebula-logger/extra-tests/flows/MockLoggerSObjectHandlerPlugin.flow-meta.xml b/nebula-logger/extra-tests/flows/MockLoggerSObjectHandlerPlugin.flow-meta.xml new file mode 100644 index 000000000..60fc05532 --- /dev/null +++ b/nebula-logger/extra-tests/flows/MockLoggerSObjectHandlerPlugin.flow-meta.xml @@ -0,0 +1,70 @@ + + + 54.0 + + Assign_example_value_0 + + 176 + 158 + + someExampleVariable + Assign + + Hello, world + + + + Example Flow used to test plugin functionality within Nebula Logger's trigger handle framework class, LoggerSObjectHandler + Mock Logger SObject Handler Plugin {!$Flow.CurrentDateTime} + + + BuilderType + + LightningFlowBuilder + + + + CanvasMode + + AUTO_LAYOUT_CANVAS + + + + OriginBuilderType + + LightningFlowBuilder + + + AutoLaunchedFlow + + 50 + 0 + + Assign_example_value_0 + + + Active + + pluginConfiguration + SObject + false + true + true + LoggerPlugin__mdt + + + pluginInput + LoggerTriggerableContext + Apex + false + true + true + + + someExampleVariable + String + false + false + true + + diff --git a/nebula-logger/extra-tests/tests/LogBatchPurger_Tests_Flow.cls b/nebula-logger/extra-tests/tests/LogBatchPurger_Tests_Flow.cls new file mode 100644 index 000000000..14be25fdc --- /dev/null +++ b/nebula-logger/extra-tests/tests/LogBatchPurger_Tests_Flow.cls @@ -0,0 +1,208 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +@SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') +@IsTest(IsParallel=false) +private class LogBatchPurger_Tests_Flow { + // This Flow simply returns a string variable called 'someExampleVariable' + // that's used in tests below to verify if the Flow was dynamically executed + private static final String MOCK_FLOW_NAME = 'MockLogBatchPurgerPlugin'; + private static final String MOCK_FLOW_OUTPUT_VARIABLE_NAME = 'someExampleVariable'; + private static final String MOCK_FLOW_OUTPUT_VARIABLE_VALUE = 'Hello, world'; + + private static final Integer NUMBER_OF_LOG_ENTRIES_TO_CREATE = 10; + + @TestSetup + static void setupData() { + LoggerSObjectHandler.shouldExecute(false); + LoggerSettings__c settings = Logger.getUserSettings(); + settings.IsEnabled__c = false; + settings.LoggingLevel__c = LoggingLevel.FINEST.name(); + insert settings; + + Date scheduledDeletionDate = System.today().addDays(-7); + Log__c log = new Log__c(LogRetentionDate__c = scheduledDeletionDate); + LoggerMockDataCreator.createDataBuilder(log).populateRequiredFields().getRecord(); + insert log; + + List logEntries = new List(); + for (Integer i = 0; i < NUMBER_OF_LOG_ENTRIES_TO_CREATE; i++) { + LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, LoggingLevel__c = LoggingLevel.INFO.name()); + LoggerMockDataCreator.createDataBuilder(logEntry).populateRequiredFields().getRecord(); + logEntries.add(logEntry); + } + insert logEntries; + + LoggerTag__c tag = (LoggerTag__c) LoggerMockDataCreator.createDataBuilder(Schema.LoggerTag__c.SObjectType).populateRequiredFields().getRecord(); + insert tag; + + List logEntryTags = new List(); + for (LogEntry__c logEntry : logEntries) { + LogEntryTag__c logEntryTag = new LogEntryTag__c(LogEntry__c = logEntry.Id, Tag__c = tag.Id); + LoggerMockDataCreator.createDataBuilder(logEntryTag).populateRequiredFields().getRecord(); + logEntryTags.add(logEntryTag); + } + insert logEntryTags; + } + + @IsTest + static void it_should_run_flow_plugin_in_start_method() { + LoggerSObjectHandler.shouldExecute(false); + LoggerPlugin__mdt mockPluginConfiguration = new LoggerPlugin__mdt( + BatchPurgerExecutionOrder__c = 1, + BatchPurgerFlowName__c = MOCK_FLOW_NAME, + DeveloperName = 'Mock_Plugin', + IsEnabled__c = true + ); + LoggerTestConfigurator.setMock(mockPluginConfiguration); + LogBatchPurger batchJobInstance = new LogBatchPurger(); + batchJobInstance.currentSObjectType = Schema.LogEntry__c.SObjectType; + Database.BatchableContext mockBatchableContext = LoggerMockDataCreator.createBatchableContext('some_fake_job_id'); + + batchJobInstance.start(mockBatchableContext); + + LoggerBatchableContext expectedInput = new LoggerBatchableContext(mockBatchableContext, batchJobInstance.currentSObjectType); + System.assertEquals( + 3, + batchJobInstance.getExecutedFlowPlugins().size(), + 'The map of executed Flow plugins should have 3 keys - one for each enum value in LogBatchPurger.BatchableMethod (START, EXECUTE, and FINISH)' + ); + System.assertEquals( + 1, + batchJobInstance.getExecutedFlowPlugins().get(LogBatchPurger.BatchableMethod.START).size(), + 'One Flow plugin should have run in the batch job\'s start method' + ); + System.assertEquals( + 0, + batchJobInstance.getExecutedFlowPlugins().get(LogBatchPurger.BatchableMethod.EXECUTE).size(), + 'No Flow plugins should have run in the batch job\'s execute method' + ); + System.assertEquals( + 0, + batchJobInstance.getExecutedFlowPlugins().get(LogBatchPurger.BatchableMethod.FINISH).size(), + 'No Flow plugins should have run in the batch job\'s finish method' + ); + Flow.Interview flowStartPlugin = batchJobInstance.getExecutedFlowPlugins().get(LogBatchPurger.BatchableMethod.START).get(0); + LoggerPlugin__mdt returnedPluginConfiguration = (LoggerPlugin__mdt) flowStartPlugin.getVariableValue('pluginConfiguration'); + System.assertEquals(mockPluginConfiguration, returnedPluginConfiguration, 'LoggerPlugin__mdt records should match'); + LoggerBatchableContext returnedPluginInput = (LoggerBatchableContext) flowStartPlugin.getVariableValue('pluginInput'); + System.assertEquals(JSON.serialize(expectedInput), JSON.serialize(returnedPluginInput), 'Plugin inputs should match'); + System.assertEquals( + MOCK_FLOW_OUTPUT_VARIABLE_VALUE, + flowStartPlugin.getVariableValue(MOCK_FLOW_OUTPUT_VARIABLE_NAME), + 'Flow should have returned the variable ' + + MOCK_FLOW_OUTPUT_VARIABLE_NAME + + ' with the value + ' + + MOCK_FLOW_OUTPUT_VARIABLE_VALUE + ); + } + + @IsTest + static void it_should_run_flow_plugin_in_execute_method() { + LoggerSObjectHandler.shouldExecute(false); + LoggerPlugin__mdt mockPluginConfiguration = new LoggerPlugin__mdt( + BatchPurgerExecutionOrder__c = 1, + BatchPurgerFlowName__c = MOCK_FLOW_NAME, + DeveloperName = 'Mock_Plugin', + IsEnabled__c = true + ); + LoggerTestConfigurator.setMock(mockPluginConfiguration); + LogBatchPurger batchJobInstance = new LogBatchPurger(); + List logsToDelete = [SELECT Id FROM Log__c]; + System.assertNotEquals(0, logsToDelete.size()); + Database.BatchableContext mockBatchableContext = LoggerMockDataCreator.createBatchableContext('some_fake_job_id'); + + batchJobInstance.execute(mockBatchableContext, logsToDelete); + + LoggerBatchableContext expectedInput = new LoggerBatchableContext(mockBatchableContext, batchJobInstance.currentSObjectType); + System.assertEquals( + 3, + batchJobInstance.getExecutedFlowPlugins().size(), + 'The map of executed Flow plugins should have 3 keys - one for each enum value in LogBatchPurger.BatchableMethod (START, EXECUTE, and FINISH)' + ); + System.assertEquals( + 0, + batchJobInstance.getExecutedFlowPlugins().get(LogBatchPurger.BatchableMethod.START).size(), + 'No Flow plugins should have run in the batch job\'s start method' + ); + System.assertEquals( + 1, + batchJobInstance.getExecutedFlowPlugins().get(LogBatchPurger.BatchableMethod.EXECUTE).size(), + 'One Flow plugin should have run in the batch job\'s execute method' + ); + System.assertEquals( + 0, + batchJobInstance.getExecutedFlowPlugins().get(LogBatchPurger.BatchableMethod.FINISH).size(), + 'No Flow plugins should have run in the batch job\'s finish method' + ); + Flow.Interview flowExecutePlugin = batchJobInstance.getExecutedFlowPlugins().get(LogBatchPurger.BatchableMethod.EXECUTE).get(0); + LoggerPlugin__mdt returnedPluginConfiguration = (LoggerPlugin__mdt) flowExecutePlugin.getVariableValue('pluginConfiguration'); + System.assertEquals(mockPluginConfiguration, returnedPluginConfiguration, 'LoggerPlugin__mdt records should match'); + LoggerBatchableContext returnedPluginInput = (LoggerBatchableContext) flowExecutePlugin.getVariableValue('pluginInput'); + System.assertEquals(JSON.serialize(expectedInput), JSON.serialize(returnedPluginInput), 'Plugin inputs should match'); + System.assertEquals( + MOCK_FLOW_OUTPUT_VARIABLE_VALUE, + flowExecutePlugin.getVariableValue(MOCK_FLOW_OUTPUT_VARIABLE_NAME), + 'Flow should have returned the variable ' + + MOCK_FLOW_OUTPUT_VARIABLE_NAME + + ' with the value + ' + + MOCK_FLOW_OUTPUT_VARIABLE_VALUE + ); + } + + // FIXME this method consistently fails inconsistently, sometimes with a GACK, but appears to work when manually testing it. I'll revisit it a future release. + // @IsTest + // static void it_should_run_flow_plugin_in_finish_method() { + // LoggerSObjectHandler.shouldExecute(false); + // LoggerPlugin__mdt mockPluginConfiguration = new LoggerPlugin__mdt( + // BatchPurgerExecutionOrder__c = 1, + // BatchPurgerFlowName__c = MOCK_FLOW_NAME, + // DeveloperName = 'Mock_Plugin', + // IsEnabled__c = true + // ); + // LoggerTestConfigurator.setMock(mockPluginConfiguration); + // LogBatchPurger batchJobInstance = new LogBatchPurger(); + // List logsToDelete = [SELECT Id FROM Log__c]; + // System.assertNotEquals(0, logsToDelete.size(), 'There should be some records to delete'); + // Database.BatchableContext mockBatchableContext = LoggerMockDataCreator.createBatchableContext('some_fake_job_id'); + + // batchJobInstance.finish(mockBatchableContext); + + // LoggerBatchableContext expectedInput = new LoggerBatchableContext(mockBatchableContext, batchJobInstance.currentSObjectType); + // System.assertEquals( + // 3, + // batchJobInstance.getExecutedFlowPlugins().size(), + // 'The map of executed Flow plugins should have 3 keys - one for each enum value in LogBatchPurger.BatchableMethod (START, EXECUTE, and FINISH)' + // ); + // System.assertEquals( + // 0, + // batchJobInstance.getExecutedFlowPlugins().get(LogBatchPurger.BatchableMethod.START).size(), + // 'No Flow plugins should have run in the batch job\'s start method' + // ); + // System.assertEquals( + // 0, + // batchJobInstance.getExecutedFlowPlugins().get(LogBatchPurger.BatchableMethod.EXECUTE).size(), + // 'No Flow plugins should have run in the batch job\'s execute method' + // ); + // System.assertEquals( + // 1, + // batchJobInstance.getExecutedFlowPlugins().get(LogBatchPurger.BatchableMethod.FINISH).size(), + // 'One Flow plugin should have run in the batch job\'s finish method' + // ); + // Flow.Interview flowFinishPlugin = batchJobInstance.getExecutedFlowPlugins().get(LogBatchPurger.BatchableMethod.FINISH).get(0); + // LoggerPlugin__mdt returnedPluginConfiguration = (LoggerPlugin__mdt) flowFinishPlugin.getVariableValue('pluginConfiguration'); + // System.assertEquals(mockPluginConfiguration, returnedPluginConfiguration, 'LoggerPlugin__mdt records should match'); + // LoggerBatchableContext returnedPluginInput = (LoggerBatchableContext) flowFinishPlugin.getVariableValue('pluginInput'); + // System.assertEquals(JSON.serialize(expectedInput), JSON.serialize(returnedPluginInput), 'Plugin inputs should match'); + // System.assertEquals( + // MOCK_FLOW_OUTPUT_VARIABLE_VALUE, + // flowFinishPlugin.getVariableValue(MOCK_FLOW_OUTPUT_VARIABLE_NAME), + // 'Flow should have returned the variable ' + + // MOCK_FLOW_OUTPUT_VARIABLE_NAME + + // ' with the value + ' + + // MOCK_FLOW_OUTPUT_VARIABLE_VALUE + // ); + // } +} diff --git a/nebula-logger/extra-tests/tests/LogBatchPurger_Tests_Flow.cls-meta.xml b/nebula-logger/extra-tests/tests/LogBatchPurger_Tests_Flow.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/extra-tests/tests/LogBatchPurger_Tests_Flow.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/extra-tests/tests/LogBatchPurger_Tests_Integration.cls b/nebula-logger/extra-tests/tests/LogBatchPurger_Tests_Integration.cls index 459cfa80e..e505762a9 100644 --- a/nebula-logger/extra-tests/tests/LogBatchPurger_Tests_Integration.cls +++ b/nebula-logger/extra-tests/tests/LogBatchPurger_Tests_Integration.cls @@ -43,7 +43,7 @@ private class LogBatchPurger_Tests_Integration { static void it_should_throw_exception_when_user_does_not_have_delete_access() { Integer originalCountOfLogEntries = [SELECT COUNT() FROM LogEntry__c]; - User standardUser = LoggerTestUtils.createUser(STANDARD_USER_PROFILE.Id); + User standardUser = LoggerMockDataCreator.createUser(STANDARD_USER_PROFILE.Id); System.runAs(standardUser) { System.assertEquals(false, Schema.Log__c.SObjectType.getDescribe().isDeletable()); diff --git a/nebula-logger/extra-tests/tests/LogEntryEventBuilder_Tests_Integration.cls b/nebula-logger/extra-tests/tests/LogEntryEventBuilder_Tests_Integration.cls index a01cf8ed1..9484f4bf7 100644 --- a/nebula-logger/extra-tests/tests/LogEntryEventBuilder_Tests_Integration.cls +++ b/nebula-logger/extra-tests/tests/LogEntryEventBuilder_Tests_Integration.cls @@ -4,20 +4,17 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=false) private class LogEntryEventBuilder_Tests_Integration { private static final Profile STANDARD_USER_PROFILE = [SELECT Id FROM Profile WHERE Name IN ('Standard User', 'Usuario estándar')]; @IsTest static void stripInaccessibleFieldsForRecordWhenEnabled() { - User standardUser = LoggerTestUtils.createUser(STANDARD_USER_PROFILE.Id); - AccountBrand mockAccountBrand = new AccountBrand( - Id = LoggerTestUtils.createMockId(Schema.AccountBrand.SObjectType), - CompanyName = 'Some Company, Inc.', - Email = 'some.one@some.company.com', - Name = 'Something', - Phone = '510-555-1234' - ); + User standardUser = LoggerMockDataCreator.createUser(STANDARD_USER_PROFILE.Id); + AccountBrand mockAccountBrand = (AccountBrand) LoggerMockDataCreator.createDataBuilder(Schema.AccountBrand.SObjectType) + .populateMockId() + .populateRequiredFields() + .getRecord(); // The 'standard user' profile doesn't have access to AccountBrand, // so stripAccessible will remove everything except the ID field AccountBrand strippedAccountBrand = new AccountBrand(Id = mockAccountBrand.Id); @@ -44,17 +41,14 @@ private class LogEntryEventBuilder_Tests_Integration { @IsTest static void stripInaccessibleFieldsForRecordsWhenEnabled() { - User standardUser = LoggerTestUtils.createUser(STANDARD_USER_PROFILE.Id); + User standardUser = LoggerMockDataCreator.createUser(STANDARD_USER_PROFILE.Id); List mockAccountBrands = new List(); List strippedAccountBrands = new List(); for (Integer i = 0; i < 5; i++) { - AccountBrand mockAccountBrand = new AccountBrand( - Id = LoggerTestUtils.createMockId(Schema.AccountBrand.SObjectType), - CompanyName = 'Some Company, Inc.', - Email = 'some.one.number_' + i + '@some.company.com', - Name = 'Something', - Phone = '510-555-1234' - ); + AccountBrand mockAccountBrand = (AccountBrand) LoggerMockDataCreator.createDataBuilder(Schema.AccountBrand.SObjectType) + .populateMockId() + .populateRequiredFields() + .getRecord(); mockAccountBrands.add(mockAccountBrand); // The 'standard user' profile doesn't have access to AccountBrand, diff --git a/nebula-logger/extra-tests/tests/LogEntryHandler_Tests_Flow.cls b/nebula-logger/extra-tests/tests/LogEntryHandler_Tests_Flow.cls index b94531ded..bfa888bdb 100644 --- a/nebula-logger/extra-tests/tests/LogEntryHandler_Tests_Flow.cls +++ b/nebula-logger/extra-tests/tests/LogEntryHandler_Tests_Flow.cls @@ -4,7 +4,7 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class LogEntryHandler_Tests_Flow { private static final String EXAMPLE_FLOW_API_NAME = 'LogEntryHandler_Tests_Flow'; @@ -12,10 +12,12 @@ private class LogEntryHandler_Tests_Flow { static void setSkipSettingFlowDetailsWhenOriginLocationIsNull() { Log__c log = new Log__c(TransactionId__c = '1234'); insert log; + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, OriginLocation__c = null, OriginType__c = 'Flow'); + insert logEntry; - logEntry = getLogEntry(); + logEntry = getLogEntry(); System.assertEquals(null, logEntry.OriginLocation__c, 'Origin Location was not null.'); System.assertEquals('Flow', logEntry.OriginType__c, 'Origin Type was not equal to Flow.'); System.assertEquals(null, logEntry.FlowActiveVersionId__c, 'FlowActiveVersionId was not null.'); @@ -35,13 +37,14 @@ private class LogEntryHandler_Tests_Flow { static void setFlowDetails() { FlowDefinitionView flowDefinition = getFlowDefinition(); FlowVersionView flowVersion = getFlowVersion(flowDefinition.ActiveVersionId); - Log__c log = new Log__c(TransactionId__c = '1234'); insert log; + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, OriginLocation__c = flowDefinition.ApiName, OriginType__c = 'Flow'); + insert logEntry; - logEntry = getLogEntry(); + logEntry = getLogEntry(); System.assertEquals('Flow', logEntry.OriginType__c, 'OriginType was not flow.'); System.assertEquals(flowDefinition.ActiveVersionId, logEntry.FlowActiveVersionId__c, 'FlowActiveVersionId was incorrect.'); System.assertEquals(flowDefinition.Description, logEntry.FlowDescription__c, 'FlowDescription was incorrect.'); diff --git a/nebula-logger/extra-tests/tests/LogEntryHandler_Tests_Integration.cls b/nebula-logger/extra-tests/tests/LogEntryHandler_Tests_Integration.cls new file mode 100644 index 000000000..a817f03f9 --- /dev/null +++ b/nebula-logger/extra-tests/tests/LogEntryHandler_Tests_Integration.cls @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +@SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') +@IsTest(IsParallel=true) +private class LogEntryHandler_Tests_Integration { + @IsTest + static void it_should_populate_related_record_name_field_on_log_entry_with_email_message_subject() { + System.assertEquals( + false, + Schema.EmailMessage.Subject.getDescribe().isNameField(), + 'This test assumes that EmailMessage does not use Subject as the object\'s display-name field' + ); + Case cas = (Case) LoggerMockDataCreator.createDataBuilder(Schema.Case.SObjectType).populateRequiredFields().getRecord(); + insert cas; + EmailMessage emailMessage = (EmailMessage) LoggerMockDataCreator.createDataBuilder(new EmailMessage(Subject = 'Some subject', ParentId = cas.Id)) + .populateRequiredFields() + .getRecord(); + insert emailMessage; + Log__c log = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); + insert log; + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, RecordId__c = emailMessage.Id); + + insert logEntry; + + logEntry = [SELECT Id, RecordId__c, RecordName__c FROM LogEntry__c WHERE Id = :logEntry.Id]; + System.assertEquals(emailMessage.Id, logEntry.RecordId__c); + System.assertEquals(emailMessage.Subject, logEntry.RecordName__c); + } +} diff --git a/nebula-logger/extra-tests/tests/LogEntryHandler_Tests_Integration.cls-meta.xml b/nebula-logger/extra-tests/tests/LogEntryHandler_Tests_Integration.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/extra-tests/tests/LogEntryHandler_Tests_Integration.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/extra-tests/tests/LogHandler_Tests_Flow.cls b/nebula-logger/extra-tests/tests/LogHandler_Tests_Flow.cls deleted file mode 100644 index 5d388ed32..000000000 --- a/nebula-logger/extra-tests/tests/LogHandler_Tests_Flow.cls +++ /dev/null @@ -1,33 +0,0 @@ -//------------------------------------------------------------------------------------------------// -// This file is part of the Nebula Logger project, released under the MIT License. // -// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // -//------------------------------------------------------------------------------------------------// - -@SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest -private class LogHandler_Tests_Flow { - @IsTest - static void runFlowPluginWhenConfigured() { - // Assumption: the Flow LogHandler_Tests_Flow makes an update to the current user's FirstName - // The specific action within the Flow isn't that important - we just want to make sure - // that that Flow is dynamically executed - String pluginFlowApiName = 'LogHandler_Tests_Flow'; - String expectedUserFirstName = 'Logger-Flow-Test'; - System.assertNotEquals(expectedUserFirstName, UserInfo.getFirstName(), 'Current user first name did not match expected user first name.'); - - Test.startTest(); - - // Use the mock configurations - LoggerPlugin__mdt plugin = new LoggerPlugin__mdt(PluginType__c = 'Flow', PluginApiName__c = pluginFlowApiName); - LoggerSObjectHandler.setMockPlugin(Schema.Log__c.SObjectType, plugin); - - Log__c log = new Log__c(TransactionId__c = '1234'); - insert log; - - Test.stopTest(); - - // Verify that the Flow ran by checking if the user's FirstName was updated - User currentUser = [SELECT Id, FirstName FROM User WHERE Id = :UserInfo.getUserId()]; - System.assertEquals(expectedUserFirstName, currentUser.FirstName, 'Current user FirstName did not match expected user first name.'); - } -} diff --git a/nebula-logger/extra-tests/tests/LogMassDeleteExtension_Tests_Integration.cls b/nebula-logger/extra-tests/tests/LogMassDeleteExtension_Tests_Integration.cls index ddc5fb085..0087b86c7 100644 --- a/nebula-logger/extra-tests/tests/LogMassDeleteExtension_Tests_Integration.cls +++ b/nebula-logger/extra-tests/tests/LogMassDeleteExtension_Tests_Integration.cls @@ -4,12 +4,14 @@ //------------------------------------------------------------------------------------------------// @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=false) private class LogMassDeleteExtension_Tests_Integration { private static final Profile STANDARD_USER_PROFILE = [SELECT Id FROM Profile WHERE Name IN ('Standard User', 'Usuario estándar')]; @TestSetup static void setupData() { + LoggerSObjectHandler.shouldExecute(false); + List logs = new List(); for (Integer i = 0; i < 10; i++) { Log__c log = new Log__c(TransactionId__c = 'TXN-' + i); @@ -31,21 +33,17 @@ private class LogMassDeleteExtension_Tests_Integration { logsToKeep.add(logs.get(i)); } } - ApexPages.StandardSetController controller = new ApexPages.StandardSetController(logs); controller.setSelected(logsToDelete); - PageReference pageReference = Page.LogMassDelete; Test.setCurrentPage(pageReference); - - User standardUser = LoggerTestUtils.createUser(STANDARD_USER_PROFILE.Id); + User standardUser = LoggerMockDataCreator.createUser(STANDARD_USER_PROFILE.Id); System.runAs(standardUser) { System.assertEquals(false, Schema.Log__c.SObjectType.getDescribe().isDeletable()); - String deleteAccessError = 'You do not have access to delete logs records'; - new LogMassDeleteExtension(controller); + String deleteAccessError = 'You do not have access to delete logs records'; System.assertEquals(true, ApexPages.hasMessages(ApexPages.SEVERITY.ERROR)); System.assertEquals(deleteAccessError, ApexPages.getMessages().get(0).getSummary()); } diff --git a/nebula-logger/extra-tests/tests/LoggerSObjectHandler_Tests_Flow.cls b/nebula-logger/extra-tests/tests/LoggerSObjectHandler_Tests_Flow.cls new file mode 100644 index 000000000..3855b4ada --- /dev/null +++ b/nebula-logger/extra-tests/tests/LoggerSObjectHandler_Tests_Flow.cls @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +@SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') +@IsTest(IsParallel=true) +private class LoggerSObjectHandler_Tests_Flow { + // This Flow simply returns a string variable called 'someExampleVariable' + // that's used in tests below to verify if the Flow was dynamically executed + private static final String MOCK_FLOW_NAME = 'MockLoggerSObjectHandlerPlugin'; + private static final String MOCK_FLOW_OUTPUT_VARIABLE_VALUE = 'Hello, world'; + + @IsTest + static void it_should_execute_flow_plugin() { + LoggerPlugin__mdt mockPluginConfiguration = new LoggerPlugin__mdt( + DeveloperName = 'ExampleFlowPlugin', + IsEnabled__c = true, + SObjectHandlerFlowName__c = MOCK_FLOW_NAME + ); + LoggerTestConfigurator.setMock(mockPluginConfiguration); + MockLogHandler mockHandler = new MockLogHandler(); + mockHandler.triggerOperationType = TriggerOperation.BEFORE_INSERT; + mockHandler.triggerNew = new List{ new Log__c(TransactionId__c = '1234') }; + mockHandler.triggerNewMap = null; + mockHandler.triggerOldMap = null; + + mockHandler.execute(); + + System.assertEquals(1, mockHandler.getPluginConfigurations().size(), mockHandler.getPluginConfigurations()); + System.assertEquals(1, mockHandler.getExecutedFlowPlugins().size(), mockHandler.getExecutedFlowPlugins()); + Flow.Interview executedFlowPlugin = mockHandler.getExecutedFlowPlugins().get(0); + System.assertEquals(mockPluginConfiguration, executedFlowPlugin.getVariableValue('pluginConfiguration')); + System.assertEquals(mockHandler.input, executedFlowPlugin.getVariableValue('pluginInput')); + System.assertEquals(MOCK_FLOW_OUTPUT_VARIABLE_VALUE, executedFlowPlugin.getVariableValue('someExampleVariable')); + } + + private class MockLogHandler extends LoggerSObjectHandler { + public override SObjectType getSObjectType() { + return Schema.Log__c.SObjectType; + } + } +} diff --git a/nebula-logger/extra-tests/tests/LoggerSObjectHandler_Tests_Flow.cls-meta.xml b/nebula-logger/extra-tests/tests/LoggerSObjectHandler_Tests_Flow.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/extra-tests/tests/LoggerSObjectHandler_Tests_Flow.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/extra-tests/tests/LoggerSettingsController_Tests_Security.cls b/nebula-logger/extra-tests/tests/LoggerSettingsController_Tests_Security.cls index 78b904890..7396961a2 100644 --- a/nebula-logger/extra-tests/tests/LoggerSettingsController_Tests_Security.cls +++ b/nebula-logger/extra-tests/tests/LoggerSettingsController_Tests_Security.cls @@ -10,14 +10,14 @@ * ...from within the normal tests, and each org might have additional required fields, VR, etc on the std objects */ @SuppressWarnings('PMD.ApexDoc, PMD.MethodNamingConventions') -@IsTest +@IsTest(IsParallel=false) private class LoggerSettingsController_Tests_Security { private static final String CAN_MODIFY_LOGGER_SETTINGS_PERMISSION_NAME = 'CanModifyLoggerSettings'; private static final Profile STANDARD_USER_PROFILE = [SELECT Id FROM Profile WHERE Name IN ('Standard User', 'Usuario estándar')]; @IsTest static void it_should_permit_user_to_modify_logger_settings_when_custom_permission_is_assigned() { - User standardUser = LoggerTestUtils.createUser(STANDARD_USER_PROFILE.Id); + User standardUser = LoggerMockDataCreator.createUser(STANDARD_USER_PROFILE.Id); insert standardUser; PermissionSet permissionSet = new PermissionSet(Name = 'CustomPermissionEnabled', Label = 'Custom Permisison Enabled'); insert permissionSet; @@ -37,9 +37,9 @@ private class LoggerSettingsController_Tests_Security { @IsTest static void it_should_permit_user_to_modify_logger_settings_when_loggerAdmin_permission_set_is_assigned() { - User standardUser = LoggerTestUtils.createUser(STANDARD_USER_PROFILE.Id); + User standardUser = LoggerMockDataCreator.createUser(STANDARD_USER_PROFILE.Id); insert standardUser; - LoggerTestUtils.assignAdminPermissionSet(standardUser.Id); + LoggerTestConfigurator.assignAdminPermissionSet(standardUser.Id); System.runAs(standardUser) { System.assertEquals(true, FeatureManagement.checkPermission(CAN_MODIFY_LOGGER_SETTINGS_PERMISSION_NAME)); @@ -49,9 +49,9 @@ private class LoggerSettingsController_Tests_Security { @IsTest static void it_should_not_permit_user_to_modify_logger_settings_when_loggerLogViewer_permission_set_is_assigned() { - User standardUser = LoggerTestUtils.createUser(STANDARD_USER_PROFILE.Id); + User standardUser = LoggerMockDataCreator.createUser(STANDARD_USER_PROFILE.Id); insert standardUser; - LoggerTestUtils.assignLogViewerPermissionSet(standardUser.Id); + LoggerTestConfigurator.assignLogViewerPermissionSet(standardUser.Id); System.runAs(standardUser) { System.assertEquals(false, FeatureManagement.checkPermission(CAN_MODIFY_LOGGER_SETTINGS_PERMISSION_NAME)); @@ -61,9 +61,9 @@ private class LoggerSettingsController_Tests_Security { @IsTest static void it_should_not_permit_user_to_modify_logger_settings_when_loggerEndUser_permission_set_is_assigned() { - User standardUser = LoggerTestUtils.createUser(STANDARD_USER_PROFILE.Id); + User standardUser = LoggerMockDataCreator.createUser(STANDARD_USER_PROFILE.Id); insert standardUser; - LoggerTestUtils.assignEndUserPermissionSet(standardUser.Id); + LoggerTestConfigurator.assignEndUserPermissionSet(standardUser.Id); System.runAs(standardUser) { System.assertEquals(false, FeatureManagement.checkPermission(CAN_MODIFY_LOGGER_SETTINGS_PERMISSION_NAME)); @@ -73,9 +73,9 @@ private class LoggerSettingsController_Tests_Security { @IsTest static void it_should_not_permit_user_to_modify_logger_settings_when_loggerLogCreator_permission_set_is_assigned() { - User standardUser = LoggerTestUtils.createUser(STANDARD_USER_PROFILE.Id); + User standardUser = LoggerMockDataCreator.createUser(STANDARD_USER_PROFILE.Id); insert standardUser; - LoggerTestUtils.assignLogCreatorPermissionSet(standardUser.Id); + LoggerTestConfigurator.assignLogCreatorPermissionSet(standardUser.Id); System.runAs(standardUser) { System.assertEquals(false, FeatureManagement.checkPermission(CAN_MODIFY_LOGGER_SETTINGS_PERMISSION_NAME)); @@ -85,7 +85,7 @@ private class LoggerSettingsController_Tests_Security { @IsTest static void it_should_not_permit_user_to_modify_logger_settings_when_custom_permission_is_not_assigned() { - User standardUser = LoggerTestUtils.createUser(STANDARD_USER_PROFILE.Id); + User standardUser = LoggerMockDataCreator.createUser(STANDARD_USER_PROFILE.Id); System.runAs(standardUser) { System.assertEquals(false, LoggerSettingsController.canUserModifyLoggerSettings()); } diff --git a/nebula-logger/extra-tests/tests/Logger_Tests_ExperienceSite.cls b/nebula-logger/extra-tests/tests/Logger_Tests_ExperienceSite.cls index 5c5e907ae..70fde7ed5 100644 --- a/nebula-logger/extra-tests/tests/Logger_Tests_ExperienceSite.cls +++ b/nebula-logger/extra-tests/tests/Logger_Tests_ExperienceSite.cls @@ -8,7 +8,7 @@ * @description Additional integration tests for orgs with Experience Sites (Communities) enabled */ @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=false) private class Logger_Tests_ExperienceSite { private static final Boolean IS_EXPERIENCE_CLOUD_ENABLED = Schema.getGlobalDescribe().containsKey('Network'); private static final String GUEST_USER_PROFILE_NAME = 'Logger Test Site Profile'; @@ -36,7 +36,7 @@ private class Logger_Tests_ExperienceSite { } User guestUser = guestUsers.get(0); - LoggerTestUtils.assignLogCreatorPermissionSet(guestUser.Id); + LoggerTestConfigurator.assignLogCreatorPermissionSet(guestUser.Id); } @IsTest @@ -92,7 +92,7 @@ private class Logger_Tests_ExperienceSite { Logger.debug(message); Logger.saveLog(); - Test.getEventBus().deliver(); + System.Test.getEventBus().deliver(); } LogEntry__c logEntry = [SELECT Id, Log__r.LoggedBy__c, Log__r.OwnerId, Log__r.UserLicenseDefinitionKey__c, Message__c FROM LogEntry__c]; diff --git a/nebula-logger/extra-tests/tests/Logger_Tests_InboundEmailHandler.cls b/nebula-logger/extra-tests/tests/Logger_Tests_InboundEmailHandler.cls index 73094cb5d..5a7b8ba47 100644 --- a/nebula-logger/extra-tests/tests/Logger_Tests_InboundEmailHandler.cls +++ b/nebula-logger/extra-tests/tests/Logger_Tests_InboundEmailHandler.cls @@ -8,35 +8,29 @@ * @description Additional integration tests for logging from an instance of `Messaging.InboundEmailHandler` */ @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class Logger_Tests_InboundEmailHandler { @IsTest - private static void saveLogsWhenRunningEmailService() { - // Create a new email and envelope object - Messaging.InboundEnvelope envelope = new Messaging.InboundEnvelope(); - - // Create the email body + private static void it_should_save_logs_when_running_within_email_service() { Messaging.InboundEmail email = new Messaging.InboundEmail(); email.plainTextBody = 'Example email content'; email.fromAddress = 'test@test.com'; email.subject = 'My example email'; - - // Create an instance of the example handler class - ExampleInboundEmailHandler handler = new ExampleInboundEmailHandler(); - + Messaging.InboundEnvelope envelope = new Messaging.InboundEnvelope(); + ExampleInboundEmailHandler emailHandler = new ExampleInboundEmailHandler(); Test.startTest(); - + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); String transactionId = Logger.getTransactionId(); - Messaging.InboundEmailResult result = handler.handleInboundEmail(email, envelope); - - Test.stopTest(); + System.assertNotEquals(1, Logger.saveLogCallCount, 'No logging should have occurred yet'); - System.assert(result.success, 'InboundEmailResult returned a failure message'); + Messaging.InboundEmailResult result = emailHandler.handleInboundEmail(email, envelope); + System.assertNotEquals(0, Logger.saveLogCallCount, 'ExampleInboundEmailHandler class should have logged & saved some logging data'); + Test.stopTest(); + System.assertEquals(true, result.success, 'InboundEmailResult returned a failure message'); List logs = [SELECT Id, TransactionId__c FROM Log__c]; System.assertEquals(1, logs.size(), 'Logs size did not match expected value of 1.'); System.assertEquals(transactionId, logs.get(0).TransactionId__c, 'Transaction Id does match expected value.'); - List logEntries = [SELECT Id, Message__c FROM LogEntry__c]; System.assertEquals(1, logEntries.size(), 'Log entries size did not match expected value of 1.'); System.assertEquals(ExampleInboundEmailHandler.logEntryMessage, logEntries.get(0).Message__c, 'Log entries message did not match expected value.'); diff --git a/nebula-logger/extra-tests/tests/Logger_Tests_MergeResult.cls b/nebula-logger/extra-tests/tests/Logger_Tests_MergeResult.cls index 2eac3d11c..32240a0d5 100644 --- a/nebula-logger/extra-tests/tests/Logger_Tests_MergeResult.cls +++ b/nebula-logger/extra-tests/tests/Logger_Tests_MergeResult.cls @@ -3,6 +3,8 @@ // See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // //------------------------------------------------------------------------------------------------// +// TODO move these test methods back into Logger_Tests, now that mocking is possible via LoggerMockDataCreator.createDatabaseMergeResult() +// (and then delete this class) /** * @group Extra Tests * @description Additional integration tests for merging records. @@ -10,7 +12,7 @@ * from within the normal tests, and each org might have additional required fields, VR, etc on the std objects */ @SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest +@IsTest(IsParallel=true) private class Logger_Tests_MergeResult { static String getMessage() { return 'Hello, world'; @@ -20,18 +22,8 @@ private class Logger_Tests_MergeResult { return new LogMessage('The current date is {0}', System.today()); } - static Database.MergeResult getMergeResult() { - Account mainAccount = new Account(Name = 'Main'); - Account duplicateAccount = new Account(Name = 'Duplicate'); - List accounts = new List{ mainAccount, duplicateAccount }; - insert accounts; - - Database.MergeResult mergeResult = Database.merge(mainAccount, duplicateAccount); - return mergeResult; - } - static List getMergeResultList() { - return new List{ getMergeResult() }; + return new List{ LoggerMockDataCreator.createDatabaseMergeResult(true) }; } @IsTest @@ -40,7 +32,7 @@ private class Logger_Tests_MergeResult { Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); System.assertEquals(0, Logger.getBufferSize(), 'Logger buffer size was incorrect.'); - Database.MergeResult mergeResult = getMergeResult(); + Database.MergeResult mergeResult = LoggerMockDataCreator.createDatabaseMergeResult(true); Test.startTest(); @@ -109,7 +101,7 @@ private class Logger_Tests_MergeResult { Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); System.assertEquals(0, Logger.getBufferSize(), 'Logger buffer size was incorrect.'); - Database.MergeResult mergeResult = getMergeResult(); + Database.MergeResult mergeResult = LoggerMockDataCreator.createDatabaseMergeResult(true); Test.startTest(); @@ -183,7 +175,7 @@ private class Logger_Tests_MergeResult { Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); System.assertEquals(0, Logger.getBufferSize(), 'Logger buffer size was incorrect.'); - Database.MergeResult mergeResult = getMergeResult(); + Database.MergeResult mergeResult = LoggerMockDataCreator.createDatabaseMergeResult(true); Test.startTest(); @@ -252,7 +244,7 @@ private class Logger_Tests_MergeResult { Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); System.assertEquals(0, Logger.getBufferSize(), 'Logger buffer size was incorrect.'); - Database.MergeResult mergeResult = getMergeResult(); + Database.MergeResult mergeResult = LoggerMockDataCreator.createDatabaseMergeResult(true); Test.startTest(); @@ -326,7 +318,7 @@ private class Logger_Tests_MergeResult { Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); System.assertEquals(0, Logger.getBufferSize(), 'Logger buffer size was incorrect.'); - Database.MergeResult mergeResult = getMergeResult(); + Database.MergeResult mergeResult = LoggerMockDataCreator.createDatabaseMergeResult(true); Test.startTest(); @@ -395,7 +387,7 @@ private class Logger_Tests_MergeResult { Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); System.assertEquals(0, Logger.getBufferSize(), 'Logger buffer size was incorrect.'); - Database.MergeResult mergeResult = getMergeResult(); + Database.MergeResult mergeResult = LoggerMockDataCreator.createDatabaseMergeResult(true); Test.startTest(); @@ -469,7 +461,7 @@ private class Logger_Tests_MergeResult { Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); System.assertEquals(0, Logger.getBufferSize(), 'Logger buffer size was incorrect.'); - Database.MergeResult mergeResult = getMergeResult(); + Database.MergeResult mergeResult = LoggerMockDataCreator.createDatabaseMergeResult(true); Test.startTest(); @@ -538,7 +530,7 @@ private class Logger_Tests_MergeResult { Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); System.assertEquals(0, Logger.getBufferSize(), 'Logger buffer size was incorrect.'); - Database.MergeResult mergeResult = getMergeResult(); + Database.MergeResult mergeResult = LoggerMockDataCreator.createDatabaseMergeResult(true); Test.startTest(); @@ -612,7 +604,7 @@ private class Logger_Tests_MergeResult { Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); System.assertEquals(0, Logger.getBufferSize(), 'Logger buffer size was incorrect.'); - Database.MergeResult mergeResult = getMergeResult(); + Database.MergeResult mergeResult = LoggerMockDataCreator.createDatabaseMergeResult(true); Test.startTest(); @@ -681,7 +673,7 @@ private class Logger_Tests_MergeResult { Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); System.assertEquals(0, Logger.getBufferSize(), 'Logger buffer size was incorrect.'); - Database.MergeResult mergeResult = getMergeResult(); + Database.MergeResult mergeResult = LoggerMockDataCreator.createDatabaseMergeResult(true); Test.startTest(); @@ -755,7 +747,7 @@ private class Logger_Tests_MergeResult { Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); System.assertEquals(0, Logger.getBufferSize(), 'Logger buffer size was incorrect.'); - Database.MergeResult mergeResult = getMergeResult(); + Database.MergeResult mergeResult = LoggerMockDataCreator.createDatabaseMergeResult(true); Test.startTest(); @@ -824,7 +816,7 @@ private class Logger_Tests_MergeResult { Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); System.assertEquals(0, Logger.getBufferSize(), 'Logger buffer size was incorrect.'); - Database.MergeResult mergeResult = getMergeResult(); + Database.MergeResult mergeResult = LoggerMockDataCreator.createDatabaseMergeResult(true); Test.startTest(); @@ -898,7 +890,7 @@ private class Logger_Tests_MergeResult { Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); System.assertEquals(0, Logger.getBufferSize(), 'Logger buffer size was incorrect.'); - Database.MergeResult mergeResult = getMergeResult(); + Database.MergeResult mergeResult = LoggerMockDataCreator.createDatabaseMergeResult(true); Test.startTest(); @@ -967,7 +959,7 @@ private class Logger_Tests_MergeResult { Logger.getUserSettings().LoggingLevel__c = loggingLevel.name(); System.assertEquals(0, Logger.getBufferSize(), 'Logger buffer size was incorrect.'); - Database.MergeResult mergeResult = getMergeResult(); + Database.MergeResult mergeResult = LoggerMockDataCreator.createDatabaseMergeResult(true); Test.startTest(); diff --git a/nebula-logger/managed-package/core/main/configuration/objects/LoggerSettings__c/fields/EnableStatusApiCallout__c.field-meta.xml b/nebula-logger/managed-package/core/main/configuration/objects/LoggerSettings__c/fields/EnableStatusApiCallout__c.field-meta.xml index 2cbb3cce7..97fecdbad 100644 --- a/nebula-logger/managed-package/core/main/configuration/objects/LoggerSettings__c/fields/EnableStatusApiCallout__c.field-meta.xml +++ b/nebula-logger/managed-package/core/main/configuration/objects/LoggerSettings__c/fields/EnableStatusApiCallout__c.field-meta.xml @@ -1,6 +1,7 @@ EnableStatusApiCallout__c + DeprecateCandidate true When enabled, an async callout is made to https://api.status.salesforce.com to get additional details about the current org, including the org's release version and release number. This information is then stored on the Log__c record. diff --git a/nebula-logger/managed-package/core/main/configuration/objects/LoggerSettings__c/fields/EnableSystemMessages__c.field-meta.xml b/nebula-logger/managed-package/core/main/configuration/objects/LoggerSettings__c/fields/EnableSystemMessages__c.field-meta.xml index 4af1e71e9..fc82cc8ef 100644 --- a/nebula-logger/managed-package/core/main/configuration/objects/LoggerSettings__c/fields/EnableSystemMessages__c.field-meta.xml +++ b/nebula-logger/managed-package/core/main/configuration/objects/LoggerSettings__c/fields/EnableSystemMessages__c.field-meta.xml @@ -1,6 +1,7 @@ EnableSystemMessages__c + DeprecateCandidate true When enabled, log entries may be generated that contain additional details about the logging system. false diff --git a/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/IsPlatformEventStorageEnabled__c.field-meta.xml b/nebula-logger/managed-package/core/main/configuration/objects/LoggerSettings__c/fields/IsPlatformEventStorageEnabled__c.field-meta.xml similarity index 81% rename from nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/IsPlatformEventStorageEnabled__c.field-meta.xml rename to nebula-logger/managed-package/core/main/configuration/objects/LoggerSettings__c/fields/IsPlatformEventStorageEnabled__c.field-meta.xml index ab0b46b87..4ef7fb06d 100644 --- a/nebula-logger/core/main/configuration/objects/LoggerSettings__c/fields/IsPlatformEventStorageEnabled__c.field-meta.xml +++ b/nebula-logger/managed-package/core/main/configuration/objects/LoggerSettings__c/fields/IsPlatformEventStorageEnabled__c.field-meta.xml @@ -1,12 +1,14 @@ IsPlatformEventStorageEnabled__c + DeprecateCandidate true Controls if LogEntryEvent__e platform events are transformed & stored in the custom objects Log__c and LogEntry__c (when IsSavingEnabled__c == true). false Controls if LogEntryEvent__e platform events are transformed & stored in the custom objects Log__c and LogEntry__c (when IsSavingEnabled__c == true). - + + false Checkbox diff --git a/nebula-logger/managed-package/core/main/deprecated/classes/LoggerEmailUtils.cls b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerEmailUtils.cls new file mode 100644 index 000000000..e2422ae32 --- /dev/null +++ b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerEmailUtils.cls @@ -0,0 +1,3 @@ +@SuppressWarnings('PMD.ApexDoc') +public class LoggerEmailUtils { +} diff --git a/nebula-logger/managed-package/core/main/deprecated/classes/LoggerEmailUtils.cls-meta.xml b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerEmailUtils.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerEmailUtils.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/managed-package/core/main/deprecated/classes/LoggerEmailUtils_Tests.cls b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerEmailUtils_Tests.cls new file mode 100644 index 000000000..71f82465d --- /dev/null +++ b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerEmailUtils_Tests.cls @@ -0,0 +1,4 @@ +@SuppressWarnings('PMD.ApexDoc') +@IsTest(IsParallel=true) +private class LoggerEmailUtils_Tests { +} diff --git a/nebula-logger/managed-package/core/main/deprecated/classes/LoggerEmailUtils_Tests.cls-meta.xml b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerEmailUtils_Tests.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerEmailUtils_Tests.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/managed-package/core/main/deprecated/classes/LoggerSObjectHandlerPlugin.cls b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerSObjectHandlerPlugin.cls new file mode 100644 index 000000000..86473e205 --- /dev/null +++ b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerSObjectHandlerPlugin.cls @@ -0,0 +1,3 @@ +@SuppressWarnings('PMD.ApexDoc') +public class LoggerSObjectHandlerPlugin { +} diff --git a/nebula-logger/managed-package/core/main/deprecated/classes/LoggerSObjectHandlerPlugin.cls-meta.xml b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerSObjectHandlerPlugin.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerSObjectHandlerPlugin.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/managed-package/core/main/deprecated/classes/LoggerSObjectHandlerPlugin_Tests.cls b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerSObjectHandlerPlugin_Tests.cls new file mode 100644 index 000000000..249852bb1 --- /dev/null +++ b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerSObjectHandlerPlugin_Tests.cls @@ -0,0 +1,4 @@ +@SuppressWarnings('PMD.ApexDoc') +@IsTest(IsParallel=true) +private class LoggerSObjectHandlerPlugin_Tests { +} diff --git a/nebula-logger/managed-package/core/main/deprecated/classes/LoggerSObjectHandlerPlugin_Tests.cls-meta.xml b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerSObjectHandlerPlugin_Tests.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerSObjectHandlerPlugin_Tests.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/managed-package/core/main/deprecated/classes/LoggerTestUtils.cls b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerTestUtils.cls new file mode 100644 index 000000000..a0d8e3f6e --- /dev/null +++ b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerTestUtils.cls @@ -0,0 +1,4 @@ +@SuppressWarnings('PMD.ApexDoc') +@IsTest(IsParallel=true) +private class LoggerTestUtils { +} diff --git a/nebula-logger/managed-package/core/main/deprecated/classes/LoggerTestUtils.cls-meta.xml b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerTestUtils.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/managed-package/core/main/deprecated/classes/LoggerTestUtils.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/managed-package/sfdx-project.json b/nebula-logger/managed-package/sfdx-project.json index 16229ea42..544fac143 100644 --- a/nebula-logger/managed-package/sfdx-project.json +++ b/nebula-logger/managed-package/sfdx-project.json @@ -10,9 +10,9 @@ "definitionFile": "./config/scratch-orgs/base-scratch-def.json", "postInstallScript": "LoggerInstallHandler", "ancestorVersion": "HIGHEST", - "versionNumber": "4.7.0.NEXT", - "versionName": "Spring '22 Release", - "versionDescription": "View the v4.7.0 milestone in GitHub for the list of changes - https://github.com/jongpie/NebulaLogger/milestone/7", + "versionNumber": "4.8.0.NEXT", + "versionName": "BETA - Summer '22 Release", + "versionDescription": "View the v4.8.0 milestone in GitHub for the list of changes - https://github.com/jongpie/NebulaLogger/milestone/7", "releaseNotesUrl": "https://github.com/jongpie/NebulaLogger/releases" } ], diff --git a/nebula-logger/plugins/.images/btn-install-unlocked-package-plugin-sandbox.png b/nebula-logger/plugins/.images/btn-install-unlocked-package-plugin-sandbox.png new file mode 100644 index 000000000..6b271f988 Binary files /dev/null and b/nebula-logger/plugins/.images/btn-install-unlocked-package-plugin-sandbox.png differ diff --git a/nebula-logger/plugins/Logger-Admin-Dashboard/images/btn-install-unlocked-package-plugin.png b/nebula-logger/plugins/.images/btn-install-unlocked-package-plugin.png similarity index 100% rename from nebula-logger/plugins/Logger-Admin-Dashboard/images/btn-install-unlocked-package-plugin.png rename to nebula-logger/plugins/.images/btn-install-unlocked-package-plugin.png diff --git a/nebula-logger/plugins/Slack/plugin/slack/classes/SlackLoggerPlugin_Tests.cls b/nebula-logger/plugins/Slack/plugin/slack/classes/SlackLoggerPlugin_Tests.cls deleted file mode 100644 index aebf133ed..000000000 --- a/nebula-logger/plugins/Slack/plugin/slack/classes/SlackLoggerPlugin_Tests.cls +++ /dev/null @@ -1,186 +0,0 @@ -//------------------------------------------------------------------------------------------------// -// This file is part of the Nebula Logger project, released under the MIT License. // -// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // -//------------------------------------------------------------------------------------------------// - -// TODO: need to improve plugin framework to make it easier for plugins to test by making it easier -// to mock CMDT records & instances of LoggerSObjectHandlerPlugin -@SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions, PMD.NcssMethodCount') -@IsTest -private class SlackLoggerPlugin_Tests { - /** - * @description Inner class for handling mock HTTP callouts. - */ - public class SuccessCalloutMock implements HttpCalloutMock { - /** - * @description Returns the mock HTTP response. - * @param request The HTTP request to "receive" - * @return The resulting HTTP response - */ - public HttpResponse respond(HttpRequest request) { - HttpResponse response = new HttpResponse(); - response.setBody(request.getBody()); - response.setStatusCode(200); - return response; - } - } - - /** - * @description Inner class for handling mock HTTP callouts that should end in errors / exceptions. - */ - public class FailureCalloutMock implements HttpCalloutMock { - /** - * @description Returns the mock HTTP response. - * @param request The HTTP request to "receive" - * @return The resulting HTTP response - */ - public HttpResponse respond(HttpRequest request) { - HttpResponse response = new HttpResponse(); - response.setBody(request.getBody()); - response.setStatusCode(400); - return response; - } - } - - static void mockConfigurations(LoggingLevel notificationLoggingLevel) { - // Set the plugin's parameters - LoggerPlugin__mdt slackPluginConfig = new LoggerPlugin__mdt( - IsEnabled__c = true, - PluginApiName__c = SlackLoggerPlugin.class.getName(), - PluginType__c = 'Apex' - ); - LoggerSObjectHandler.setMockPlugin(Schema.Log__c.SObjectType, slackPluginConfig); - - // Set the plugin's internal variables - SlackLoggerPlugin.endpoint = 'https://fake.slack.com/'; - SlackLoggerPlugin.notificationLoggingLevel = notificationLoggingLevel; - } - - static void verifyLogEntryCountEquals(Integer expectedCount) { - List existingLogEntries = [SELECT Id FROM LogEntry__c]; - System.assertEquals(expectedCount, existingLogEntries.size(), 'Existing log entries did NOT match the expected count.'); - } - - static List queryLogs() { - return [ - SELECT - Id, - MaxLogEntryLoggingLevelOrdinal__c, - SendSlackNotification__c, - SlackNotificationDate__c, - ( - SELECT Id, LoggingLevel__c, Message__c - FROM LogEntries__r - WHERE LoggingLevelOrdinal__c >= :LoggingLevel.WARN.ordinal() - ORDER BY Timestamp__c DESC - LIMIT 1 - ) - FROM Log__c - ]; - } - - @IsTest - static void pushLogWhenLoggingLevelIsMet() { - SuccessCalloutMock calloutMock = new SuccessCalloutMock(); - - verifyLogEntryCountEquals(0); - - Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), SendSlackNotification__c = false, TransactionId__c = '1234'); - insert log; - - LoggingLevel logEntryLoggingLevel = LoggingLevel.WARN; - LogEntry__c logEntry = new LogEntry__c( - Log__c = log.Id, - LoggingLevel__c = logEntryLoggingLevel.name(), - LoggingLevelOrdinal__c = logEntryLoggingLevel.ordinal(), - Timestamp__c = System.now() - ); - insert logEntry; - - verifyLogEntryCountEquals(1); - - List logs = queryLogs(); - System.assertEquals(1, logs.size(), 'Logs size did not match expected value of 1.'); - log = logs.get(0); - - System.assertEquals(1, log.LogEntries__r.size(), 'Log entries did not match the expected count of 1.'); - System.assertEquals(false, log.SendSlackNotification__c, 'SendSlackNotification was incorrectly set to true.'); - System.assertEquals(null, log.SlackNotificationDate__c, 'SlackNotificationDate was not null.'); - - Test.startTest(); - Test.setMock(HttpCalloutMock.class, calloutMock); - - // Load the mock configurations - the plugin framework won't load actual CMDT records during tests - mockConfigurations(logEntryLoggingLevel); - System.assert( - logEntryLoggingLevel.ordinal() >= SlackLoggerPlugin.notificationLoggingLevel.ordinal(), - 'The notification logging level ordinal was incorrect.' - ); - - // Update the records to trigger the handler framework, which will then run the Slack plugin - update log; - - // Verify that the internal queueable job has been enqueued - System.assertEquals(1, Limits.getAsyncCalls(), 'The enqueueable job was not enqueued.'); - - // Stop the test so the internal queueable job runs - Test.stopTest(); - - log = [SELECT Id, MaxLogEntryLoggingLevelOrdinal__c, SendSlackNotification__c, SlackNotificationDate__c FROM Log__c]; - System.assertEquals(true, log.SendSlackNotification__c, 'SendSlackNotification was incorrectly set to false.'); - System.assertNotEquals(null, log.SlackNotificationDate__c, 'SlackNotificationDate was null.'); - System.assertEquals(System.today(), log.SlackNotificationDate__c.date(), 'SlackNotificationDate was not set to TODAY.'); - } - - @IsTest - static void doNotPushLogWhenLoggingLevelIsNotMet() { - SuccessCalloutMock calloutMock = new SuccessCalloutMock(); - - verifyLogEntryCountEquals(0); - - Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), SendSlackNotification__c = false, TransactionId__c = '1234'); - insert log; - - LoggingLevel logEntryLoggingLevel = LoggingLevel.WARN; - LogEntry__c logEntry = new LogEntry__c( - Log__c = log.Id, - LoggingLevel__c = logEntryLoggingLevel.name(), - LoggingLevelOrdinal__c = logEntryLoggingLevel.ordinal(), - Timestamp__c = System.now() - ); - insert logEntry; - - verifyLogEntryCountEquals(1); - - List logs = queryLogs(); - System.assertEquals(1, logs.size(), 'Logs size did not match expected value of 1.'); - log = logs.get(0); - - System.assertEquals(1, log.LogEntries__r.size(), 'Log entries size was not equal to 1.'); - System.assertEquals(false, log.SendSlackNotification__c, 'SendSlackNotification was incorrectly set to true.'); - System.assertEquals(null, log.SlackNotificationDate__c, 'SlackNotificationDate was not null.'); - - Test.startTest(); - Test.setMock(HttpCalloutMock.class, calloutMock); - - // Load the mock configurations - the plugin framework won't load actual CMDT records during tests - LoggingLevel slackLoggingLevel = LoggingLevel.ERROR; - System.assert(logEntryLoggingLevel.ordinal() < slackLoggingLevel.ordinal(), 'Slack logging level ordinal was incorrect.'); - mockConfigurations(slackLoggingLevel); - System.assert(logEntryLoggingLevel.ordinal() < SlackLoggerPlugin.notificationLoggingLevel.ordinal(), 'Slack logging level ordinal was incorrect.'); - - // Update the records to trigger the handler framework, which will then run the Slack plugin - update log; - - // Verify that the internal queueable job has been enqueued - System.assertEquals(0, Limits.getAsyncCalls(), 'The queueable job has not been enqueued.'); - - // Stop the test so the internal queueable job runs - Test.stopTest(); - - log = queryLogs().get(0); - System.assertEquals(1, log.LogEntries__r.size(), 'Log entries size was not equal to 1.'); - System.assertEquals(false, log.SendSlackNotification__c, 'SendSlackNotification incorrectly set to true.'); - System.assertEquals(null, log.SlackNotificationDate__c, 'SlackNotificationDate was not null.'); - } -} diff --git a/nebula-logger/plugins/Slack/plugin/slack/customMetadata/LoggerPlugin.Slack.md-meta.xml b/nebula-logger/plugins/Slack/plugin/slack/customMetadata/LoggerPlugin.Slack.md-meta.xml deleted file mode 100644 index 7160cebf7..000000000 --- a/nebula-logger/plugins/Slack/plugin/slack/customMetadata/LoggerPlugin.Slack.md-meta.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - false - - Description__c - Adds a Slack integration for Nebula Logger. - -Any logs with MaxLogEntryLoggingLevelOrdinal__c >= the parameter 'SlackLoggingLevelThreshold' will send a notification to Slack - - - PluginApiName__c - SlackLoggerPlugin - - - PluginType__c - Apex - - - SObjectType__c - Log__c - - diff --git a/nebula-logger/plugins/big-object-archiving/.images/log-entry-archives-tab.png b/nebula-logger/plugins/big-object-archiving/.images/log-entry-archives-tab.png new file mode 100644 index 000000000..b1649e86f Binary files /dev/null and b/nebula-logger/plugins/big-object-archiving/.images/log-entry-archives-tab.png differ diff --git a/nebula-logger/plugins/big-object-archiving/README.md b/nebula-logger/plugins/big-object-archiving/README.md new file mode 100644 index 000000000..403644da2 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/README.md @@ -0,0 +1,32 @@ +# Big Object Archiving plugin for Nebula Logger + +> :information_source: This plugin requires `v4.7.1` or newer of Nebula Logger's unlocked package + +[![Install Unlocked Package](../.images/btn-install-unlocked-package-plugin-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015lgLQAQ) +Adds a Big Object - `LogEntryArchive__b` - to Nebula Logger for archiving of logging data. + +The `LogEntryArchive__b` object can be used to: + +- **To immediately publish logging data, instead of using platform events**. Out of the box, Nebula Logger leverages platform events (`LogEntryEvent__e`) as the mechanism for saving logging data, even if an error occurs. It then transforms the platform event data in `LogEntryEvent__e` and stores it in `Log__c` and `LogEntry__c` for reporting & managing of logs. If you want to skip the platform events altogether, and don't need to report on the data via Log**c or LogEntry**c, then you can leverage the Big Object Archiving plugin to immediately write to `LogEntryArchive__b`, giving you a way to store logging data on platform, without consuming your data storage limits (although it's worth noting that Big Objects have their own storage limits as well). +- **To later archive `Log__c` and `LogEntry__c` data**. If you want to leverage the benefits of having logging data in `Log__c` and `LogEntry__c`, but need to delete some records due to storage limits, the plugin also provides the ability to archive `Log__c` and `LogEntry__c` data into the big object `LogEntryArchive__b`. This is accomplished by setting a "Log Purge Action" to "Archive" on any `Log__c` records that you want to archive into the `LogEntryArchive__b` big object. + - When the `LogBatchPurger` job runs, any `Log__c` (and related `LogEntry__c` records) with a "Log Purge Action" of "Archive" and a "Log Retention Date" <= TODAY will first be copied into the big object `LogEntryArchive__b`, before being deleted in `Log__c` and `LogEntry__c`. + +![Big Object Archiving plugin: Log Entry Archives tab](./images/log-entry-archives-tab.png) + +--- + +## What's Included + +This plugin includes some add-on metadata for Nebula Logger to support storing logging data within a big object + +1. BigObject `LogEntryArchive__b` +2. Custom tab "Log Entry Archives" to display the included LWC `logEntryArchives` +3. Apex classes `LogEntryArchivePlugin`, `LogEntryArchiveBuilder` and corresponding test classes +4. Plugin configuration details stored in Logger's CMDT objects `LoggerPlugin__mdt` and `LoggerParameter__mdt` +5. Field-level security (FLS) & tab access via a new permission set `LogEntryArchiveAdmin` to provide access to the custom Slack fields + +--- + +## Installation Steps + +TODO diff --git a/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveBuilder.cls b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveBuilder.cls new file mode 100644 index 000000000..0c841fe60 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveBuilder.cls @@ -0,0 +1,325 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @group Plugins + * @description Builder class to create an instance of `LogEntryArchive__b`, used by the BigObject plugin + * @see LogEntryArchivePlugin + * @see LogEntryEventBuilder + */ +public without sharing class LogEntryArchiveBuilder { + private LogEntryEvent__e logEntryEvent; + private LogEntry__c logEntry; + private LogEntryArchive__b logEntryArchive; + + /** + * @description Used by `LogEntryArchivePlugin` to instantiate a new instance of `LogEntryArchiveBuilder` + * @param logEntryEvent The `LogEntryEvent__e` record that will be converted to a `LogEntryArchive__b` record + */ + public LogEntryArchiveBuilder(LogEntryEvent__e logEntryEvent) { + this.logEntryEvent = logEntryEvent; + } + + /** + * @description Used by `LogEntryArchivePlugin` to instantiate a new instance of `LogEntryArchiveBuilder` + * @param logEntry The `LogEntry__c` record that will be converted to a `LogEntryArchive__b` record + */ + public LogEntryArchiveBuilder(LogEntry__c logEntry) { + this.logEntry = logEntry; + } + + /** + * @description Returns the `LogEntryArchive__b` record for this instance of LogEntryEventBuilder + * @return The `LogEntryArchive__b` record + */ + public LogEntryArchive__b getLogEntryArchive() { + if (this.logEntryArchive == null && this.logEntryEvent != null) { + this.convertLogEntryEventToLogEntryArchive(); + this.truncateFieldValues(); + } else if (this.logEntryArchive == null && this.logEntry != null) { + this.convertLogEntryToLogEntryArchive(); + this.truncateFieldValues(); + } + + return this.logEntryArchive; + } + + private void convertLogEntryEventToLogEntryArchive() { + this.logEntryArchive = new LogEntryArchive__b( + ApiVersion__c = this.logEntryEvent.ApiVersion__c, + ArchivedById__c = UserInfo.getUserId(), + ArchivedDate__c = System.now(), + ArchivedByUsername__c = UserInfo.getUsername(), + ComponentType__c = this.logEntryEvent.ComponentType__c, + DatabaseResultCollectionSize__c = this.logEntryEvent.DatabaseResultCollectionSize__c, + DatabaseResultCollectionType__c = this.logEntryEvent.DatabaseResultCollectionType__c, + DatabaseResultJson__c = this.logEntryEvent.DatabaseResultJson__c, + DatabaseResultType__c = this.logEntryEvent.DatabaseResultType__c, + EpochTimestamp__c = this.logEntryEvent.EpochTimestamp__c, + EventUuid__c = this.logEntryEvent.EventUuid, + ExceptionMessage__c = this.logEntryEvent.ExceptionMessage__c, + ExceptionStackTrace__c = this.logEntryEvent.ExceptionStackTrace__c, + ExceptionType__c = this.logEntryEvent.ExceptionType__c, + HttpRequestBody__c = this.logEntryEvent.HttpRequestBody__c, + HttpRequestBodyMasked__c = String.valueOf(this.logEntryEvent.HttpRequestBodyMasked__c), + HttpRequestCompressed__c = String.valueOf(this.logEntryEvent.HttpRequestCompressed__c), + HttpRequestEndpoint__c = this.logEntryEvent.HttpRequestEndpoint__c, + HttpRequestMethod__c = this.logEntryEvent.HttpRequestMethod__c, + HttpResponseBody__c = this.logEntryEvent.HttpResponseBody__c, + HttpResponseBodyMasked__c = String.valueOf(this.logEntryEvent.HttpResponseBody__c), + HttpResponseHeaderKeys__c = this.logEntryEvent.HttpResponseHeaderKeys__c, + HttpResponseStatus__c = this.logEntryEvent.HttpResponseStatus__c, + HttpResponseStatusCode__c = this.logEntryEvent.HttpResponseStatusCode__c, + LimitsAggregateQueriesMax__c = this.logEntryEvent.LimitsAggregateQueriesMax__c, + LimitsAggregateQueriesUsed__c = this.logEntryEvent.LimitsAggregateQueriesUsed__c, + LimitsAsyncCallsMax__c = this.logEntryEvent.LimitsAsyncCallsMax__c, + LimitsAsyncCallsUsed__c = this.logEntryEvent.LimitsAsyncCallsUsed__c, + LimitsCalloutsUsed__c = this.logEntryEvent.LimitsCalloutsUsed__c, + LimitsCpuTimeMax__c = this.logEntryEvent.LimitsCpuTimeMax__c, + LimitsCpuTimeUsed__c = this.logEntryEvent.LimitsCpuTimeUsed__c, + LimitsDmlRowsMax__c = this.logEntryEvent.LimitsDmlRowsMax__c, + LimitsDmlRowsUsed__c = this.logEntryEvent.LimitsDmlRowsUsed__c, + LimitsDmlStatementsMax__c = this.logEntryEvent.LimitsDmlStatementsMax__c, + LimitsDmlStatementsUsed__c = this.logEntryEvent.LimitsDmlStatementsUsed__c, + LimitsEmailInvocationsMax__c = this.logEntryEvent.LimitsEmailInvocationsMax__c, + LimitsEmailInvocationsUsed__c = this.logEntryEvent.LimitsEmailInvocationsUsed__c, + LimitsFutureCallsMax__c = this.logEntryEvent.LimitsFutureCallsMax__c, + LimitsFutureCallsUsed__c = this.logEntryEvent.LimitsFutureCallsUsed__c, + LimitsHeapSizeMax__c = this.logEntryEvent.LimitsHeapSizeMax__c, + LimitsHeapSizeUsed__c = this.logEntryEvent.LimitsHeapSizeUsed__c, + LimitsMobilePushApexCallsMax__c = this.logEntryEvent.LimitsMobilePushApexCallsMax__c, + LimitsMobilePushApexCallsUsed__c = this.logEntryEvent.LimitsMobilePushApexCallsUsed__c, + LimitsPublishImmediateDmlStatementsMax__c = this.logEntryEvent.LimitsPublishImmediateDmlStatementsMax__c, + LimitsPublishImmediateDmlStatementsUsed__c = this.logEntryEvent.LimitsPublishImmediateDmlStatementsUsed__c, + LimitsQueueableJobsMax__c = this.logEntryEvent.LimitsQueueableJobsMax__c, + LimitsQueueableJobsUsed__c = this.logEntryEvent.LimitsQueueableJobsUsed__c, + LimitsSoqlQueriesMax__c = this.logEntryEvent.LimitsSoqlQueriesMax__c, + LimitsSoqlQueriesUsed__c = this.logEntryEvent.LimitsSoqlQueriesUsed__c, + LimitsSoqlQueryLocatorRowsMax__c = this.logEntryEvent.LimitsSoqlQueryLocatorRowsMax__c, + LimitsSoqlQueryLocatorRowsUsed__c = this.logEntryEvent.LimitsSoqlQueryLocatorRowsUsed__c, + LimitsSoqlQueryRowsMax__c = this.logEntryEvent.LimitsSoqlQueryRowsMax__c, + LimitsSoqlQueryRowsUsed__c = this.logEntryEvent.LimitsSoqlQueryRowsUsed__c, + LimitsSoslSearchesMax__c = this.logEntryEvent.LimitsSoslSearchesMax__c, + LimitsSoslSearchesUsed__c = this.logEntryEvent.LimitsSoslSearchesUsed__c, + Locale__c = this.logEntryEvent.Locale__c, + // LoggedBy__c = String.isNotBlank(logEntryEvent.LoggedById__c) ? logEntryEvent.LoggedById__c : 'Anonymous', + LoggedById__c = this.logEntryEvent.LoggedById__c, + LoggedByUsername__c = String.isNotBlank(this.logEntryEvent.LoggedByUsername__c) ? this.logEntryEvent.LoggedByUsername__c : 'Anonymous', + LoggerVersionNumber__c = this.logEntryEvent.LoggerVersionNumber__c, + LoggingLevel__c = this.logEntryEvent.LoggingLevel__c, + LoggingLevelOrdinal__c = this.logEntryEvent.LoggingLevelOrdinal__c, + LoginApplication__c = this.logEntryEvent.LoginApplication__c, + LoginBrowser__c = this.logEntryEvent.LoginBrowser__c, + LoginHistoryId__c = this.logEntryEvent.LoginHistoryId__c, + LoginPlatform__c = this.logEntryEvent.LoginPlatform__c, + LoginType__c = this.logEntryEvent.LoginType__c, + LogoutUrl__c = this.logEntryEvent.LogoutUrl__c, + Message__c = this.logEntryEvent.Message__c, + NetworkId__c = this.logEntryEvent.NetworkId__c, + NetworkLoginUrl__c = this.logEntryEvent.NetworkLoginUrl__c, + NetworkLogoutUrl__c = this.logEntryEvent.NetworkLogoutUrl__c, + NetworkSelfRegistrationUrl__c = this.logEntryEvent.NetworkSelfRegistrationUrl__c, + NetworkUrlPathPrefix__c = this.logEntryEvent.NetworkUrlPathPrefix__c, + OrganizationDomainUrl__c = this.logEntryEvent.OrganizationDomainUrl__c, + OrganizationEnvironmentType__c = this.logEntryEvent.OrganizationEnvironmentType__c, + OrganizationId__c = this.logEntryEvent.OrganizationId__c, + OrganizationInstanceName__c = this.logEntryEvent.OrganizationInstanceName__c, + OrganizationName__c = this.logEntryEvent.OrganizationName__c, + OrganizationNamespacePrefix__c = this.logEntryEvent.OrganizationNamespacePrefix__c, + OrganizationType__c = this.logEntryEvent.OrganizationType__c, + OriginLocation__c = this.logEntryEvent.OriginLocation__c, + OriginType__c = this.logEntryEvent.OriginType__c, + ParentLogTransactionId__c = this.logEntryEvent.ParentLogTransactionId__c, + ProfileId__c = this.logEntryEvent.ProfileId__c, + ProfileName__c = this.logEntryEvent.ProfileName__c, + RecordCollectionSize__c = this.logEntryEvent.RecordCollectionSize__c, + RecordCollectionType__c = this.logEntryEvent.RecordCollectionType__c, + RecordId__c = this.logEntryEvent.RecordId__c, + RecordJson__c = this.logEntryEvent.RecordJson__c, + RecordSObjectClassification__c = this.logEntryEvent.RecordSObjectClassification__c, + RecordSObjectType__c = this.logEntryEvent.RecordSObjectType__c, + RecordSObjectTypeNamespace__c = this.logEntryEvent.RecordSObjectTypeNamespace__c, + SessionId__c = this.logEntryEvent.SessionId__c, + SessionSecurityLevel__c = this.logEntryEvent.SessionSecurityLevel__c, + SessionType__c = this.logEntryEvent.SessionType__c, + SourceIp__c = this.logEntryEvent.SourceIp__c, + StackTrace__c = this.logEntryEvent.StackTrace__c, + SystemMode__c = this.logEntryEvent.SystemMode__c, + Tags__c = this.logEntryEvent.Tags__c, + ThemeDisplayed__c = this.logEntryEvent.ThemeDisplayed__c, + Timestamp__c = this.logEntryEvent.Timestamp__c, + TimestampString__c = this.logEntryEvent.TimestampString__c, + TimeZoneId__c = this.logEntryEvent.TimeZoneId__c, + TransactionEntryNumber__c = this.logEntryEvent.TransactionEntryNumber__c, + TransactionId__c = this.logEntryEvent.TransactionId__c, + TriggerOperationType__c = this.logEntryEvent.TriggerOperationType__c, + TriggerSObjectType__c = this.logEntryEvent.TriggerSObjectType__c, + UserLicenseDefinitionKey__c = this.logEntryEvent.UserLicenseDefinitionKey__c, + UserLicenseName__c = this.logEntryEvent.UserLicenseName__c, + UserLoggingLevel__c = this.logEntryEvent.UserLoggingLevel__c, + UserLoggingLevelOrdinal__c = this.logEntryEvent.UserLoggingLevelOrdinal__c, + UserRoleId__c = this.logEntryEvent.UserRoleId__c, + UserRoleName__c = this.logEntryEvent.UserRoleName__c, + UserType__c = this.logEntryEvent.UserType__c + ); + } + + private void convertLogEntryToLogEntryArchive() { + List tagNames = new List(); + for (LogEntryTag__c logEntryTag : this.logEntry.LogEntryTags__r) { + tagNames.add(logEntryTag.Tag__r.Name); + } + tagNames = new List(new Set(tagNames)); + tagNames.sort(); + + this.logEntryArchive = new LogEntryArchive__b( + ApiReleaseNumber__c = this.logEntry.Log__r.ApiReleaseNumber__c, + ApiReleaseVersion__c = this.logEntry.Log__r.ApiReleaseVersion__c, + ApiVersion__c = this.logEntry.Log__r.ApiVersion__c, + ArchivedById__c = UserInfo.getUserId(), + ArchivedDate__c = System.now(), + ArchivedByUsername__c = UserInfo.getUsername(), + ClosedById__c = this.logEntry.Log__r.ClosedBy__c, + ClosedByUsername__c = this.logEntry.Log__r.ClosedBy__r.Username, + ClosedDate__c = this.logEntry.Log__r.ClosedDate__c, + Comments__c = this.logEntry.Log__r.Comments__c, + ComponentType__c = this.logEntry.ComponentType__c, + DatabaseResultCollectionSize__c = this.logEntry.DatabaseResultCollectionSize__c, + DatabaseResultCollectionType__c = this.logEntry.DatabaseResultCollectionType__c, + DatabaseResultJson__c = this.logEntry.DatabaseResultJson__c, + DatabaseResultType__c = this.logEntry.DatabaseResultType__c, + EpochTimestamp__c = this.logEntry.EpochTimestamp__c, + EventUuid__c = this.logEntry.EventUuid__c, + ExceptionMessage__c = this.logEntry.ExceptionMessage__c, + ExceptionStackTrace__c = this.logEntry.ExceptionStackTrace__c, + ExceptionType__c = this.logEntry.ExceptionType__c, + HttpRequestBody__c = this.logEntry.HttpRequestBody__c, + HttpRequestBodyMasked__c = String.valueOf(this.logEntry.HttpRequestBodyMasked__c), + HttpRequestCompressed__c = String.valueOf(this.logEntry.HttpRequestCompressed__c), + HttpRequestEndpoint__c = this.logEntry.HttpRequestEndpoint__c, + HttpRequestMethod__c = this.logEntry.HttpRequestMethod__c, + HttpResponseBody__c = this.logEntry.HttpResponseBody__c, + HttpResponseBodyMasked__c = String.valueOf(this.logEntry.HttpResponseBodyMasked__c), + HttpResponseHeaderKeys__c = this.logEntry.HttpResponseHeaderKeys__c, + HttpResponseStatus__c = this.logEntry.HttpResponseStatus__c, + HttpResponseStatusCode__c = this.logEntry.HttpResponseStatusCode__c, + IsClosed__c = String.valueOf(this.logEntry.Log__r.IsClosed__c), + IsResolved__c = String.valueOf(this.logEntry.Log__r.IsResolved__c), + Issue__c = this.logEntry.Log__r.Issue__c, + LimitsAggregateQueriesMax__c = this.logEntry.LimitsAggregateQueriesMax__c, + LimitsAggregateQueriesUsed__c = this.logEntry.LimitsAggregateQueriesUsed__c, + LimitsAsyncCallsMax__c = this.logEntry.LimitsAsyncCallsMax__c, + LimitsAsyncCallsUsed__c = this.logEntry.LimitsAsyncCallsUsed__c, + LimitsCalloutsUsed__c = this.logEntry.LimitsCalloutsUsed__c, + LimitsCpuTimeMax__c = this.logEntry.LimitsCpuTimeMax__c, + LimitsCpuTimeUsed__c = this.logEntry.LimitsCpuTimeUsed__c, + LimitsDmlRowsMax__c = this.logEntry.LimitsDmlRowsMax__c, + LimitsDmlRowsUsed__c = this.logEntry.LimitsDmlRowsUsed__c, + LimitsDmlStatementsMax__c = this.logEntry.LimitsDmlStatementsMax__c, + LimitsDmlStatementsUsed__c = this.logEntry.LimitsDmlStatementsUsed__c, + LimitsEmailInvocationsMax__c = this.logEntry.LimitsEmailInvocationsMax__c, + LimitsEmailInvocationsUsed__c = this.logEntry.LimitsEmailInvocationsUsed__c, + LimitsFutureCallsMax__c = this.logEntry.LimitsFutureCallsMax__c, + LimitsFutureCallsUsed__c = this.logEntry.LimitsFutureCallsUsed__c, + LimitsHeapSizeMax__c = this.logEntry.LimitsHeapSizeMax__c, + LimitsHeapSizeUsed__c = this.logEntry.LimitsHeapSizeUsed__c, + LimitsMobilePushApexCallsMax__c = this.logEntry.LimitsMobilePushApexCallsMax__c, + LimitsMobilePushApexCallsUsed__c = this.logEntry.LimitsMobilePushApexCallsUsed__c, + LimitsPublishImmediateDmlStatementsMax__c = this.logEntry.LimitsPublishImmediateDmlStatementsMax__c, + LimitsPublishImmediateDmlStatementsUsed__c = this.logEntry.LimitsPublishImmediateDmlStatementsUsed__c, + LimitsQueueableJobsMax__c = this.logEntry.LimitsQueueableJobsMax__c, + LimitsQueueableJobsUsed__c = this.logEntry.LimitsQueueableJobsUsed__c, + LimitsSoqlQueriesMax__c = this.logEntry.LimitsSoqlQueriesMax__c, + LimitsSoqlQueriesUsed__c = this.logEntry.LimitsSoqlQueriesUsed__c, + LimitsSoqlQueryLocatorRowsMax__c = this.logEntry.LimitsSoqlQueryLocatorRowsMax__c, + LimitsSoqlQueryLocatorRowsUsed__c = this.logEntry.LimitsSoqlQueryLocatorRowsUsed__c, + LimitsSoqlQueryRowsMax__c = this.logEntry.LimitsSoqlQueryRowsMax__c, + LimitsSoqlQueryRowsUsed__c = this.logEntry.LimitsSoqlQueryRowsUsed__c, + LimitsSoslSearchesMax__c = this.logEntry.LimitsSoslSearchesMax__c, + LimitsSoslSearchesUsed__c = this.logEntry.LimitsSoslSearchesUsed__c, + Locale__c = this.logEntry.Log__r.Locale__c, + LogEntryName__c = this.logEntry.Name, + LoggedById__c = this.logEntry.Log__r.LoggedBy__c, + LoggedByUsername__c = this.logEntry.Log__r.LoggedByUsername__c, + LoggerVersionNumber__c = this.logEntry.Log__r.LoggerVersionNumber__c, + LoggingLevel__c = this.logEntry.LoggingLevel__c, + LoggingLevelOrdinal__c = this.logEntry.LoggingLevelOrdinal__c, + LoginApplication__c = this.logEntry.Log__r.LoginApplication__c, + LoginBrowser__c = this.logEntry.Log__r.LoginBrowser__c, + LoginHistoryId__c = this.logEntry.Log__r.LoginHistoryId__c, + LoginPlatform__c = this.logEntry.Log__r.LoginPlatform__c, + LoginType__c = this.logEntry.Log__r.LoginType__c, + LogName__c = this.logEntry.Log__r.Name, + LogoutUrl__c = this.logEntry.Log__r.LogoutUrl__c, + LogPurgeAction__c = this.logEntry.Log__r.LogPurgeAction__c, // TODO Not sure it makes sense to have these fields in archive? Maybe? + LogRetentionDate__c = this.logEntry.Log__r.LogRetentionDate__c, // TODO Not sure it makes sense to have these fields in archive? Maybe? + Message__c = this.logEntry.Message__c, + MessageMasked__c = String.valueOf(this.logEntry.MessageMasked__c), + MessageTruncated__c = String.valueOf(this.logEntry.MessageTruncated__c), + NetworkId__c = this.logEntry.Log__r.NetworkId__c, + NetworkLoginUrl__c = this.logEntry.Log__r.NetworkLoginUrl__c, + NetworkLogoutUrl__c = this.logEntry.Log__r.NetworkLogoutUrl__c, + NetworkSelfRegistrationUrl__c = this.logEntry.Log__r.NetworkSelfRegistrationUrl__c, + NetworkUrlPathPrefix__c = this.logEntry.Log__r.NetworkUrlPathPrefix__c, + OrganizationDomainUrl__c = this.logEntry.Log__r.OrganizationDomainUrl__c, + OrganizationEnvironmentType__c = this.logEntry.Log__r.OrganizationEnvironmentType__c, + OrganizationId__c = this.logEntry.Log__r.OrganizationId__c, + OrganizationInstanceName__c = this.logEntry.Log__r.OrganizationInstanceName__c, + OrganizationInstanceReleaseCycle__c = this.logEntry.Log__r.OrganizationInstanceReleaseCycle__c, // TODO deprecated field + OrganizationName__c = this.logEntry.Log__r.OrganizationName__c, + OrganizationNamespacePrefix__c = this.logEntry.Log__r.OrganizationNamespacePrefix__c, + OrganizationType__c = this.logEntry.Log__r.OrganizationType__c, + OriginLocation__c = this.logEntry.OriginLocation__c, + OriginType__c = this.logEntry.OriginType__c, + ParentLogTransactionId__c = this.logEntry.Log__r.ParentLog__r?.TransactionId__c, + Priority__c = this.logEntry.Log__r.Priority__c, + ProfileId__c = this.logEntry.Log__r.ProfileId__c, + ProfileName__c = this.logEntry.Log__r.ProfileName__c, + RecordCollectionSize__c = this.logEntry.RecordCollectionSize__c, + RecordCollectionType__c = this.logEntry.RecordCollectionType__c, + RecordId__c = this.logEntry.RecordId__c, + RecordJson__c = this.logEntry.RecordJson__c, + RecordJsonMasked__c = String.valueOf(this.logEntry.RecordJsonMasked__c), + RecordName__c = String.valueOf(this.logEntry.RecordName__c), + RecordSObjectClassification__c = this.logEntry.RecordSObjectClassification__c, + RecordSObjectType__c = this.logEntry.RecordSObjectType__c, + RecordSObjectTypeNamespace__c = this.logEntry.RecordSObjectTypeNamespace__c, + SessionId__c = this.logEntry.Log__r.SessionId__c, + SessionSecurityLevel__c = this.logEntry.Log__r.SessionSecurityLevel__c, + SessionType__c = this.logEntry.Log__r.SessionType__c, + SourceIp__c = this.logEntry.Log__r.SourceIp__c, + StackTrace__c = this.logEntry.StackTrace__c, + Status__c = this.logEntry.Log__r.Status__c, + SystemMode__c = this.logEntry.Log__r.SystemMode__c, + Tags__c = String.join(tagNames, '\n'), + ThemeDisplayed__c = this.logEntry.Log__r.ThemeDisplayed__c, + Timestamp__c = this.logEntry.Timestamp__c, + TimestampString__c = String.valueOf(this.logEntry.Timestamp__c), + TimeZoneId__c = this.logEntry.Log__r.TimeZoneId__c, + TransactionEntryNumber__c = this.logEntry.TransactionEntryNumber__c, + TransactionId__c = this.logEntry.Log__r.TransactionId__c, + TriggerIsExecuting__c = String.valueOf(this.logEntry.TriggerIsExecuting__c), + TriggerOperationType__c = this.logEntry.TriggerOperationType__c, + TriggerSObjectType__c = this.logEntry.TriggerSObjectType__c, + UserLicenseDefinitionKey__c = this.logEntry.Log__r.UserLicenseDefinitionKey__c, + UserLicenseName__c = this.logEntry.Log__r.UserLicenseName__c, + UserLoggingLevel__c = this.logEntry.Log__r.UserLoggingLevel__c, + UserLoggingLevelOrdinal__c = this.logEntry.Log__r.UserLoggingLevelOrdinal__c, + UserRoleId__c = this.logEntry.Log__r.UserRoleId__c, + UserRoleName__c = this.logEntry.Log__r.UserRoleName__c, + UserType__c = this.logEntry.Log__r.UserType__c + ); + } + + private void truncateFieldValues() { + for (String fieldName : this.logEntryArchive.getPopulatedFieldsAsMap().keySet()) { + Schema.SObjectField field = Schema.LogEntryArchive__b.SObjectType.getDescribe().fields.getMap().get(fieldName); + if (field.getDescribe().getSoapType() == Schema.SoapType.STRING) { + String fieldValue = (String) this.logEntryArchive.get(field); + this.logEntryArchive.put(field, fieldValue?.left(field.getDescribe().getLength())); + } + } + } +} diff --git a/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveBuilder.cls-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveBuilder.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveBuilder.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveBuilder_Tests.cls b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveBuilder_Tests.cls new file mode 100644 index 000000000..ef615922d --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveBuilder_Tests.cls @@ -0,0 +1,863 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +@SuppressWarnings('PMD.ApexDoc, PMD.ApexAssertionsShouldIncludeMessage, PMD.MethodNamingConventions') +@IsTest(IsParallel=true) +private class LogEntryArchiveBuilder_Tests { + @IsTest + static void it_should_write_all_fields_over_from_log_entry_event() { + Datetime timestamp = System.now(); + LogEntryEvent__e mockEvent = (LogEntryEvent__e) LoggerMockDataCreator.createDataBuilder(Schema.LogEntryEvent__e.SObjectType) + .populateAllFields() + .getRecord(); + mockEvent = (LogEntryEvent__e) LoggerMockDataCreator.setReadOnlyField(mockEvent, Schema.LogEntryEvent__e.EventUuid, 'abc-xyz-some-value'); + mockEvent.LoggingLevel__c = LoggingLevel.INFO.name(); + mockEvent.Timestamp__c = timestamp; + mockEvent.TimestampString__c = String.valueOf(timestamp.getTime()); + + LogEntryArchive__b logEntryArchive = new LogEntryArchiveBuilder(mockEvent).getLogEntryArchive(); + + System.assertNotEquals(null, logEntryArchive); + assertAllFieldsMatch(timestamp, mockEvent, logEntryArchive); + } + + @IsTest + static void it_should_cache_instance_of_log_entry_archive_for_log_entry_event() { + LogEntryEvent__e mockEvent = (LogEntryEvent__e) LoggerMockDataCreator.createDataBuilder(Schema.LogEntryEvent__e.SObjectType) + .populateAllFields() + .getRecord(); + mockEvent = (LogEntryEvent__e) LoggerMockDataCreator.setReadOnlyField(mockEvent, Schema.LogEntryEvent__e.EventUuid, 'abc-xyz-some-value'); + LogEntryArchiveBuilder archiveBuilder = new LogEntryArchiveBuilder(mockEvent); + LogEntryArchive__b originalLogEntryArchive = archiveBuilder.getLogEntryArchive(); + originalLogEntryArchive.Message__c = 'Some new value'; + + LogEntryArchive__b secondLogEntryArchive = archiveBuilder.getLogEntryArchive(); + + System.assertEquals(originalLogEntryArchive, secondLogEntryArchive); + } + + @IsTest + static void it_should_truncate_log_entry_archive_field_values_when_too_long() { + LogEntryEvent__e mockEvent = (LogEntryEvent__e) LoggerMockDataCreator.createDataBuilder(Schema.LogEntryEvent__e.SObjectType) + .populateAllFields() + .getRecord(); + mockEvent = (LogEntryEvent__e) LoggerMockDataCreator.setReadOnlyField(mockEvent, Schema.LogEntryEvent__e.EventUuid, 'abc-xyz-some-value'); + mockEvent.Message__c = 'Z'.repeat(Schema.LogEntryArchive__b.Message__c.getDescribe().getLength() + 1); + LogEntryArchive__b logEntryArchive = new LogEntryArchiveBuilder(mockEvent).getLogEntryArchive(); + + System.assertNotEquals(mockEvent.Message__c, logEntryArchive.Message__c); + System.assertEquals(mockEvent.Message__c.left(Schema.LogEntryArchive__b.Message__c.getDescribe().getLength()), logEntryArchive.Message__c); + } + + @IsTest + static void it_should_write_all_fields_over_from_log_entry() { + LogEntry__c mockLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType).populateAllFields().getRecord(); + mockLogEntry.Log__r = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateAllFields().getRecord(); + mockLogEntry.LoggingLevel__c = LoggingLevel.INFO.name(); + + LogEntryArchive__b logEntryArchive = new LogEntryArchiveBuilder(mockLogEntry).getLogEntryArchive(); + + System.assertNotEquals(null, logEntryArchive); + assertAllFieldsMatch(mockLogEntry, logEntryArchive); + } + + @IsTest + static void it_should_cache_instance_of_log_entry_archive_for_log_entry() { + LogEntry__c mockLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType).populateRequiredFields().getRecord(); + mockLogEntry.Log__r = (Log__c) LoggerMockDataCreator.createDataBuilder(Schema.Log__c.SObjectType).populateRequiredFields().getRecord(); + LogEntryArchiveBuilder archiveBuilder = new LogEntryArchiveBuilder(mockLogEntry); + LogEntryArchive__b originalLogEntryArchive = archiveBuilder.getLogEntryArchive(); + originalLogEntryArchive.Message__c = 'Some new value'; + + LogEntryArchive__b secondLogEntryArchive = archiveBuilder.getLogEntryArchive(); + + System.assertEquals(originalLogEntryArchive, secondLogEntryArchive); + System.assertEquals(originalLogEntryArchive.Message__c, secondLogEntryArchive.Message__c); + } + + @IsTest + static void it_should_truncate_log_entry_field_values_when_too_long() { + LogEntry__c mockLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType).populateRequiredFields().getRecord(); + mockLogEntry.Message__c = 'Z'.repeat(Schema.LogEntryArchive__b.Message__c.getDescribe().getLength() + 1); + LogEntryArchive__b logEntryArchive = new LogEntryArchiveBuilder(mockLogEntry).getLogEntryArchive(); + + System.assertNotEquals(mockLogEntry.Message__c, logEntryArchive.Message__c); + System.assertEquals(mockLogEntry.Message__c.left(Schema.LogEntryArchive__b.Message__c.getDescribe().getLength()), logEntryArchive.Message__c); + } + + @SuppressWarnings('PMD.NcssMethodCount') + private static void assertAllFieldsMatch(Datetime timestamp, LogEntryEvent__e mockEvent, LogEntryArchive__b logEntryArchive) { + System.assertEquals(mockEvent.ApiVersion__c, logEntryArchive.ApiVersion__c, 'logEntryArchive.ApiVersion__c was not properly set'); + System.assertEquals(UserInfo.getUserId(), logEntryArchive.ArchivedById__c, 'logEntryArchive.ArchivedById__c was not properly set'); + System.assertNotEquals(null, logEntryArchive.ArchivedDate__c, 'logEntryArchive.ArchivedDate__c was not properly set'); + System.assertEquals(System.today(), logEntryArchive.ArchivedDate__c.date(), 'logEntryArchive.ArchivedDate__c was not properly set'); + System.assertEquals(UserInfo.getUsername(), logEntryArchive.ArchivedByUsername__c, 'logEntryArchive.ArchivedByUsername__c was not properly set'); + System.assertEquals(mockEvent.ComponentType__c, logEntryArchive.ComponentType__c, 'logEntryArchive.ComponentType__c was not properly set'); + System.assertEquals( + mockEvent.DatabaseResultCollectionSize__c, + logEntryArchive.DatabaseResultCollectionSize__c, + 'logEntryArchive.DatabaseResultCollectionSize__c was not properly set' + ); + System.assertEquals( + mockEvent.DatabaseResultCollectionType__c, + logEntryArchive.DatabaseResultCollectionType__c, + 'logEntryArchive.DatabaseResultCollectionType__c was not properly set' + ); + System.assertEquals( + mockEvent.DatabaseResultJson__c, + logEntryArchive.DatabaseResultJson__c, + 'logEntryArchive.DatabaseResultJson__c was not properly set' + ); + System.assertEquals( + mockEvent.DatabaseResultType__c, + logEntryArchive.DatabaseResultType__c, + 'logEntryArchive.DatabaseResultType__c was not properly set' + ); + System.assertEquals(mockEvent.EpochTimestamp__c, logEntryArchive.EpochTimestamp__c, 'logEntryArchive.EpochTimestamp__c was not properly set'); + System.assertEquals(mockEvent.EventUuid, logEntryArchive.EventUuid__c, 'logEntryArchive.EventUuid__c was not properly set'); + System.assertEquals(mockEvent.ExceptionMessage__c, logEntryArchive.ExceptionMessage__c, 'logEntryArchive.ExceptionMessage__c was not properly set'); + System.assertEquals( + mockEvent.ExceptionStackTrace__c, + logEntryArchive.ExceptionStackTrace__c, + 'logEntryArchive.ExceptionStackTrace__c was not properly set' + ); + System.assertEquals(mockEvent.ExceptionType__c, logEntryArchive.ExceptionType__c, 'logEntryArchive.ExceptionType__c was not properly set'); + System.assertEquals( + String.valueOf(mockEvent.HttpRequestBody__c), + logEntryArchive.HttpRequestBody__c, + 'logEntryArchive.HttpRequestBody__c was not properly set' + ); + System.assertEquals( + String.valueOf(mockEvent.HttpRequestCompressed__c), + logEntryArchive.HttpRequestCompressed__c, + 'logEntryArchive.HttpRequestCompressed__c was not properly set' + ); + System.assertEquals( + mockEvent.HttpRequestEndpoint__c, + logEntryArchive.HttpRequestEndpoint__c, + 'logEntryArchive.HttpRequestEndpoint__c was not properly set' + ); + System.assertEquals(mockEvent.HttpRequestMethod__c, logEntryArchive.HttpRequestMethod__c, 'logEntryArchive.HttpRequestMethod__c was not properly set'); + System.assertEquals(mockEvent.HttpResponseBody__c, logEntryArchive.HttpResponseBody__c, 'logEntryArchive.HttpResponseBody__c was not properly set'); + System.assertEquals( + mockEvent.HttpResponseHeaderKeys__c, + logEntryArchive.HttpResponseHeaderKeys__c, + 'logEntryArchive.HttpResponseHeaderKeys__c was not properly set' + ); + System.assertEquals( + mockEvent.HttpResponseStatus__c, + logEntryArchive.HttpResponseStatus__c, + 'logEntryArchive.HttpResponseStatus__c was not properly set' + ); + System.assertEquals( + mockEvent.HttpResponseStatusCode__c, + logEntryArchive.HttpResponseStatusCode__c, + 'logEntryArchive.HttpResponseStatusCode__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsAggregateQueriesMax__c, + logEntryArchive.LimitsAggregateQueriesMax__c, + 'logEntryArchive.LimitsAggregateQueriesMax__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsAggregateQueriesUsed__c, + logEntryArchive.LimitsAggregateQueriesUsed__c, + 'logEntryArchive.LimitsAggregateQueriesUsed__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsAsyncCallsMax__c, + logEntryArchive.LimitsAsyncCallsMax__c, + 'logEntryArchive.LimitsAsyncCallsMax__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsAsyncCallsUsed__c, + logEntryArchive.LimitsAsyncCallsUsed__c, + 'logEntryArchive.LimitsAsyncCallsUsed__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsCalloutsUsed__c, + logEntryArchive.LimitsCalloutsUsed__c, + 'logEntryArchive.LimitsCalloutsUsed__c was not properly set' + ); + System.assertEquals(mockEvent.LimitsCpuTimeMax__c, logEntryArchive.LimitsCpuTimeMax__c, 'logEntryArchive.LimitsCpuTimeMax__c was not properly set'); + System.assertEquals(mockEvent.LimitsCpuTimeUsed__c, logEntryArchive.LimitsCpuTimeUsed__c, 'logEntryArchive.LimitsCpuTimeUsed__c was not properly set'); + System.assertEquals(mockEvent.LimitsDmlRowsMax__c, logEntryArchive.LimitsDmlRowsMax__c, 'logEntryArchive.LimitsDmlRowsMax__c was not properly set'); + System.assertEquals(mockEvent.LimitsDmlRowsUsed__c, logEntryArchive.LimitsDmlRowsUsed__c, 'logEntryArchive.LimitsDmlRowsUsed__c was not properly set'); + System.assertEquals( + mockEvent.LimitsDmlStatementsMax__c, + logEntryArchive.LimitsDmlStatementsMax__c, + 'logEntryArchive.LimitsDmlStatementsMax__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsDmlStatementsUsed__c, + logEntryArchive.LimitsDmlStatementsUsed__c, + 'logEntryArchive.LimitsDmlStatementsUsed__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsEmailInvocationsMax__c, + logEntryArchive.LimitsEmailInvocationsMax__c, + 'logEntryArchive.LimitsEmailInvocationsMax__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsEmailInvocationsUsed__c, + logEntryArchive.LimitsEmailInvocationsUsed__c, + 'logEntryArchive.LimitsEmailInvocationsUsed__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsFutureCallsMax__c, + logEntryArchive.LimitsFutureCallsMax__c, + 'logEntryArchive.LimitsFutureCallsMax__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsFutureCallsUsed__c, + logEntryArchive.LimitsFutureCallsUsed__c, + 'logEntryArchive.LimitsFutureCallsUsed__c was not properly set' + ); + System.assertEquals(mockEvent.LimitsHeapSizeMax__c, logEntryArchive.LimitsHeapSizeMax__c, 'logEntryArchive.LimitsHeapSizeMax__c was not properly set'); + System.assertEquals( + mockEvent.LimitsHeapSizeUsed__c, + logEntryArchive.LimitsHeapSizeUsed__c, + 'logEntryArchive.LimitsHeapSizeUsed__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsPublishImmediateDmlStatementsMax__c, + logEntryArchive.LimitsPublishImmediateDmlStatementsMax__c, + 'logEntryArchive.LimitsPublishImmediateDmlStatementsMax__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsPublishImmediateDmlStatementsUsed__c, + logEntryArchive.LimitsPublishImmediateDmlStatementsUsed__c, + 'logEntryArchive.LimitsPublishImmediateDmlStatementsUsed__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsMobilePushApexCallsMax__c, + logEntryArchive.LimitsMobilePushApexCallsMax__c, + 'logEntryArchive.LimitsMobilePushApexCallsMax__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsMobilePushApexCallsUsed__c, + logEntryArchive.LimitsMobilePushApexCallsUsed__c, + 'logEntryArchive.LimitsMobilePushApexCallsUsed__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsQueueableJobsMax__c, + logEntryArchive.LimitsQueueableJobsMax__c, + 'logEntryArchive.LimitsQueueableJobsMax__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsQueueableJobsUsed__c, + logEntryArchive.LimitsQueueableJobsUsed__c, + 'logEntryArchive.LimitsQueueableJobsUsed__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsSoqlQueriesMax__c, + logEntryArchive.LimitsSoqlQueriesMax__c, + 'logEntryArchive.LimitsSoqlQueriesMax__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsSoqlQueriesUsed__c, + logEntryArchive.LimitsSoqlQueriesUsed__c, + 'logEntryArchive.LimitsSoqlQueriesUsed__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsSoqlQueryLocatorRowsMax__c, + logEntryArchive.LimitsSoqlQueryLocatorRowsMax__c, + 'logEntryArchive.LimitsSoqlQueryLocatorRowsMax__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsSoqlQueryLocatorRowsUsed__c, + logEntryArchive.LimitsSoqlQueryLocatorRowsUsed__c, + 'logEntryArchive.LimitsSoqlQueryLocatorRowsUsed__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsSoqlQueryRowsMax__c, + logEntryArchive.LimitsSoqlQueryRowsMax__c, + 'logEntryArchive.LimitsSoqlQueryRowsMax__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsSoqlQueryRowsUsed__c, + logEntryArchive.LimitsSoqlQueryRowsUsed__c, + 'logEntryArchive.LimitsSoqlQueryRowsUsed__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsSoslSearchesMax__c, + logEntryArchive.LimitsSoslSearchesMax__c, + 'logEntryArchive.LimitsSoslSearchesMax__c was not properly set' + ); + System.assertEquals( + mockEvent.LimitsSoslSearchesUsed__c, + logEntryArchive.LimitsSoslSearchesUsed__c, + 'logEntryArchive.LimitsSoslSearchesUsed__c was not properly set' + ); + System.assertEquals(mockEvent.Locale__c, logEntryArchive.Locale__c, 'logEntryArchive.Locale__c was not properly set'); + // System.assertEquals(String.isNotBlank(mockEvent.LoggedById__c) ? mockEvent.LoggedById__c : 'Anonymous', logEntryArchive.LoggedBy__c); + System.assertEquals(mockEvent.LoggedById__c, logEntryArchive.LoggedById__c, 'logEntryArchive.LoggedById__c was not properly set'); + System.assertEquals( + String.isNotBlank(mockEvent.LoggedByUsername__c) ? mockEvent.LoggedByUsername__c : 'Anonymous', + logEntryArchive.LoggedByUsername__c, + 'logEntryArchive.LoggedByUsername__c was not properly set' + ); + System.assertEquals( + mockEvent.LoggerVersionNumber__c, + logEntryArchive.LoggerVersionNumber__c, + 'logEntryArchive.LoggerVersionNumber__c was not properly set' + ); + System.assertEquals(mockEvent.LoggingLevel__c, logEntryArchive.LoggingLevel__c, 'logEntryArchive.LoggingLevel__c was not properly set'); + System.assertEquals( + mockEvent.LoggingLevelOrdinal__c, + logEntryArchive.LoggingLevelOrdinal__c, + 'logEntryArchive.LoggingLevelOrdinal__c was not properly set' + ); + System.assertEquals(mockEvent.LoginApplication__c, logEntryArchive.LoginApplication__c, 'logEntryArchive.LoginApplication__c was not properly set'); + System.assertEquals(mockEvent.LoginBrowser__c, logEntryArchive.LoginBrowser__c, 'logEntryArchive.LoginBrowser__c was not properly set'); + System.assertEquals(mockEvent.LoginHistoryId__c, logEntryArchive.LoginHistoryId__c, 'logEntryArchive.LoginHistoryId__c was not properly set'); + System.assertEquals(mockEvent.LoginPlatform__c, logEntryArchive.LoginPlatform__c, 'logEntryArchive.LoginPlatform__c was not properly set'); + System.assertEquals(mockEvent.LoginType__c, logEntryArchive.LoginType__c, 'logEntryArchive.LoginType__c was not properly set'); + System.assertEquals(mockEvent.LogoutUrl__c, logEntryArchive.LogoutUrl__c, 'logEntryArchive.LogoutUrl__c was not properly set'); + System.assertEquals(mockEvent.Message__c, logEntryArchive.Message__c, 'logEntryArchive.Message__c was not properly set'); + System.assertEquals(mockEvent.NetworkId__c, logEntryArchive.NetworkId__c, 'logEntryArchive.NetworkId__c was not properly set'); + System.assertEquals(mockEvent.NetworkLoginUrl__c, logEntryArchive.NetworkLoginUrl__c, 'logEntryArchive.NetworkLoginUrl__c was not properly set'); + System.assertEquals(mockEvent.NetworkLogoutUrl__c, logEntryArchive.NetworkLogoutUrl__c, 'logEntryArchive.NetworkLogoutUrl__c was not properly set'); + System.assertEquals( + mockEvent.NetworkSelfRegistrationUrl__c, + logEntryArchive.NetworkSelfRegistrationUrl__c, + 'logEntryArchive.NetworkSelfRegistrationUrl__c was not properly set' + ); + System.assertEquals( + mockEvent.NetworkUrlPathPrefix__c, + logEntryArchive.NetworkUrlPathPrefix__c, + 'logEntryArchive.NetworkUrlPathPrefix__c was not properly set' + ); + System.assertEquals( + mockEvent.OrganizationDomainUrl__c, + logEntryArchive.OrganizationDomainUrl__c, + 'logEntryArchive.OrganizationDomainUrl__c was not properly set' + ); + System.assertEquals( + mockEvent.OrganizationEnvironmentType__c, + logEntryArchive.OrganizationEnvironmentType__c, + 'logEntryArchive.OrganizationEnvironmentType__c was not properly set' + ); + System.assertEquals(mockEvent.OrganizationId__c, logEntryArchive.OrganizationId__c, 'logEntryArchive.OrganizationId__c was not properly set'); + System.assertEquals( + mockEvent.OrganizationInstanceName__c, + logEntryArchive.OrganizationInstanceName__c, + 'logEntryArchive.OrganizationInstanceName__c was not properly set' + ); + System.assertEquals(mockEvent.OrganizationName__c, logEntryArchive.OrganizationName__c, 'logEntryArchive.OrganizationName__c was not properly set'); + System.assertEquals( + mockEvent.OrganizationNamespacePrefix__c, + logEntryArchive.OrganizationNamespacePrefix__c, + 'logEntryArchive.OrganizationNamespacePrefix__c was not properly set' + ); + System.assertEquals(mockEvent.OrganizationType__c, logEntryArchive.OrganizationType__c, 'logEntryArchive.OrganizationType__c was not properly set'); + System.assertEquals(mockEvent.OriginLocation__c, logEntryArchive.OriginLocation__c, 'logEntryArchive.OriginLocation__c was not properly set'); + System.assertEquals(mockEvent.OriginType__c, logEntryArchive.OriginType__c, 'logEntryArchive.OriginType__c was not properly set'); + System.assertEquals( + mockEvent.ParentLogTransactionId__c, + logEntryArchive.ParentLogTransactionId__c, + 'logEntryArchive.ParentLogTransactionId__c was not properly set' + ); + System.assertEquals(mockEvent.ProfileId__c, logEntryArchive.ProfileId__c, 'logEntryArchive.ProfileId__c was not properly set'); + System.assertEquals(mockEvent.ProfileName__c, logEntryArchive.ProfileName__c, 'logEntryArchive.ProfileName__c was not properly set'); + System.assertEquals( + mockEvent.RecordCollectionSize__c, + logEntryArchive.RecordCollectionSize__c, + 'logEntryArchive.RecordCollectionSize__c was not properly set' + ); + System.assertEquals( + mockEvent.RecordCollectionType__c, + logEntryArchive.RecordCollectionType__c, + 'logEntryArchive.RecordCollectionType__c was not properly set' + ); + System.assertEquals(mockEvent.RecordId__c, logEntryArchive.RecordId__c, 'logEntryArchive.RecordId__c was not properly set'); + System.assertEquals(mockEvent.RecordJson__c, logEntryArchive.RecordJson__c, 'logEntryArchive.RecordJson__c was not properly set'); + System.assertEquals( + mockEvent.RecordSObjectClassification__c, + logEntryArchive.RecordSObjectClassification__c, + 'logEntryArchive.RecordSObjectClassification__c was not properly set' + ); + System.assertEquals(mockEvent.RecordSObjectType__c, logEntryArchive.RecordSObjectType__c, 'logEntryArchive.RecordSObjectType__c was not properly set'); + System.assertEquals( + mockEvent.RecordSObjectTypeNamespace__c, + logEntryArchive.RecordSObjectTypeNamespace__c, + 'logEntryArchive.RecordSObjectTypeNamespace__c was not properly set' + ); + System.assertEquals(mockEvent.SessionId__c, logEntryArchive.SessionId__c, 'logEntryArchive.SessionId__c was not properly set'); + System.assertEquals( + mockEvent.SessionSecurityLevel__c, + logEntryArchive.SessionSecurityLevel__c, + 'logEntryArchive.SessionSecurityLevel__c was not properly set' + ); + System.assertEquals(mockEvent.SessionType__c, logEntryArchive.SessionType__c, 'logEntryArchive.SessionType__c was not properly set'); + System.assertEquals(mockEvent.SourceIp__c, logEntryArchive.SourceIp__c, 'logEntryArchive.SourceIp__c was not properly set'); + System.assertEquals(mockEvent.StackTrace__c, logEntryArchive.StackTrace__c, 'logEntryArchive.StackTrace__c was not properly set'); + System.assertEquals(mockEvent.SystemMode__c, logEntryArchive.SystemMode__c, 'logEntryArchive.SystemMode__c was not properly set'); + System.assertEquals(mockEvent.Tags__c, logEntryArchive.Tags__c, 'logEntryArchive.Tags__c was not properly set'); + System.assertEquals(mockEvent.ThemeDisplayed__c, logEntryArchive.ThemeDisplayed__c, 'logEntryArchive.ThemeDisplayed__c was not properly set'); + System.assertEquals(timestamp, logEntryArchive.Timestamp__c, 'logEntryArchive.Timestamp__c was not properly set'); + System.assertEquals(String.valueOf(timestamp.getTime()), logEntryArchive.TimestampString__c, 'logEntryArchive.TimestampString__c was not properly set'); + System.assertEquals(mockEvent.TimeZoneId__c, logEntryArchive.TimeZoneId__c, 'logEntryArchive.TimeZoneId__c was not properly set'); + System.assertEquals( + mockEvent.TransactionEntryNumber__c, + logEntryArchive.TransactionEntryNumber__c, + 'logEntryArchive.TransactionEntryNumber__c was not properly set' + ); + System.assertEquals(mockEvent.TransactionId__c, logEntryArchive.TransactionId__c, 'logEntryArchive.TransactionId__c was not properly set'); + System.assertEquals( + mockEvent.TriggerOperationType__c, + logEntryArchive.TriggerOperationType__c, + 'logEntryArchive.TriggerOperationType__c was not properly set' + ); + System.assertEquals( + mockEvent.TriggerSObjectType__c, + logEntryArchive.TriggerSObjectType__c, + 'logEntryArchive.TriggerSObjectType__c was not properly set' + ); + System.assertEquals( + mockEvent.UserLicenseDefinitionKey__c, + logEntryArchive.UserLicenseDefinitionKey__c, + 'logEntryArchive.UserLicenseDefinitionKey__c was not properly set' + ); + System.assertEquals(mockEvent.UserLicenseName__c, logEntryArchive.UserLicenseName__c, 'logEntryArchive.UserLicenseName__c was not properly set'); + System.assertEquals(mockEvent.UserLoggingLevel__c, logEntryArchive.UserLoggingLevel__c, 'logEntryArchive.UserLoggingLevel__c was not properly set'); + System.assertEquals( + mockEvent.UserLoggingLevelOrdinal__c, + logEntryArchive.UserLoggingLevelOrdinal__c, + 'logEntryArchive.UserLoggingLevelOrdinal__c was not properly set' + ); + System.assertEquals(mockEvent.UserRoleId__c, logEntryArchive.UserRoleId__c, 'logEntryArchive.UserRoleId__c was not properly set'); + System.assertEquals(mockEvent.UserRoleName__c, logEntryArchive.UserRoleName__c, 'logEntryArchive.UserRoleName__c was not properly set'); + System.assertEquals(mockEvent.UserType__c, logEntryArchive.UserType__c, 'logEntryArchive.UserType__c was not properly set'); + } + + @SuppressWarnings('PMD.NcssMethodCount') + private static void assertAllFieldsMatch(LogEntry__c logEntry, LogEntryArchive__b logEntryArchive) { + List tagNames = new List(); + for (LogEntryTag__c logEntryTag : logEntry.LogEntryTags__r) { + tagNames.add(logEntryTag.Tag__r.Name); + } + tagNames = new List(new Set(tagNames)); + tagNames.sort(); + String tags = String.join(tagNames, '\n'); + + System.assertEquals( + logEntry.Log__r.ApiReleaseNumber__c, + logEntryArchive.ApiReleaseNumber__c, + 'logEntryArchive.ApiReleaseNumber__c was not properly set' + ); + System.assertEquals( + logEntry.Log__r.ApiReleaseVersion__c, + logEntryArchive.ApiReleaseVersion__c, + 'logEntryArchive.ApiReleaseVersion__c was not properly set' + ); + System.assertEquals(logEntry.Log__r.ApiVersion__c, logEntryArchive.ApiVersion__c, 'logEntryArchive.ApiVersion__c was not properly set'); + System.assertEquals(UserInfo.getUserId(), logEntryArchive.ArchivedById__c, 'logEntryArchive.ArchivedById__c was not properly set'); + System.assertNotEquals(null, logEntryArchive.ArchivedDate__c, 'logEntryArchive.ArchivedDate__c was not properly set'); + System.assertEquals(System.today(), logEntryArchive.ArchivedDate__c.date(), 'logEntryArchive.ArchivedDate__c was not properly set'); + System.assertEquals(UserInfo.getUsername(), logEntryArchive.ArchivedByUsername__c, 'logEntryArchive.ArchivedByUsername__c was not properly set'); + System.assertEquals(logEntry.Log__r.ClosedBy__c, logEntryArchive.ClosedById__c, 'logEntryArchive.ClosedById__c was not properly set'); + System.assertEquals( + logEntry.Log__r.ClosedBy__r?.Username, + logEntryArchive.ClosedByUsername__c, + 'logEntryArchive.ClosedByUsername__c was not properly set' + ); + System.assertEquals(logEntry.Log__r.ClosedDate__c, logEntryArchive.ClosedDate__c, 'logEntryArchive.ClosedDate__c was not properly set'); + System.assertEquals(logEntry.Log__r.Comments__c, logEntryArchive.Comments__c, 'logEntryArchive.Comments__c was not properly set'); + System.assertEquals(logEntry.ComponentType__c, logEntryArchive.ComponentType__c, 'logEntryArchive.ComponentType__c was not properly set'); + System.assertEquals( + logEntry.DatabaseResultCollectionSize__c, + logEntryArchive.DatabaseResultCollectionSize__c, + 'logEntryArchive.DatabaseResultCollectionSize__c was not properly set' + ); + System.assertEquals( + logEntry.DatabaseResultCollectionType__c, + logEntryArchive.DatabaseResultCollectionType__c, + 'logEntryArchive.DatabaseResultCollectionType__c was not properly set' + ); + System.assertEquals( + logEntry.DatabaseResultJson__c, + logEntryArchive.DatabaseResultJson__c, + 'logEntryArchive.DatabaseResultJson__c was not properly set' + ); + System.assertEquals( + logEntry.DatabaseResultType__c, + logEntryArchive.DatabaseResultType__c, + 'logEntryArchive.DatabaseResultType__c was not properly set' + ); + System.assertEquals(logEntry.EpochTimestamp__c, logEntryArchive.EpochTimestamp__c, 'logEntryArchive.EpochTimestamp__c was not properly set'); + System.assertEquals(logEntry.EventUuid__c, logEntryArchive.EventUuid__c, 'logEntryArchive.EventUuid__c was not properly set'); + System.assertEquals(logEntry.ExceptionMessage__c, logEntryArchive.ExceptionMessage__c, 'logEntryArchive.ExceptionMessage__c was not properly set'); + System.assertEquals( + logEntry.ExceptionStackTrace__c, + logEntryArchive.ExceptionStackTrace__c, + 'logEntryArchive.ExceptionStackTrace__c was not properly set' + ); + System.assertEquals(logEntry.ExceptionType__c, logEntryArchive.ExceptionType__c, 'logEntryArchive.ExceptionType__c was not properly set'); + System.assertEquals(logEntry.HttpRequestBody__c, logEntryArchive.HttpRequestBody__c, 'logEntryArchive.HttpRequestBody__c was not properly set'); + System.assertEquals( + String.valueOf(logEntry.HttpRequestBodyMasked__c), + logEntryArchive.HttpRequestBodyMasked__c, + 'logEntryArchive.HttpRequestBodyMasked__c was not properly set' + ); + System.assertEquals( + logEntry.HttpRequestEndpoint__c, + logEntryArchive.HttpRequestEndpoint__c, + 'logEntryArchive.HttpRequestEndpoint__c was not properly set' + ); + System.assertEquals(logEntry.HttpRequestMethod__c, logEntryArchive.HttpRequestMethod__c, 'logEntryArchive.HttpRequestMethod__c was not properly set'); + System.assertEquals(logEntry.HttpResponseBody__c, logEntryArchive.HttpResponseBody__c, 'logEntryArchive.HttpResponseBody__c was not properly set'); + System.assertEquals( + String.valueOf(logEntry.HttpResponseBodyMasked__c), + logEntryArchive.HttpResponseBodyMasked__c, + 'logEntryArchive.HttpResponseBodyMasked__c was not properly set' + ); + System.assertEquals( + logEntry.HttpResponseHeaderKeys__c, + logEntryArchive.HttpResponseHeaderKeys__c, + 'logEntryArchive.HttpResponseHeaderKeys__c was not properly set' + ); + System.assertEquals( + logEntry.HttpResponseStatus__c, + logEntryArchive.HttpResponseStatus__c, + 'logEntryArchive.HttpResponseStatus__c was not properly set' + ); + System.assertEquals( + logEntry.HttpResponseStatusCode__c, + logEntryArchive.HttpResponseStatusCode__c, + 'logEntryArchive.HttpResponseStatusCode__c was not properly set' + ); + System.assertEquals(String.valueOf(logEntry.Log__r.IsClosed__c), logEntryArchive.IsClosed__c, 'logEntryArchive.IsClosed__c was not properly set'); + System.assertEquals(String.valueOf(logEntry.Log__r.IsResolved__c), logEntryArchive.IsResolved__c, 'logEntryArchive.IsResolved__c was not properly set'); + System.assertEquals(logEntry.Log__r.Issue__c, logEntryArchive.Issue__c, 'logEntryArchive.Issue__c was not properly set'); + System.assertEquals( + logEntry.LimitsAggregateQueriesMax__c, + logEntryArchive.LimitsAggregateQueriesMax__c, + 'logEntryArchive.LimitsAggregateQueriesMax__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsAggregateQueriesUsed__c, + logEntryArchive.LimitsAggregateQueriesUsed__c, + 'logEntryArchive.LimitsAggregateQueriesUsed__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsAsyncCallsMax__c, + logEntryArchive.LimitsAsyncCallsMax__c, + 'logEntryArchive.LimitsAsyncCallsMax__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsAsyncCallsUsed__c, + logEntryArchive.LimitsAsyncCallsUsed__c, + 'logEntryArchive.LimitsAsyncCallsUsed__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsCalloutsUsed__c, + logEntryArchive.LimitsCalloutsUsed__c, + 'logEntryArchive.LimitsCalloutsUsed__c was not properly set' + ); + System.assertEquals(logEntry.LimitsCpuTimeMax__c, logEntryArchive.LimitsCpuTimeMax__c, 'logEntryArchive.LimitsCpuTimeMax__c was not properly set'); + System.assertEquals(logEntry.LimitsCpuTimeUsed__c, logEntryArchive.LimitsCpuTimeUsed__c, 'logEntryArchive.LimitsCpuTimeUsed__c was not properly set'); + System.assertEquals(logEntry.LimitsDmlRowsMax__c, logEntryArchive.LimitsDmlRowsMax__c, 'logEntryArchive.LimitsDmlRowsMax__c was not properly set'); + System.assertEquals(logEntry.LimitsDmlRowsUsed__c, logEntryArchive.LimitsDmlRowsUsed__c, 'logEntryArchive.LimitsDmlRowsUsed__c was not properly set'); + System.assertEquals( + logEntry.LimitsDmlStatementsMax__c, + logEntryArchive.LimitsDmlStatementsMax__c, + 'logEntryArchive.LimitsDmlStatementsMax__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsDmlStatementsUsed__c, + logEntryArchive.LimitsDmlStatementsUsed__c, + 'logEntryArchive.LimitsDmlStatementsUsed__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsEmailInvocationsMax__c, + logEntryArchive.LimitsEmailInvocationsMax__c, + 'logEntryArchive.LimitsEmailInvocationsMax__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsEmailInvocationsUsed__c, + logEntryArchive.LimitsEmailInvocationsUsed__c, + 'logEntryArchive.LimitsEmailInvocationsUsed__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsFutureCallsMax__c, + logEntryArchive.LimitsFutureCallsMax__c, + 'logEntryArchive.LimitsFutureCallsMax__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsFutureCallsUsed__c, + logEntryArchive.LimitsFutureCallsUsed__c, + 'logEntryArchive.LimitsFutureCallsUsed__c was not properly set' + ); + System.assertEquals(logEntry.LimitsHeapSizeMax__c, logEntryArchive.LimitsHeapSizeMax__c, 'logEntryArchive.LimitsHeapSizeMax__c was not properly set'); + System.assertEquals( + logEntry.LimitsHeapSizeUsed__c, + logEntryArchive.LimitsHeapSizeUsed__c, + 'logEntryArchive.LimitsHeapSizeUsed__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsMobilePushApexCallsMax__c, + logEntryArchive.LimitsMobilePushApexCallsMax__c, + 'logEntryArchive.LimitsMobilePushApexCallsMax__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsMobilePushApexCallsUsed__c, + logEntryArchive.LimitsMobilePushApexCallsUsed__c, + 'logEntryArchive.LimitsMobilePushApexCallsUsed__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsPublishImmediateDmlStatementsMax__c, + logEntryArchive.LimitsPublishImmediateDmlStatementsMax__c, + 'logEntryArchive.LimitsPublishImmediateDmlStatementsMax__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsPublishImmediateDmlStatementsUsed__c, + logEntryArchive.LimitsPublishImmediateDmlStatementsUsed__c, + 'logEntryArchive.LimitsPublishImmediateDmlStatementsUsed__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsQueueableJobsMax__c, + logEntryArchive.LimitsQueueableJobsMax__c, + 'logEntryArchive.LimitsQueueableJobsMax__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsQueueableJobsUsed__c, + logEntryArchive.LimitsQueueableJobsUsed__c, + 'logEntryArchive.LimitsQueueableJobsUsed__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsSoqlQueriesMax__c, + logEntryArchive.LimitsSoqlQueriesMax__c, + 'logEntryArchive.LimitsSoqlQueriesMax__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsSoqlQueriesUsed__c, + logEntryArchive.LimitsSoqlQueriesUsed__c, + 'logEntryArchive.LimitsSoqlQueriesUsed__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsSoqlQueryLocatorRowsMax__c, + logEntryArchive.LimitsSoqlQueryLocatorRowsMax__c, + 'logEntryArchive.LimitsSoqlQueryLocatorRowsMax__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsSoqlQueryLocatorRowsUsed__c, + logEntryArchive.LimitsSoqlQueryLocatorRowsUsed__c, + 'logEntryArchive.LimitsSoqlQueryLocatorRowsUsed__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsSoqlQueryRowsMax__c, + logEntryArchive.LimitsSoqlQueryRowsMax__c, + 'logEntryArchive.LimitsSoqlQueryRowsMax__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsSoqlQueryRowsUsed__c, + logEntryArchive.LimitsSoqlQueryRowsUsed__c, + 'logEntryArchive.LimitsSoqlQueryRowsUsed__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsSoslSearchesMax__c, + logEntryArchive.LimitsSoslSearchesMax__c, + 'logEntryArchive.LimitsSoslSearchesMax__c was not properly set' + ); + System.assertEquals( + logEntry.LimitsSoslSearchesUsed__c, + logEntryArchive.LimitsSoslSearchesUsed__c, + 'logEntryArchive.LimitsSoslSearchesUsed__c was not properly set' + ); + System.assertEquals(logEntry.Log__r.Locale__c, logEntryArchive.Locale__c, 'logEntryArchive.Locale__c was not properly set'); + System.assertEquals(logEntry.Log__r.LoggedBy__c, logEntryArchive.LoggedById__c, 'logEntryArchive.LoggedById__c was not properly set'); + System.assertEquals( + logEntry.Log__r.LoggedByUsername__c, + logEntryArchive.LoggedByUsername__c, + 'logEntryArchive.LoggedByUsername__c was not properly set' + ); + System.assertEquals( + logEntry.Log__r.LoggerVersionNumber__c, + logEntryArchive.LoggerVersionNumber__c, + 'logEntryArchive.LoggerVersionNumber__c was not properly set' + ); + System.assertEquals(logEntry.LoggingLevel__c, logEntryArchive.LoggingLevel__c, 'logEntryArchive.LoggingLevel__c was not properly set'); + System.assertEquals( + logEntry.LoggingLevelOrdinal__c, + logEntryArchive.LoggingLevelOrdinal__c, + 'logEntryArchive.LoggingLevelOrdinal__c was not properly set' + ); + System.assertEquals( + logEntry.Log__r.LoginApplication__c, + logEntryArchive.LoginApplication__c, + 'logEntryArchive.LoginApplication__c was not properly set' + ); + System.assertEquals(logEntry.Log__r.LoginBrowser__c, logEntryArchive.LoginBrowser__c, 'logEntryArchive.LoginBrowser__c was not properly set'); + System.assertEquals(logEntry.Log__r.LoginHistoryId__c, logEntryArchive.LoginHistoryId__c, 'logEntryArchive.LoginHistoryId__c was not properly set'); + System.assertEquals(logEntry.Log__r.LoginPlatform__c, logEntryArchive.LoginPlatform__c, 'logEntryArchive.LoginPlatform__c was not properly set'); + System.assertEquals(logEntry.Log__r.LoginType__c, logEntryArchive.LoginType__c, 'logEntryArchive.LoginType__c was not properly set'); + System.assertEquals(logEntry.Log__r.LogoutUrl__c, logEntryArchive.LogoutUrl__c, 'logEntryArchive.LogoutUrl__c was not properly set'); + System.assertEquals(logEntry.Log__r.LogPurgeAction__c, logEntryArchive.LogPurgeAction__c, 'logEntryArchive.LogPurgeAction__c was not properly set'); + System.assertEquals( + logEntry.Log__r.LogRetentionDate__c, + logEntryArchive.LogRetentionDate__c, + 'logEntryArchive.LogRetentionDate__c was not properly set' + ); + System.assertEquals(logEntry.Message__c, logEntryArchive.Message__c, 'logEntryArchive.Message__c was not properly set'); + System.assertEquals( + String.valueOf(logEntry.MessageMasked__c), + logEntryArchive.MessageMasked__c, + 'logEntryArchive.MessageMasked__c was not properly set' + ); + System.assertEquals( + String.valueOf(logEntry.MessageTruncated__c), + logEntryArchive.MessageTruncated__c, + 'logEntryArchive.MessageTruncated__c was not properly set' + ); + System.assertEquals(logEntry.Log__r.NetworkId__c, logEntryArchive.NetworkId__c, 'logEntryArchive.NetworkId__c was not properly set'); + System.assertEquals(logEntry.Log__r.NetworkLoginUrl__c, logEntryArchive.NetworkLoginUrl__c, 'logEntryArchive.NetworkLoginUrl__c was not properly set'); + System.assertEquals( + logEntry.Log__r.NetworkLogoutUrl__c, + logEntryArchive.NetworkLogoutUrl__c, + 'logEntryArchive.NetworkLogoutUrl__c was not properly set' + ); + System.assertEquals( + logEntry.Log__r.NetworkSelfRegistrationUrl__c, + logEntryArchive.NetworkSelfRegistrationUrl__c, + 'logEntryArchive.NetworkSelfRegistrationUrl__c was not properly set' + ); + System.assertEquals( + logEntry.Log__r.NetworkUrlPathPrefix__c, + logEntryArchive.NetworkUrlPathPrefix__c, + 'logEntryArchive.NetworkUrlPathPrefix__c was not properly set' + ); + System.assertEquals( + logEntry.Log__r.OrganizationDomainUrl__c, + logEntryArchive.OrganizationDomainUrl__c, + 'logEntryArchive.OrganizationDomainUrl__c was not properly set' + ); + System.assertEquals( + logEntry.Log__r.OrganizationEnvironmentType__c, + logEntryArchive.OrganizationEnvironmentType__c, + 'logEntryArchive.OrganizationEnvironmentType__c was not properly set' + ); + System.assertEquals(logEntry.Log__r.OrganizationId__c, logEntryArchive.OrganizationId__c, 'logEntryArchive.OrganizationId__c was not properly set'); + System.assertEquals( + logEntry.Log__r.OrganizationInstanceName__c, + logEntryArchive.OrganizationInstanceName__c, + 'logEntryArchive.OrganizationInstanceName__c was not properly set' + ); + System.assertEquals( + logEntry.Log__r.OrganizationName__c, + logEntryArchive.OrganizationName__c, + 'logEntryArchive.OrganizationName__c was not properly set' + ); + System.assertEquals( + logEntry.Log__r.OrganizationNamespacePrefix__c, + logEntryArchive.OrganizationNamespacePrefix__c, + 'logEntryArchive.OrganizationNamespacePrefix__c was not properly set' + ); + System.assertEquals( + logEntry.Log__r.OrganizationType__c, + logEntryArchive.OrganizationType__c, + 'logEntryArchive.OrganizationType__c was not properly set' + ); + System.assertEquals(logEntry.OriginLocation__c, logEntryArchive.OriginLocation__c, 'logEntryArchive.OriginLocation__c was not properly set'); + System.assertEquals(logEntry.OriginType__c, logEntryArchive.OriginType__c, 'logEntryArchive.OriginType__c was not properly set'); + System.assertEquals( + logEntry.Log__r.ParentLog__r?.TransactionId__c, + logEntryArchive.ParentLogTransactionId__c, + 'logEntryArchive.ParentLogTransactionId__c was not properly set' + ); + System.assertEquals(logEntry.Log__r.Priority__c, logEntryArchive.Priority__c, 'logEntryArchive.Priority__c was not properly set'); + System.assertEquals(logEntry.Log__r.ProfileId__c, logEntryArchive.ProfileId__c, 'logEntryArchive.ProfileId__c was not properly set'); + System.assertEquals(logEntry.Log__r.ProfileName__c, logEntryArchive.ProfileName__c, 'logEntryArchive.ProfileName__c was not properly set'); + System.assertEquals( + logEntry.RecordCollectionSize__c, + logEntryArchive.RecordCollectionSize__c, + 'logEntryArchive.RecordCollectionSize__c was not properly set' + ); + System.assertEquals( + logEntry.RecordCollectionType__c, + logEntryArchive.RecordCollectionType__c, + 'logEntryArchive.RecordCollectionType__c was not properly set' + ); + System.assertEquals(logEntry.RecordId__c, logEntryArchive.RecordId__c, 'logEntryArchive.RecordId__c was not properly set'); + System.assertEquals(logEntry.RecordJson__c, logEntryArchive.RecordJson__c, 'logEntryArchive.RecordJson__c was not properly set'); + System.assertEquals(logEntry.RecordName__c, logEntryArchive.RecordName__c, 'logEntryArchive.RecordName__c was not properly set'); + System.assertEquals( + String.valueOf(logEntry.RecordJsonMasked__c), + logEntryArchive.RecordJsonMasked__c, + 'logEntryArchive.RecordJsonMasked__c was not properly set' + ); + System.assertEquals( + logEntry.RecordSObjectClassification__c, + logEntryArchive.RecordSObjectClassification__c, + 'logEntryArchive.RecordSObjectClassification__c was not properly set' + ); + System.assertEquals(logEntry.RecordSObjectType__c, logEntryArchive.RecordSObjectType__c, 'logEntryArchive.RecordSObjectType__c was not properly set'); + System.assertEquals( + logEntry.RecordSObjectTypeNamespace__c, + logEntryArchive.RecordSObjectTypeNamespace__c, + 'logEntryArchive.RecordSObjectTypeNamespace__c was not properly set' + ); + System.assertEquals(logEntry.Log__r.SessionId__c, logEntryArchive.SessionId__c, 'logEntryArchive.SessionId__c was not properly set'); + System.assertEquals( + logEntry.Log__r.SessionSecurityLevel__c, + logEntryArchive.SessionSecurityLevel__c, + 'logEntryArchive.SessionSecurityLevel__c was not properly set' + ); + System.assertEquals(logEntry.Log__r.SessionType__c, logEntryArchive.SessionType__c, 'logEntryArchive.SessionType__c was not properly set'); + System.assertEquals(logEntry.Log__r.SourceIp__c, logEntryArchive.SourceIp__c, 'logEntryArchive.SourceIp__c was not properly set'); + System.assertEquals(logEntry.StackTrace__c, logEntryArchive.StackTrace__c, 'logEntryArchive.StackTrace__c was not properly set'); + System.assertEquals(logEntry.Log__r.Status__c, logEntryArchive.Status__c, 'logEntryArchive.Status__c was not properly set'); + System.assertEquals(logEntry.Log__r.SystemMode__c, logEntryArchive.SystemMode__c, 'logEntryArchive.SystemMode__c was not properly set'); + System.assertEquals(tags, logEntryArchive.Tags__c, 'logEntryArchive.Tags__c was not properly set'); + System.assertEquals(logEntry.Log__r.ThemeDisplayed__c, logEntryArchive.ThemeDisplayed__c, 'logEntryArchive.ThemeDisplayed__c was not properly set'); + System.assertEquals(logEntry.Timestamp__c, logEntryArchive.Timestamp__c, 'logEntryArchive.Timestamp__c was not properly set'); + System.assertEquals( + String.valueOf(logEntry.Timestamp__c), + logEntryArchive.TimestampString__c, + 'logEntryArchive.TimestampString__c was not properly set' + ); + System.assertEquals(logEntry.Log__r.TimeZoneId__c, logEntryArchive.TimeZoneId__c, 'logEntryArchive.TimeZoneId__c was not properly set'); + System.assertEquals( + logEntry.TransactionEntryNumber__c, + logEntryArchive.TransactionEntryNumber__c, + 'logEntryArchive.TransactionEntryNumber__c was not properly set' + ); + System.assertEquals(logEntry.Log__r.TransactionId__c, logEntryArchive.TransactionId__c, 'logEntryArchive.TransactionId__c was not properly set'); + System.assertEquals( + String.valueOf(logEntry.TriggerIsExecuting__c), + logEntryArchive.TriggerIsExecuting__c, + 'logEntryArchive.TriggerIsExecuting__c was not properly set' + ); + System.assertEquals( + logEntry.TriggerOperationType__c, + logEntryArchive.TriggerOperationType__c, + 'logEntryArchive.TriggerOperationType__c was not properly set' + ); + System.assertEquals( + logEntry.TriggerSObjectType__c, + logEntryArchive.TriggerSObjectType__c, + 'logEntryArchive.TriggerSObjectType__c was not properly set' + ); + System.assertEquals( + logEntry.Log__r.UserLicenseDefinitionKey__c, + logEntryArchive.UserLicenseDefinitionKey__c, + 'logEntryArchive.UserLicenseDefinitionKey__c was not properly set' + ); + System.assertEquals(logEntry.Log__r.UserLicenseName__c, logEntryArchive.UserLicenseName__c, 'logEntryArchive.UserLicenseName__c was not properly set'); + System.assertEquals( + logEntry.Log__r.UserLoggingLevel__c, + logEntryArchive.UserLoggingLevel__c, + 'logEntryArchive.UserLoggingLevel__c was not properly set' + ); + System.assertEquals( + logEntry.Log__r.UserLoggingLevelOrdinal__c, + logEntryArchive.UserLoggingLevelOrdinal__c, + 'logEntryArchive.UserLoggingLevelOrdinal__c was not properly set' + ); + System.assertEquals(logEntry.Log__r.UserRoleId__c, logEntryArchive.UserRoleId__c, 'logEntryArchive.UserRoleId__c was not properly set'); + System.assertEquals(logEntry.Log__r.UserRoleName__c, logEntryArchive.UserRoleName__c, 'logEntryArchive.UserRoleName__c was not properly set'); + System.assertEquals(logEntry.Log__r.UserType__c, logEntryArchive.UserType__c, 'logEntryArchive.UserType__c was not properly set'); + } +} diff --git a/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveBuilder_Tests.cls-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveBuilder_Tests.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveBuilder_Tests.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveController.cls b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveController.cls new file mode 100644 index 000000000..97857448e --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveController.cls @@ -0,0 +1,102 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @group Plugins + * @description Controller class used by the LWC `logEntryArchives` to display `LogEntryArchive__b` data + * @see LogEntryArchivePlugin + * @see LogEntryArchiveBuilder + */ +public with sharing class LogEntryArchiveController { + @TestVisible + private static final List MOCK_RECORDS = new List(); + + /** + * @description Returns a list of `LogEntryArchive__b` records, based on the current user's record access + an optional search term for `Message__c` + * @param startDate The initial date to check for matching `LogEntryArchive__b` records, used to filter on `LogEntryArchive__b.Timestamp__c` + * @param endDate The last date to check for matching `LogEntryArchive__b` records, used to filter on `LogEntryArchive__b.Timestamp__c` + * @param rowLimit The max number of rows to return + * @param minimumLoggingLevelOrdinal Optional filter for a minimal logging level ordinal, applied to the field `LoggingLevelOrdinal__c` + * @param messageSearchTerm Optional filter for text contained within the field `Message__c` + * @return The list of matching `LogEntryArchive__b` records + */ + @SuppressWarnings('PMD.CognitiveComplexity, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList') + @AuraEnabled + public static List getLogEntryArchives( + Date startDate, + Date endDate, + Integer rowLimit, + Integer minimumLoggingLevelOrdinal, + String messageSearchTerm + ) { + List matchingLogEntryArchives = new List(); + + // Big Objects have very, very limited support for SOQL filtering, so additional filtering is applied after querying + // Since additional filtering is applied below (outside of the query), so this query gets as many rows + // as possible to maximize the possible matches from post-query filtering + Integer queryLimit = System.Test.isRunningTest() == true ? 1 : Limits.getLimitQueryRows(); + for (LogEntryArchive__b logEntryArchive : [ + SELECT + LoggedByUsername__c, + LoggingLevel__c, + LoggingLevelOrdinal__c, + Message__c, + OriginLocation__c, + OriginType__c, + Tags__c, + Timestamp__c, + TransactionEntryNumber__c, + TransactionId__c + FROM LogEntryArchive__b + WHERE Timestamp__c >= :startDate AND Timestamp__c <= :endDate.addDays(1) + WITH SECURITY_ENFORCED + ORDER BY Timestamp__c DESC, TransactionId__c ASC, TransactionEntryNumber__c DESC + LIMIT :queryLimit + ]) { + addMatches(matchingLogEntryArchives, logEntryArchive, minimumLoggingLevelOrdinal, messageSearchTerm, rowLimit); + } + + // In a test context, creating Big Object data will actually, truly create the data - it's not isolated + // from the org's data. That makes testing trickier, so mock records are injected here. + if (System.Test.isRunningTest() == true) { + matchingLogEntryArchives.clear(); + for (LogEntryArchive__b mockLogEntryArchive : MOCK_RECORDS) { + addMatches(matchingLogEntryArchives, mockLogEntryArchive, minimumLoggingLevelOrdinal, messageSearchTerm, rowLimit); + } + } + + return matchingLogEntryArchives; + } + + @SuppressWarnings('PMD.ExcessiveParameterList') + private static void addMatches( + List matchingLogEntryArchives, + LogEntryArchive__b potentialMatchingArchive, + Integer minimumLoggingLevelOrdinal, + String messageSearchTerm, + Integer rowLimit + ) { + if (matchingLogEntryArchives.size() == rowLimit) { + return; + } + + if (matchesFilterCriteria(potentialMatchingArchive, minimumLoggingLevelOrdinal, messageSearchTerm) == true) { + matchingLogEntryArchives.add(potentialMatchingArchive); + } + } + + private static Boolean matchesFilterCriteria(LogEntryArchive__b logEntryArchive, Integer minimumLoggingLevelOrdinal, String messageSearchTerm) { + Boolean matchesLoggingLevelOrdinal = minimumLoggingLevelOrdinal == null || logEntryArchive.LoggingLevelOrdinal__c >= minimumLoggingLevelOrdinal; + + messageSearchTerm = messageSearchTerm == null ? '' : messageSearchTerm; + String messageValue = logEntryArchive.Message__c == null ? '' : logEntryArchive.Message__c; + Boolean matchesSearchTerm = + String.isBlank(messageSearchTerm) == true || + messageValue.containsIgnoreCase(messageSearchTerm) == true || + Pattern.matches(messageSearchTerm, messageValue) == true; + + return matchesLoggingLevelOrdinal && matchesSearchTerm; + } +} diff --git a/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveController.cls-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveController.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveController.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveController_Tests.cls b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveController_Tests.cls new file mode 100644 index 000000000..bae74bd6c --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveController_Tests.cls @@ -0,0 +1,98 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +@SuppressWarnings('PMD.MethodNamingConventions, PMD.PropertyNamingConventions') +@IsTest(IsParallel=true) +private class LogEntryArchiveController_Tests { + @IsTest + static void it_returns_subset_of_log_entry_archives_when_row_limit_met() { + List expectedLogEntryArchives = createLogEntryArchive(5, LoggingLevel.DEBUG); + LogEntryArchiveController.MOCK_RECORDS.addAll(expectedLogEntryArchives); + Integer rowLimit = expectedLogEntryArchives.size() - 2; + + List returnedLogEntryArchives = LogEntryArchiveController.getLogEntryArchives( + System.today().addDays(-1), + System.today(), + rowLimit, + null, + null + ); + + System.assertNotEquals(0, returnedLogEntryArchives.size(), 'Records should have been returned'); + System.assertEquals(rowLimit, returnedLogEntryArchives.size(), 'Returned records should match the specified row limit'); + } + + @IsTest + static void it_returns_all_log_entry_archives_when_logging_level_and_message_search_term_are_null() { + List expectedLogEntryArchives = createLogEntryArchive(5, LoggingLevel.DEBUG); + LogEntryArchiveController.MOCK_RECORDS.addAll(expectedLogEntryArchives); + + List returnedLogEntryArchives = LogEntryArchiveController.getLogEntryArchives( + System.today().addDays(-1), + System.today(), + 100, + null, + null + ); + + System.assertNotEquals(0, returnedLogEntryArchives.size(), 'Records should have been returned'); + System.assertEquals(expectedLogEntryArchives.size(), returnedLogEntryArchives.size(), 'Returned records should match the expected records'); + } + + @IsTest + static void it_returns_filtered_log_entry_archives_whenlogging_level_filter_is_specified() { + List expectedLogEntryArchives = createLogEntryArchive(5, LoggingLevel.DEBUG); + LoggingLevel minimumLoggingLevel = LoggingLevel.INFO; + expectedLogEntryArchives.get(0).LoggingLevel__c = LoggingLevel.WARN.name(); + expectedLogEntryArchives.get(0).LoggingLevelOrdinal__c = LoggingLevel.WARN.ordinal(); + LogEntryArchiveController.MOCK_RECORDS.addAll(expectedLogEntryArchives); + + List returnedLogEntryArchives = LogEntryArchiveController.getLogEntryArchives( + System.today().addDays(-1), + System.today(), + 100, + minimumLoggingLevel.ordinal(), + null + ); + + System.assertEquals(1, returnedLogEntryArchives.size(), 'Only one matching record should have been returned'); + System.assertEquals(true, returnedLogEntryArchives.get(0).LoggingLevelOrdinal__c > minimumLoggingLevel.ordinal()); + } + + @IsTest + static void it_returns_filtered_log_entry_archives_when_message_search_term_is_specified() { + List expectedLogEntryArchives = createLogEntryArchive(5, LoggingLevel.DEBUG); + String messageSearchTerm = 'some substring'; + expectedLogEntryArchives.get(0).Message__c = 'some extra text and ' + messageSearchTerm + ' and then also some more text, blah blah blah'; + LogEntryArchiveController.MOCK_RECORDS.addAll(expectedLogEntryArchives); + + List returnedLogEntryArchives = LogEntryArchiveController.getLogEntryArchives( + System.today().addDays(-1), + System.today(), + 100, + null, + messageSearchTerm + ); + + System.assertEquals(1, returnedLogEntryArchives.size(), 'Only one matching record should have been returned'); + System.assertEquals(true, returnedLogEntryArchives.get(0).Message__c.contains(messageSearchTerm)); + } + + private static List createLogEntryArchive(Integer numberOfRecordsToCreate, LoggingLevel logLevel) { + List records = new List(); + for (Integer i = 0; i < numberOfRecordsToCreate; i++) { + records.add( + new LogEntryArchive__b( + LoggingLevel__c = logLevel.name(), + LoggingLevelOrdinal__c = logLevel.ordinal(), + Timestamp__c = System.now().addMinutes(-i), + TransactionId__c = null, + TransactionEntryNumber__c = i + 1 + ) + ); + } + return records; + } +} diff --git a/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveController_Tests.cls-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveController_Tests.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchiveController_Tests.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchivePlugin.cls b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchivePlugin.cls new file mode 100644 index 000000000..8e70b2f8b --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchivePlugin.cls @@ -0,0 +1,231 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +/** + * @group Plugins + * @description Optional plugin that provides a BigObject, `LogEntryArchive__b`, as an alternative option + * to the platform event `LogEntryEvent__e` + * @see LoggerPlugin + */ +public without sharing class LogEntryArchivePlugin implements LoggerPlugin.Batchable, LoggerPlugin.Triggerable { + @TestVisible + private static final String BIG_OBJECT_IMMEDIATE_LOGGER_SAVE_METHOD = LoggerParameter.getString('CustomSaveMethodBigObjectImmediate', null); + @TestVisible + private static final String BIG_OBJECT_QUEUEABLE_LOGGER_SAVE_METHOD = LoggerParameter.getString('CustomSaveMethodBigObjectQueueable', null); + @TestVisible + private static final String BIG_OBJECT_LOG_PURGE_ACTION = LoggerParameter.getString('CustomLogPurgeActionArchive', null); + @TestVisible + private static final String BIG_OBJECT_STORAGE_LOCATION = LoggerParameter.getString('CustomStorageLocationBigObject', null); + @TestVisible + private static final List LOG_ENTRY_ARCHIVES_TO_SAVE = new List(); + + @TestVisible + private static String lastSaveMethodUsed; + + /** + * @description Default constructor + */ + @SuppressWarnings('PMD.EmptyStatementBlock') + public LogEntryArchivePlugin() { + } + + // Batchable interface methods + /** + * @description Skips directly deleting `LogEntryTag__c` records in `LogBatchPurger` so that the tags + * can be included when `LogEntry__c` records are archived into `LogEntryArchive__b` + * @param configuration The instance of `LoggerPlugin__mdt` configured for this specific plugin + * @param input The instance of `LoggerBatchableContext`, provided by the logging system + */ + public void start(LoggerPlugin__mdt configuration, LoggerBatchableContext input) { + // Skip directly deleting LogEntryTag__c records so that the tags can be included when LogEntry__c records + // are archived into LogEntryArchive__b + if (input.sobjectType == Schema.LogEntryTag__c.SObjectType) { + input.sobjectType = Schema.LogEntry__c.SObjectType; + } + } + + /** + * @description Converts any `LogEntry__c` records into `LogEntryArchive__b` records + * @param configuration The instance of `LoggerPlugin__mdt` configured for this specific plugin + * @param input The instance of `LoggerBatchableContext`, provided by the logging system + * @param loggerRecords The list of `SObject` scope records provider by `LogBatchPurger` + */ + public void execute(LoggerPlugin__mdt configuration, LoggerBatchableContext input, List loggerRecords) { + if (input.sobjectType != Schema.LogEntry__c.SObjectType) { + return; + } + + List logEntries = this.requeryLogEntriesToArchive((List) loggerRecords); + for (LogEntry__c logEntry : logEntries) { + LOG_ENTRY_ARCHIVES_TO_SAVE.add(new LogEntryArchiveBuilder(logEntry).getLogEntryArchive()); + } + this.saveLogEntryArchives(BIG_OBJECT_IMMEDIATE_LOGGER_SAVE_METHOD); + } + + /** + * @description No-op method, required by the interface `LoggerPlugin.Batchable` + * @param configuration The instance of `LoggerPlugin__mdt` configured for this specific plugin + * @param input The instance of `LoggerBatchableContext`, provided by the logging system + */ + @SuppressWarnings('PMD.EmptyStatementBlock') + public void finish(LoggerPlugin__mdt configuration, LoggerBatchableContext input) { + // No-op + } + + // Triggerable interface method + /** + * @description Handles converting Logger's buffer of `LogEntryEvent__e` records into `LogEntryArchive__b` records + * for any user with the included custom save method 'BIG_OBJECT' + * @param configuration The instance of `LoggerPlugin__mdt` configured for this specific plugin + * @param input The instance of `LoggerTriggerableContext`, provided by the logging system + */ + public void execute(LoggerPlugin__mdt configuration, LoggerTriggerableContext input) { + if (input.sobjectType != Schema.LogEntryEvent__e.SObjectType) { + return; + } + Set bigObjectSaveMethods = new Set{ BIG_OBJECT_IMMEDIATE_LOGGER_SAVE_METHOD, BIG_OBJECT_QUEUEABLE_LOGGER_SAVE_METHOD }; + + if ( + input.triggerOperationType == TriggerOperation.BEFORE_INSERT && + bigObjectSaveMethods.contains(Logger.getUserSettings().DefaultSaveMethod__c) == false + ) { + return; + } + + List logEntryEvents = this.filterLogEntryEventsToSave(input); + for (LogEntryEvent__e logEntryEvent : logEntryEvents) { + LOG_ENTRY_ARCHIVES_TO_SAVE.add(new LogEntryArchiveBuilder(logEntryEvent).getLogEntryArchive()); + } + + if (LOG_ENTRY_ARCHIVES_TO_SAVE.isEmpty() == true) { + return; + } + + String saveMethodName; + switch on input.triggerOperationType { + when BEFORE_INSERT { + saveMethodName = Logger.getUserSettings().DefaultSaveMethod__c; + } + when AFTER_INSERT { + saveMethodName = BIG_OBJECT_QUEUEABLE_LOGGER_SAVE_METHOD; + } + } + this.saveLogEntryArchives(saveMethodName); + + Logger.flushBuffer(); + } + + private List requeryLogEntriesToArchive(List logEntries) { + String logLookupRelationshipName = Schema.LogEntry__c.Log__c.getDescribe().getName().removeEnd('__c') + '__r'; + List logFieldsToQuery = new List(); + for (String fieldName : Schema.Log__c.SObjectType.getDescribe().fields.getMap().keySet()) { + logFieldsToQuery.add(logLookupRelationshipName + '.' + fieldName); + } + String closedByUsernameField = getParentFieldPath( + new List{ Schema.LogEntry__c.Log__c, Schema.Log__c.ClosedBy__c, Schema.User.Username } + ); + logFieldsToQuery.add(closedByUsernameField); + String parentLogTransactionIdField = getParentFieldPath( + new List{ Schema.LogEntry__c.Log__c, Schema.Log__c.ParentLog__c, Schema.Log__c.TransactionId__c } + ); + logFieldsToQuery.add(parentLogTransactionIdField); + List logEntryFieldsToQuery = new List(Schema.LogEntry__c.SObjectType.getDescribe().fields.getMap().keySet()); + logEntryFieldsToQuery.addAll(logFieldsToQuery); + + String tagLookupRelationshipName = Schema.LogEntryTag__c.Tag__c.getDescribe().getName().removeEnd('__c') + '__r'; + String tagNameField = tagLookupRelationshipName + '.' + Schema.LoggerTag__c.Name.getDescribe().getName(); + + String logPurgeActionParentFieldName = logLookupRelationshipName + '.' + Schema.Log__c.LogPurgeAction__c.getDescribe().getName(); + String queryTemplate = 'SELECT {0}, (SELECT {1} FROM {2}) FROM {3} WHERE Id IN :logEntries AND {4} = :BIG_OBJECT_LOG_PURGE_ACTION'; + List queryInputs = new List{ + String.join(logEntryFieldsToQuery, ', '), + tagNameField, + 'LogEntryTags__r', // TODO replace with strongly-typed reference or namespace-safe string + Schema.LogEntry__c.SObjectType.getDescribe().getName(), + logPurgeActionParentFieldName + }; + String query = String.escapeSingleQuotes(String.format(queryTemplate, queryInputs)); + return (List) Database.query(query); + } + + private String getParentFieldPath(List parentFieldChainPieces) { + String parentFieldPath = ''; + Integer lastIndex = parentFieldChainPieces.size() - 1; + for (Integer i = 0; i < parentFieldChainPieces.size(); i++) { + Schema.SObjectField field = parentFieldChainPieces.get(i); + if (i != lastIndex) { + parentFieldPath += field.getDescribe().getName().removeEnd('__c') + '__r.'; + } else { + parentFieldPath += field.getDescribe().getName(); + } + } + return parentFieldPath; + } + + private List filterLogEntryEventsToSave(LoggerTriggerableContext input) { + // In a BEFORE_INSERT context, if one of the 2 Big Object save methods is used, then + // all of the LogEntryEvent__e records should be saved in LogEntryArchive__b + if ( + input.triggerOperationType == TriggerOperation.BEFORE_INSERT && + new Set{ BIG_OBJECT_IMMEDIATE_LOGGER_SAVE_METHOD, BIG_OBJECT_QUEUEABLE_LOGGER_SAVE_METHOD } + .contains(Logger.getUserSettings().DefaultSaveMethod__c) + ) { + return (List) input.triggerNew; + } + + if (input.triggerOperationType != TriggerOperation.AFTER_INSERT) { + return new List(); + } + + // In an AFTER_INSERT context, only save LogEntryEvent__e records if the LoggedyId__c user + // as 'BIG_OBJECT' set as their storage location for platform events (DefaultPlatformEventStorageLocation__c) + List logEntryEventsToSave = new List(); + for (LogEntryEvent__e logEntryEvent : (List) input.triggerNew) { + User loggingUser = new User(Id = logEntryEvent.LoggedById__c, ProfileId = logEntryEvent.ProfileId__c); + LoggerSettings__c loggingUserSettings = Logger.getUserSettings(loggingUser); + if (loggingUserSettings.DefaultPlatformEventStorageLocation__c == BIG_OBJECT_STORAGE_LOCATION) { + logEntryEventsToSave.add(logEntryEvent); + } + } + return logEntryEventsToSave; + } + + private void saveLogEntryArchives(String saveMethodName) { + if (System.Test.isRunningTest() == true) { + lastSaveMethodUsed = saveMethodName; + } + + if (saveMethodName == BIG_OBJECT_IMMEDIATE_LOGGER_SAVE_METHOD && System.Test.isRunningTest() == false) { + System.Database.insertImmediate(LOG_ENTRY_ARCHIVES_TO_SAVE); + } else if (saveMethodName == BIG_OBJECT_QUEUEABLE_LOGGER_SAVE_METHOD || saveMethodName == BIG_OBJECT_STORAGE_LOCATION) { + System.enqueueJob(new QueueableSaver(LOG_ENTRY_ARCHIVES_TO_SAVE)); + } + + if (System.Test.isRunningTest() == false) { + LOG_ENTRY_ARCHIVES_TO_SAVE.clear(); + } + } + + /** + * @description Inner class for publishing log entries via the Queueable interface. + */ + private class QueueableSaver implements Queueable { + private List logEntryArchives = new List(); + + private QueueableSaver(List logEntryArchives) { + this.logEntryArchives = logEntryArchives; + } + + /** + * @description Asynchronoulsy inserts the list of `LogEntryArchive_b` records + * @param queueableContext The context of the current queue, provided by the platform + */ + public void execute(System.QueueableContext queueableContext) { + if (System.Test.isRunningTest() == false) { + System.Database.insertImmediate(this.logEntryArchives); + } + } + } +} diff --git a/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchivePlugin.cls-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchivePlugin.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchivePlugin.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchivePlugin_Tests.cls b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchivePlugin_Tests.cls new file mode 100644 index 000000000..9f939c478 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchivePlugin_Tests.cls @@ -0,0 +1,239 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +@SuppressWarnings('PMD.ApexDoc, PMD.ApexAssertionsShouldIncludeMessage, PMD.MethodNamingConventions') +@IsTest(IsParallel=true) +private class LogEntryArchivePlugin_Tests { + @TestSetup + static void setupData() { + LoggerSObjectHandler.shouldExecute(false); + createParameterConfigurations(); + + Log__c logToArchive = new Log__c( + LogPurgeAction__c = LogEntryArchivePlugin.BIG_OBJECT_LOG_PURGE_ACTION, + LogRetentionDate__c = System.today().addDays(-1), + TransactionId__c = '1234' + ); + Log__c logToDelete = new Log__c(LogPurgeAction__c = 'Delete', LogRetentionDate__c = System.today().addDays(-1), TransactionId__c = '5678'); + insert new List{ logToArchive, logToDelete }; + + List logEntries = new List(); + for (Integer i = 0; i < 10; i++) { + logEntries.add(new LogEntry__c(Log__c = logToArchive.Id, Message__c = 'Some message to archive for ' + i, TransactionEntryNumber__c = i)); + logEntries.add(new LogEntry__c(Log__c = logToDelete.Id, Message__c = 'Some message to skip for ' + i, TransactionEntryNumber__c = i)); + } + insert logEntries; + } + + @IsTest + static void it_archives_log_entry_records_in_log_batch_purger_when_purge_action_is_archive() { + LoggerSObjectHandler.shouldExecute(false); + createParameterConfigurations(); + createPluginConfiguration(); + LogBatchPurger batchPurger = new LogBatchPurger(); + Log__c log = [SELECT Id, (SELECT Id FROM LogEntries__r) FROM Log__c WHERE LogPurgeAction__c = :LogEntryArchivePlugin.BIG_OBJECT_LOG_PURGE_ACTION]; + Test.startTest(); + + Database.executeBatch(batchPurger); + + Test.stopTest(); + System.assertEquals(log.LogEntries__r.size(), LogEntryArchivePlugin.LOG_ENTRY_ARCHIVES_TO_SAVE.size()); + List existingLogs = [SELECT Id FROM Log__c WHERE LogPurgeAction__c = :LogEntryArchivePlugin.BIG_OBJECT_LOG_PURGE_ACTION]; + System.assertEquals(0, existingLogs.size()); + } + + @IsTest + static void it_skips_log_entry_records_in_log_batch_purger_when_purge_action_is_not_archive() { + LoggerSObjectHandler.shouldExecute(false); + createParameterConfigurations(); + createPluginConfiguration(); + LogBatchPurger batchPurger = new LogBatchPurger(); + Log__c logToArchive = [ + SELECT Id, (SELECT Id FROM LogEntries__r) + FROM Log__c + WHERE LogPurgeAction__c = :LogEntryArchivePlugin.BIG_OBJECT_LOG_PURGE_ACTION + ]; + System.assertNotEquals( + true, + logToArchive.LogEntries__r.isEmpty(), + 'Test has started under the wrong condiations - log record should have some related log entries' + ); + Log__c logToSkip = [SELECT Id, (SELECT Id FROM LogEntries__r) FROM Log__c WHERE LogPurgeAction__c = 'Delete']; + System.assertNotEquals( + true, + logToSkip.LogEntries__r.isEmpty(), + 'Test has started under the wrong condiations - log record should have some related log entries' + ); + Test.startTest(); + + Database.executeBatch(batchPurger); + + Test.stopTest(); + System.assertEquals( + logToArchive.LogEntries__r.size(), + LogEntryArchivePlugin.LOG_ENTRY_ARCHIVES_TO_SAVE.size(), + 'Only the log entries for logToArchive should have been archived' + ); + List existingLogs = [SELECT Id FROM Log__c]; + System.assertEquals(0, existingLogs.size(), 'All logs should havve been deleted'); + } + + @IsTest + static void it_includes_tags_for_log_entry_in_log_batch_purger_when_tags_exist() { + LoggerSObjectHandler.shouldExecute(false); + createParameterConfigurations(); + createPluginConfiguration(); + LogBatchPurger batchPurger = new LogBatchPurger(); + Log__c logToArchive = [ + SELECT Id, (SELECT Id FROM LogEntries__r) + FROM Log__c + WHERE LogPurgeAction__c = :LogEntryArchivePlugin.BIG_OBJECT_LOG_PURGE_ACTION + ]; + LoggerTag__c tag = new LoggerTag__c(Name = 'Some tag'); + insert tag; + List logEntryTags = new List(); + for (LogEntry__c logEntry : logToArchive.LogEntries__r) { + logEntryTags.add(new LogEntryTag__c(LogEntry__c = logEntry.Id, Tag__c = tag.Id)); + } + insert logEntryTags; + Test.startTest(); + + Database.executeBatch(batchPurger); + + System.assertEquals(0, Limits.getPublishImmediateDml()); + Test.stopTest(); + System.assertEquals(0, Limits.getPublishImmediateDml()); + System.assertEquals(logToArchive.LogEntries__r.size(), LogEntryArchivePlugin.LOG_ENTRY_ARCHIVES_TO_SAVE.size()); + for (LogEntryArchive__b logEntryArchive : LogEntryArchivePlugin.LOG_ENTRY_ARCHIVES_TO_SAVE) { + System.assertEquals(tag.Name, logEntryArchive.Tags__c); + } + List existingLogs = [SELECT Id FROM Log__c]; + System.assertEquals(0, existingLogs.size()); + } + + @IsTest + static void it_should_not_create_archive_in_logger_when_save_method_is_not_valid_big_object_save_method() { + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + createParameterConfigurations(); + createPluginConfiguration(); + Logger.getUserSettings().DefaultSaveMethod__c = Logger.SaveMethod.EVENT_BUS.name(); + LogEntryEvent__e mockEvent = (LogEntryEvent__e) LoggerMockDataCreator.createDataBuilder(Schema.LogEntryEvent__e.SObjectType) + .populateRequiredFields() + .getRecord(); + LoggerPlugin__mdt pluginConfiguration = createPluginConfiguration(); + LoggerTriggerableContext pluginInput = new LoggerTriggerableContext( + Schema.LogEntryEvent__e.SObjectType, + TriggerOperation.BEFORE_INSERT, + new List{ mockEvent }, + null, + null + ); + + new LogEntryArchivePlugin().execute(pluginConfiguration, pluginInput); + + System.assertEquals(0, LogEntryArchivePlugin.LOG_ENTRY_ARCHIVES_TO_SAVE.size(), 'Should not have tried to create big object'); + } + + @IsTest + static void it_should_create_archive_in_logger_when_platform_event_storage_location_is_big_object() { + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + createParameterConfigurations(); + createPluginConfiguration(); + Logger.getUserSettings().DefaultSaveMethod__c = Logger.SaveMethod.EVENT_BUS.name(); + Logger.getUserSettings().DefaultPlatformEventStorageLocation__c = LogEntryArchivePlugin.BIG_OBJECT_STORAGE_LOCATION; + upsert Logger.getUserSettings(); + System.Test.startTest(); + String transactionId = Logger.getTransactionId(); + Logger.info('Testing big object creation'); + System.assertEquals(1, Logger.getBufferSize(), 'Should have one record in Logger\'s platform event buffer'); + + Logger.saveLog(); + System.Test.getEventBus().deliver(); + + System.assertEquals(0, Logger.getBufferSize(), 'Should have been cleared from Logger\'s platform event buffer'); + System.assertEquals( + 'BIG_OBJECT_QUEUEABLE', + LogEntryArchivePlugin.lastSaveMethodUsed, + 'Last save method used should have been set to BIG_OBJECT_EVENT_BUS' + ); + System.Test.stopTest(); + System.assertEquals(1, LogEntryArchivePlugin.LOG_ENTRY_ARCHIVES_TO_SAVE.size(), 'Should have been put into big object buffer'); + System.assertNotEquals(null, transactionId, 'Should have a value for transaction ID'); + System.assertEquals(transactionId, LogEntryArchivePlugin.LOG_ENTRY_ARCHIVES_TO_SAVE.get(0).TransactionId__c, 'Transaction ID should match'); + System.assertEquals(0, [SELECT COUNT() FROM Log__c WHERE TransactionId__c = :transactionId], 'No custom object data should have been created'); + } + + @IsTest + static void it_should_create_archive_in_logger_when_save_method_is_big_object_immediate() { + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + createParameterConfigurations(); + createPluginConfiguration(); + Logger.getUserSettings().DefaultSaveMethod__c = LogEntryArchivePlugin.BIG_OBJECT_IMMEDIATE_LOGGER_SAVE_METHOD; + createPluginConfiguration(); + Logger.info('Testing big object creation').getLogEntryEvent(); + + Logger.saveLog(); + + System.assertEquals( + 0, + Limits.getPublishImmediateDml(), + 'Should not have actually used any DML statements in tests because big objects actually get inserted, yikes' + ); + System.assertEquals(0, Logger.getBufferSize(), 'Should not have been put into Logger\'s platform event buffer'); + System.assertEquals(1, LogEntryArchivePlugin.LOG_ENTRY_ARCHIVES_TO_SAVE.size(), 'Should have been put into big object buffer'); + System.assertEquals( + 'BIG_OBJECT_IMMEDIATE', + LogEntryArchivePlugin.lastSaveMethodUsed, + 'Last save method used should have been set to BIG_OBJECT_IMMEDIATE' + ); + } + + @IsTest + static void it_should_create_archive_in_logger_when_save_method_is_big_object_queueable() { + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + createParameterConfigurations(); + createPluginConfiguration(); + Logger.getUserSettings().DefaultSaveMethod__c = LogEntryArchivePlugin.BIG_OBJECT_QUEUEABLE_LOGGER_SAVE_METHOD; + createPluginConfiguration(); + Logger.info('Testing big object creation').getLogEntryEvent(); + Test.startTest(); + System.assertEquals(0, Limits.getAsyncCalls(), 'Should not have executed any queueable jobs'); + + Logger.saveLog(); + + System.assertEquals(1, Limits.getAsyncCalls(), 'Should have executed queueable saver job'); + System.assertEquals( + 0, + Limits.getPublishImmediateDml(), + 'Should not have actually used any DML statements in tests because big objects actually get inserted, yikes' + ); + System.assertEquals(0, Logger.getBufferSize(), 'Should not have been put into Logger\'s platform event buffer'); + System.assertEquals(1, LogEntryArchivePlugin.LOG_ENTRY_ARCHIVES_TO_SAVE.size(), 'Should have been put into big object buffer'); + System.assertEquals( + 'BIG_OBJECT_QUEUEABLE', + LogEntryArchivePlugin.lastSaveMethodUsed, + 'Last save method used should have been set to BIG_OBJECT_QUEUEABLE' + ); + Test.stopTest(); + } + + private static void createParameterConfigurations() { + LoggerTestConfigurator.setMock(new LoggerParameter__mdt(DeveloperName = 'CustomSaveMethodBigObjectImmediate', Value__c = 'BIG_OBJECT_IMMEDIATE')); + LoggerTestConfigurator.setMock(new LoggerParameter__mdt(DeveloperName = 'CustomSaveMethodBigObjectQueueable', Value__c = 'BIG_OBJECT_QUEUEABLE')); + LoggerTestConfigurator.setMock(new LoggerParameter__mdt(DeveloperName = 'CustomStorageLocationBigObject', Value__c = 'BIG_OBJECT_EVENT_BUS')); + LoggerTestConfigurator.setMock(new LoggerParameter__mdt(DeveloperName = 'CustomLogPurgeActionArchive', Value__c = 'Archive')); + } + + private static LoggerPlugin__mdt createPluginConfiguration() { + LoggerPlugin__mdt configuration = new LoggerPlugin__mdt( + BatchPurgerApexClass__c = LogEntryArchivePlugin.class.getName(), + DeveloperName = 'LogEntryArchivePlugin', + IsEnabled__c = true, + SObjectHandlerApexClass__c = LogEntryArchivePlugin.class.getName() + ); + LoggerTestConfigurator.setMock(configuration); + return configuration; + } +} diff --git a/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchivePlugin_Tests.cls-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchivePlugin_Tests.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/classes/LogEntryArchivePlugin_Tests.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/customMetadata/LoggerParameter.CustomLogPurgeActionArchive.md-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/customMetadata/LoggerParameter.CustomLogPurgeActionArchive.md-meta.xml new file mode 100644 index 000000000..1c3f2a9d0 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/customMetadata/LoggerParameter.CustomLogPurgeActionArchive.md-meta.xml @@ -0,0 +1,17 @@ + + + + true + + Description__c + Adds a new purge action Archive to the list of log purge actions displayed in the LWC loggerSettings + + + Value__c + Archive + + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/customMetadata/LoggerParameter.CustomSaveMethodBigObjectImmediate.md-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/customMetadata/LoggerParameter.CustomSaveMethodBigObjectImmediate.md-meta.xml new file mode 100644 index 000000000..5aa427afa --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/customMetadata/LoggerParameter.CustomSaveMethodBigObjectImmediate.md-meta.xml @@ -0,0 +1,17 @@ + + + + true + + Description__c + Adds a new save method BIG_OBJECT_IMMEDIATE to the list of save methods displayed in the LWC loggerSettings + + + Value__c + BIG_OBJECT_IMMEDIATE + + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/customMetadata/LoggerParameter.CustomSaveMethodBigObjectQueueable.md-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/customMetadata/LoggerParameter.CustomSaveMethodBigObjectQueueable.md-meta.xml new file mode 100644 index 000000000..9f6528081 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/customMetadata/LoggerParameter.CustomSaveMethodBigObjectQueueable.md-meta.xml @@ -0,0 +1,17 @@ + + + + true + + Description__c + Adds a new save method BIG_OBJECT_QUEUEABLE to the list of save methods displayed in the LWC loggerSettings + + + Value__c + BIG_OBJECT_QUEUEABLE + + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/customMetadata/LoggerParameter.CustomStorageLocationBigObject.md-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/customMetadata/LoggerParameter.CustomStorageLocationBigObject.md-meta.xml new file mode 100644 index 000000000..87ac883c1 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/customMetadata/LoggerParameter.CustomStorageLocationBigObject.md-meta.xml @@ -0,0 +1,19 @@ + + + + true + + Description__c + Adds a new storage location BIG_OBJECT_EVENT_BUS to the list of storage locations for platform events (LogEntryEvent__e) + + + Value__c + BIG_OBJECT + + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/customMetadata/LoggerPlugin.LogEntryArchive.md-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/customMetadata/LoggerPlugin.LogEntryArchive.md-meta.xml new file mode 100644 index 000000000..c541e6dc4 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/customMetadata/LoggerPlugin.LogEntryArchive.md-meta.xml @@ -0,0 +1,49 @@ + + + + false + + BatchPurgerApexClass__c + LogEntryArchivePlugin + + + BatchPurgerExecutionOrder__c + + + + BatchPurgerFlowName__c + + + + Description__c + Adds the ability to log directly to the BigObject LogEntryArchive__b + + + IsEnabled__c + true + + + Link__c + + + + SObjectHandlerApexClass__c + LogEntryArchivePlugin + + + SObjectHandlerExecutionOrder__c + + + + SObjectHandlerFlowName__c + + + + VersionNumber__c + + + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/lwc/logEntryArchives/__tests__/data/LoggerSObjectMetadata.getSchemaForName.json b/nebula-logger/plugins/big-object-archiving/plugin/lwc/logEntryArchives/__tests__/data/LoggerSObjectMetadata.getSchemaForName.json new file mode 100644 index 000000000..2b7463634 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/lwc/logEntryArchives/__tests__/data/LoggerSObjectMetadata.getSchemaForName.json @@ -0,0 +1,799 @@ +{ + "apiName": "LogEntryArchive__b", + "fields": { + "Id": { + "apiName": "Id", + "label": "ID", + "localApiName": "Id", + "type": "id" + }, + "CreatedById": { + "apiName": "CreatedById", + "label": "Created By ID", + "localApiName": "CreatedById", + "type": "reference" + }, + "CreatedDate": { + "apiName": "CreatedDate", + "label": "Created Date", + "localApiName": "CreatedDate", + "type": "datetime" + }, + "SystemModstamp": { + "apiName": "SystemModstamp", + "label": "System Modstamp", + "localApiName": "SystemModstamp", + "type": "datetime" + }, + "ApiReleaseNumber__c": { + "apiName": "ApiReleaseNumber__c", + "inlineHelpText": "The release number for the org's instance - determined by making a callout to status.salesforce.com", + "label": "API Release Number", + "localApiName": "ApiReleaseNumber__c", + "type": "string" + }, + "ApiReleaseVersion__c": { + "apiName": "ApiReleaseVersion__c", + "inlineHelpText": "The release version for the org's instance - determined by making a callout to status.salesforce.com", + "label": "API Release Version", + "localApiName": "ApiReleaseVersion__c", + "type": "string" + }, + "ApiVersion__c": { + "apiName": "ApiVersion__c", + "label": "API Version", + "localApiName": "ApiVersion__c", + "type": "string" + }, + "ClosedById__c": { + "apiName": "ClosedById__c", + "label": "Closed By ID", + "localApiName": "ClosedById__c", + "type": "string" + }, + "ClosedByUsername__c": { + "apiName": "ClosedByUsername__c", + "label": "Closed By Username", + "localApiName": "ClosedByUsername__c", + "type": "string" + }, + "ClosedDate__c": { + "apiName": "ClosedDate__c", + "label": "Closed Date", + "localApiName": "ClosedDate__c", + "type": "datetime" + }, + "Comments__c": { + "apiName": "Comments__c", + "label": "Comments", + "localApiName": "Comments__c", + "type": "textarea" + }, + "ComponentType__c": { + "apiName": "ComponentType__c", + "label": "Component Type", + "localApiName": "ComponentType__c", + "type": "string" + }, + "DatabaseResultCollectionSize__c": { + "apiName": "DatabaseResultCollectionSize__c", + "inlineHelpText": "The number of items contained in the collection of database results", + "label": "Database Result Collection Size", + "localApiName": "DatabaseResultCollectionSize__c", + "type": "double" + }, + "DatabaseResultCollectionType__c": { + "apiName": "DatabaseResultCollectionType__c", + "label": "Database Result Collection Type", + "localApiName": "DatabaseResultCollectionType__c", + "type": "string" + }, + "DatabaseResultJson__c": { + "apiName": "DatabaseResultJson__c", + "label": "Database Result JSON", + "localApiName": "DatabaseResultJson__c", + "type": "textarea" + }, + "DatabaseResultType__c": { + "apiName": "DatabaseResultType__c", + "label": "Database Result Type", + "localApiName": "DatabaseResultType__c", + "type": "string" + }, + "EpochTimestamp__c": { + "apiName": "EpochTimestamp__c", + "label": "Epoch Timestamp", + "localApiName": "EpochTimestamp__c", + "type": "double" + }, + "ExceptionMessage__c": { + "apiName": "ExceptionMessage__c", + "label": "Exception Message", + "localApiName": "ExceptionMessage__c", + "type": "textarea" + }, + "ExceptionStackTrace__c": { + "apiName": "ExceptionStackTrace__c", + "label": "Exception Stack Trace", + "localApiName": "ExceptionStackTrace__c", + "type": "textarea" + }, + "ExceptionType__c": { + "apiName": "ExceptionType__c", + "label": "Exception Type", + "localApiName": "ExceptionType__c", + "type": "string" + }, + "IsClosed__c": { + "apiName": "IsClosed__c", + "label": "Is Closed", + "localApiName": "IsClosed__c", + "type": "string" + }, + "IsResolved__c": { + "apiName": "IsResolved__c", + "label": "Is Resolved", + "localApiName": "IsResolved__c", + "type": "string" + }, + "Issue__c": { + "apiName": "Issue__c", + "label": "Issue", + "localApiName": "Issue__c", + "type": "string" + }, + "LimitsAggregateQueriesMax__c": { + "apiName": "LimitsAggregateQueriesMax__c", + "label": "Aggregate Queries Max", + "localApiName": "LimitsAggregateQueriesMax__c", + "type": "double" + }, + "LimitsAggregateQueriesUsed__c": { + "apiName": "LimitsAggregateQueriesUsed__c", + "label": "Aggregate Queries Used", + "localApiName": "LimitsAggregateQueriesUsed__c", + "type": "double" + }, + "LimitsAggregateQueryMax__c": { + "apiName": "LimitsAggregateQueryMax__c", + "label": "Limits AggregateQueryMax_", + "localApiName": "LimitsAggregateQueryMax__c", + "type": "double" + }, + "LimitsAsyncCallsMax__c": { + "apiName": "LimitsAsyncCallsMax__c", + "label": "Async Calls Max", + "localApiName": "LimitsAsyncCallsMax__c", + "type": "double" + }, + "LimitsAsyncCallsUsed__c": { + "apiName": "LimitsAsyncCallsUsed__c", + "label": "Async Calls Used", + "localApiName": "LimitsAsyncCallsUsed__c", + "type": "double" + }, + "LimitsCalloutsMax__c": { + "apiName": "LimitsCalloutsMax__c", + "label": "Callouts Max", + "localApiName": "LimitsCalloutsMax__c", + "type": "double" + }, + "LimitsCalloutsUsed__c": { + "apiName": "LimitsCalloutsUsed__c", + "label": "Callouts Used", + "localApiName": "LimitsCalloutsUsed__c", + "type": "double" + }, + "LimitsCpuTimeMax__c": { + "apiName": "LimitsCpuTimeMax__c", + "label": "CPU Time Max", + "localApiName": "LimitsCpuTimeMax__c", + "type": "double" + }, + "LimitsCpuTimeUsed__c": { + "apiName": "LimitsCpuTimeUsed__c", + "label": "CPU Time Used", + "localApiName": "LimitsCpuTimeUsed__c", + "type": "double" + }, + "LimitsDmlRowsMax__c": { + "apiName": "LimitsDmlRowsMax__c", + "label": "DML Rows Max", + "localApiName": "LimitsDmlRowsMax__c", + "type": "double" + }, + "LimitsDmlRowsUsed__c": { + "apiName": "LimitsDmlRowsUsed__c", + "label": "DML Rows Used", + "localApiName": "LimitsDmlRowsUsed__c", + "type": "double" + }, + "LimitsDmlStatementsMax__c": { + "apiName": "LimitsDmlStatementsMax__c", + "label": "DML Statements Max", + "localApiName": "LimitsDmlStatementsMax__c", + "type": "double" + }, + "LimitsDmlStatementsUsed__c": { + "apiName": "LimitsDmlStatementsUsed__c", + "label": "DML Statements Used", + "localApiName": "LimitsDmlStatementsUsed__c", + "type": "double" + }, + "LimitsEmailInvocationsMax__c": { + "apiName": "LimitsEmailInvocationsMax__c", + "label": "Email Invocations Max", + "localApiName": "LimitsEmailInvocationsMax__c", + "type": "double" + }, + "LimitsEmailInvocationsUsed__c": { + "apiName": "LimitsEmailInvocationsUsed__c", + "label": "Email Invocations Used", + "localApiName": "LimitsEmailInvocationsUsed__c", + "type": "double" + }, + "LimitsFutureCallsMax__c": { + "apiName": "LimitsFutureCallsMax__c", + "label": "Future Calls Max", + "localApiName": "LimitsFutureCallsMax__c", + "type": "double" + }, + "LimitsFutureCallsUsed__c": { + "apiName": "LimitsFutureCallsUsed__c", + "label": "Future Calls Used", + "localApiName": "LimitsFutureCallsUsed__c", + "type": "double" + }, + "LimitsHeapSizeMax__c": { + "apiName": "LimitsHeapSizeMax__c", + "label": "Heap Size Max", + "localApiName": "LimitsHeapSizeMax__c", + "type": "double" + }, + "LimitsHeapSizeUsed__c": { + "apiName": "LimitsHeapSizeUsed__c", + "label": "Heap Size Used", + "localApiName": "LimitsHeapSizeUsed__c", + "type": "double" + }, + "LimitsMobilePushApexCallsMax__c": { + "apiName": "LimitsMobilePushApexCallsMax__c", + "label": "Mobile Push Apex Calls Max", + "localApiName": "LimitsMobilePushApexCallsMax__c", + "type": "double" + }, + "LimitsMobilePushApexCallsUsed__c": { + "apiName": "LimitsMobilePushApexCallsUsed__c", + "label": "Mobile Push Apex Calls Used", + "localApiName": "LimitsMobilePushApexCallsUsed__c", + "type": "double" + }, + "LimitsPublishImmediateDmlStatementsMax__c": { + "apiName": "LimitsPublishImmediateDmlStatementsMax__c", + "label": "Publish Immediate Statements DML Max", + "localApiName": "LimitsPublishImmediateDmlStatementsMax__c", + "type": "double" + }, + "LimitsPublishImmediateDmlStatementsUsed__c": { + "apiName": "LimitsPublishImmediateDmlStatementsUsed__c", + "label": "Publish Immediate Statements DML Used", + "localApiName": "LimitsPublishImmediateDmlStatementsUsed__c", + "type": "double" + }, + "LimitsQueueableJobsMax__c": { + "apiName": "LimitsQueueableJobsMax__c", + "label": "Queueable Jobs Max", + "localApiName": "LimitsQueueableJobsMax__c", + "type": "double" + }, + "LimitsQueueableJobsUsed__c": { + "apiName": "LimitsQueueableJobsUsed__c", + "label": "Queueable Jobs Used", + "localApiName": "LimitsQueueableJobsUsed__c", + "type": "double" + }, + "LimitsSoqlQueriesMax__c": { + "apiName": "LimitsSoqlQueriesMax__c", + "label": "SOQL Queries Max", + "localApiName": "LimitsSoqlQueriesMax__c", + "type": "double" + }, + "LimitsSoqlQueriesUsed__c": { + "apiName": "LimitsSoqlQueriesUsed__c", + "label": "SOQL Queries Used", + "localApiName": "LimitsSoqlQueriesUsed__c", + "type": "double" + }, + "LimitsSoqlQueryLocatorRowsMax__c": { + "apiName": "LimitsSoqlQueryLocatorRowsMax__c", + "label": "SOQL Query Locator Rows Max", + "localApiName": "LimitsSoqlQueryLocatorRowsMax__c", + "type": "double" + }, + "LimitsSoqlQueryLocatorRowsUsed__c": { + "apiName": "LimitsSoqlQueryLocatorRowsUsed__c", + "label": "SOQL Query Locator Rows Used", + "localApiName": "LimitsSoqlQueryLocatorRowsUsed__c", + "type": "double" + }, + "LimitsSoqlQueryRowsMax__c": { + "apiName": "LimitsSoqlQueryRowsMax__c", + "label": "SOQL Query Rows Max", + "localApiName": "LimitsSoqlQueryRowsMax__c", + "type": "double" + }, + "LimitsSoqlQueryRowsUsed__c": { + "apiName": "LimitsSoqlQueryRowsUsed__c", + "label": "SOQL Query Rows Used", + "localApiName": "LimitsSoqlQueryRowsUsed__c", + "type": "double" + }, + "LimitsSoslSearchesMax__c": { + "apiName": "LimitsSoslSearchesMax__c", + "label": "SOSL Searches Max", + "localApiName": "LimitsSoslSearchesMax__c", + "type": "double" + }, + "LimitsSoslSearchesUsed__c": { + "apiName": "LimitsSoslSearchesUsed__c", + "label": "SOSL Searches Used", + "localApiName": "LimitsSoslSearchesUsed__c", + "type": "double" + }, + "Locale__c": { + "apiName": "Locale__c", + "label": "Locale", + "localApiName": "Locale__c", + "type": "string" + }, + "LogEntryName__c": { + "apiName": "LogEntryName__c", + "label": "Log Name", + "localApiName": "LogEntryName__c", + "type": "string" + }, + "LogName__c": { + "apiName": "LogName__c", + "label": "Log Name", + "localApiName": "LogName__c", + "type": "string" + }, + "LogPurgeAction__c": { + "apiName": "LogPurgeAction__c", + "label": "Log Purge Action", + "localApiName": "LogPurgeAction__c", + "type": "string" + }, + "LogRetentionDate__c": { + "apiName": "LogRetentionDate__c", + "label": "Log Retention Date", + "localApiName": "LogRetentionDate__c", + "type": "datetime" + }, + "LoggedById__c": { + "apiName": "LoggedById__c", + "label": "Logged By ID", + "localApiName": "LoggedById__c", + "type": "string" + }, + "LoggedByUsername__c": { + "apiName": "LoggedByUsername__c", + "label": "Username", + "localApiName": "LoggedByUsername__c", + "type": "string" + }, + "LoggerVersionNumber__c": { + "apiName": "LoggerVersionNumber__c", + "label": "Logger Version Number", + "localApiName": "LoggerVersionNumber__c", + "type": "string" + }, + "LoggingLevelOrdinal__c": { + "apiName": "LoggingLevelOrdinal__c", + "label": "Logging Level Ordinal", + "localApiName": "LoggingLevelOrdinal__c", + "type": "double" + }, + "LoggingLevel__c": { + "apiName": "LoggingLevel__c", + "label": "Logging Level", + "localApiName": "LoggingLevel__c", + "type": "string" + }, + "LoginApplication__c": { + "apiName": "LoginApplication__c", + "label": "Login Application", + "localApiName": "LoginApplication__c", + "type": "string" + }, + "LoginBrowser__c": { + "apiName": "LoginBrowser__c", + "label": "Login Browser", + "localApiName": "LoginBrowser__c", + "type": "string" + }, + "LoginDomain__c": { + "apiName": "LoginDomain__c", + "label": "DEPRECATED: Login Domain", + "localApiName": "LoginDomain__c", + "type": "string" + }, + "LoginHistoryId__c": { + "apiName": "LoginHistoryId__c", + "label": "Login History ID", + "localApiName": "LoginHistoryId__c", + "type": "string" + }, + "LoginPlatform__c": { + "apiName": "LoginPlatform__c", + "label": "Login Platform", + "localApiName": "LoginPlatform__c", + "type": "string" + }, + "LoginType__c": { + "apiName": "LoginType__c", + "label": "Login Type", + "localApiName": "LoginType__c", + "type": "string" + }, + "LogoutUrl__c": { + "apiName": "LogoutUrl__c", + "label": "Logout URL", + "localApiName": "LogoutUrl__c", + "type": "string" + }, + "MessageMasked__c": { + "apiName": "MessageMasked__c", + "label": "Message Masked", + "localApiName": "MessageMasked__c", + "type": "string" + }, + "MessageTruncated__c": { + "apiName": "MessageTruncated__c", + "label": "Message Truncated", + "localApiName": "MessageTruncated__c", + "type": "string" + }, + "Message__c": { + "apiName": "Message__c", + "label": "Message", + "localApiName": "Message__c", + "type": "textarea" + }, + "NetworkId__c": { + "apiName": "NetworkId__c", + "label": "Network ID", + "localApiName": "NetworkId__c", + "type": "string" + }, + "NetworkLoginUrl__c": { + "apiName": "NetworkLoginUrl__c", + "label": "Site Login URL", + "localApiName": "NetworkLoginUrl__c", + "type": "string" + }, + "NetworkLogoutUrl__c": { + "apiName": "NetworkLogoutUrl__c", + "label": "Site Logout URL", + "localApiName": "NetworkLogoutUrl__c", + "type": "string" + }, + "NetworkName__c": { + "apiName": "NetworkName__c", + "label": "Site Name", + "localApiName": "NetworkName__c", + "type": "string" + }, + "NetworkSelfRegistrationUrl__c": { + "apiName": "NetworkSelfRegistrationUrl__c", + "label": "Site Self Registration URL", + "localApiName": "NetworkSelfRegistrationUrl__c", + "type": "string" + }, + "NetworkUrlPathPrefix__c": { + "apiName": "NetworkUrlPathPrefix__c", + "label": "Site URL Path Prefix", + "localApiName": "NetworkUrlPathPrefix__c", + "type": "string" + }, + "OrganizationDomainUrl__c": { + "apiName": "OrganizationDomainUrl__c", + "label": "Organization Domain URL", + "localApiName": "OrganizationDomainUrl__c", + "type": "string" + }, + "OrganizationEnvironmentType__c": { + "apiName": "OrganizationEnvironmentType__c", + "label": "Organization Environment Type", + "localApiName": "OrganizationEnvironmentType__c", + "type": "string" + }, + "OrganizationId__c": { + "apiName": "OrganizationId__c", + "label": "Organization ID", + "localApiName": "OrganizationId__c", + "type": "string" + }, + "OrganizationInstanceName__c": { + "apiName": "OrganizationInstanceName__c", + "label": "Organization Instance Name", + "localApiName": "OrganizationInstanceName__c", + "type": "string" + }, + "OrganizationInstanceReleaseCycle__c": { + "apiName": "OrganizationInstanceReleaseCycle__c", + "label": "DEPRECATED: Instance Release Cycle", + "localApiName": "OrganizationInstanceReleaseCycle__c", + "type": "string" + }, + "OrganizationName__c": { + "apiName": "OrganizationName__c", + "label": "Organization Name", + "localApiName": "OrganizationName__c", + "type": "string" + }, + "OrganizationNamespacePrefix__c": { + "apiName": "OrganizationNamespacePrefix__c", + "label": "Organization Namespace Prefix", + "localApiName": "OrganizationNamespacePrefix__c", + "type": "string" + }, + "OrganizationType__c": { + "apiName": "OrganizationType__c", + "label": "Organization Type", + "localApiName": "OrganizationType__c", + "type": "string" + }, + "OriginLocation__c": { + "apiName": "OriginLocation__c", + "label": "Origin Location", + "localApiName": "OriginLocation__c", + "type": "string" + }, + "OriginType__c": { + "apiName": "OriginType__c", + "label": "Origin Type", + "localApiName": "OriginType__c", + "type": "string" + }, + "ParentLogTransactionId__c": { + "apiName": "ParentLogTransactionId__c", + "label": "Parent Log Transaction ID", + "localApiName": "ParentLogTransactionId__c", + "type": "string" + }, + "Priority__c": { + "apiName": "Priority__c", + "label": "Priority", + "localApiName": "Priority__c", + "type": "string" + }, + "ProfileId__c": { + "apiName": "ProfileId__c", + "label": "Profile ID", + "localApiName": "ProfileId__c", + "type": "string" + }, + "ProfileName__c": { + "apiName": "ProfileName__c", + "label": "Profile Name", + "localApiName": "ProfileName__c", + "type": "string" + }, + "RecordCollectionSize__c": { + "apiName": "RecordCollectionSize__c", + "inlineHelpText": "The number of items contained in the collection of database results", + "label": "Related Record Collection Size", + "localApiName": "RecordCollectionSize__c", + "type": "double" + }, + "RecordCollectionType__c": { + "apiName": "RecordCollectionType__c", + "label": "Related Record Collection Type", + "localApiName": "RecordCollectionType__c", + "type": "string" + }, + "RecordId__c": { + "apiName": "RecordId__c", + "label": "Related Record ID", + "localApiName": "RecordId__c", + "type": "string" + }, + "RecordJsonMasked__c": { + "apiName": "RecordJsonMasked__c", + "label": "Record JSON Masked", + "localApiName": "RecordJsonMasked__c", + "type": "string" + }, + "RecordJson__c": { + "apiName": "RecordJson__c", + "label": "Related Record JSON", + "localApiName": "RecordJson__c", + "type": "textarea" + }, + "RecordSObjectClassification__c": { + "apiName": "RecordSObjectClassification__c", + "label": "Related Record SObject Classification", + "localApiName": "RecordSObjectClassification__c", + "type": "string" + }, + "RecordSObjectTypeNamespace__c": { + "apiName": "RecordSObjectTypeNamespace__c", + "label": "Related Record Object Namespace", + "localApiName": "RecordSObjectTypeNamespace__c", + "type": "string" + }, + "RecordSObjectType__c": { + "apiName": "RecordSObjectType__c", + "label": "Related Record SObject Type", + "localApiName": "RecordSObjectType__c", + "type": "string" + }, + "Scenario__c": { + "apiName": "Scenario__c", + "label": "Scenario", + "localApiName": "Scenario__c", + "type": "string" + }, + "SessionId__c": { + "apiName": "SessionId__c", + "label": "SessionId", + "localApiName": "SessionId__c", + "type": "string" + }, + "SessionSecurityLevel__c": { + "apiName": "SessionSecurityLevel__c", + "label": "Session Security Level", + "localApiName": "SessionSecurityLevel__c", + "type": "string" + }, + "SessionType__c": { + "apiName": "SessionType__c", + "label": "Session Type", + "localApiName": "SessionType__c", + "type": "string" + }, + "SourceIp__c": { + "apiName": "SourceIp__c", + "label": "Source IP", + "localApiName": "SourceIp__c", + "type": "string" + }, + "StackTrace__c": { + "apiName": "StackTrace__c", + "label": "Stack Trace", + "localApiName": "StackTrace__c", + "type": "textarea" + }, + "Status__c": { + "apiName": "Status__c", + "label": "Status", + "localApiName": "Status__c", + "type": "string" + }, + "SystemMode__c": { + "apiName": "SystemMode__c", + "label": "System Mode", + "localApiName": "SystemMode__c", + "type": "string" + }, + "Tags__c": { + "apiName": "Tags__c", + "label": "Tags", + "localApiName": "Tags__c", + "type": "textarea" + }, + "ThemeDisplayed__c": { + "apiName": "ThemeDisplayed__c", + "label": "Theme Displayed", + "localApiName": "ThemeDisplayed__c", + "type": "string" + }, + "TimeZoneId__c": { + "apiName": "TimeZoneId__c", + "label": "Time Zone ID", + "localApiName": "TimeZoneId__c", + "type": "string" + }, + "TimeZoneName__c": { + "apiName": "TimeZoneName__c", + "label": "Time Zone Name", + "localApiName": "TimeZoneName__c", + "type": "string" + }, + "TimestampString__c": { + "apiName": "TimestampString__c", + "label": "Timestamp String", + "localApiName": "TimestampString__c", + "type": "string" + }, + "Timestamp__c": { + "apiName": "Timestamp__c", + "label": "Timestamp", + "localApiName": "Timestamp__c", + "type": "datetime" + }, + "TransactionEntryNumber__c": { + "apiName": "TransactionEntryNumber__c", + "label": "Entry #", + "localApiName": "TransactionEntryNumber__c", + "type": "double" + }, + "TransactionId__c": { + "apiName": "TransactionId__c", + "label": "Transaction ID", + "localApiName": "TransactionId__c", + "type": "string" + }, + "TriggerIsExecuting__c": { + "apiName": "TriggerIsExecuting__c", + "label": "Trigger Is Executing", + "localApiName": "TriggerIsExecuting__c", + "type": "string" + }, + "TriggerOperationType__c": { + "apiName": "TriggerOperationType__c", + "label": "Trigger Operation Type", + "localApiName": "TriggerOperationType__c", + "type": "string" + }, + "TriggerSObjectType__c": { + "apiName": "TriggerSObjectType__c", + "label": "Trigger SObject Type", + "localApiName": "TriggerSObjectType__c", + "type": "string" + }, + "UserLicenseDefinitionKey__c": { + "apiName": "UserLicenseDefinitionKey__c", + "label": "User License Definition Key", + "localApiName": "UserLicenseDefinitionKey__c", + "type": "string" + }, + "UserLicenseId__c": { + "apiName": "UserLicenseId__c", + "label": "User License ID", + "localApiName": "UserLicenseId__c", + "type": "string" + }, + "UserLicenseName__c": { + "apiName": "UserLicenseName__c", + "label": "User License Name", + "localApiName": "UserLicenseName__c", + "type": "string" + }, + "UserLoggingLevelOrdinal__c": { + "apiName": "UserLoggingLevelOrdinal__c", + "label": "User Logging Level Ordinal", + "localApiName": "UserLoggingLevelOrdinal__c", + "type": "double" + }, + "UserLoggingLevel__c": { + "apiName": "UserLoggingLevel__c", + "label": "User Logging Level", + "localApiName": "UserLoggingLevel__c", + "type": "string" + }, + "UserRoleId__c": { + "apiName": "UserRoleId__c", + "label": "User Role ID", + "localApiName": "UserRoleId__c", + "type": "string" + }, + "UserRoleName__c": { + "apiName": "UserRoleName__c", + "label": "User Role Name", + "localApiName": "UserRoleName__c", + "type": "string" + }, + "UserType__c": { + "apiName": "UserType__c", + "label": "User Type", + "localApiName": "UserType__c", + "type": "string" + } + }, + "label": "Log Entry Archive", + "labelPlural": "Log Entry Archives", + "localApiName": "LogEntryArchive__b", + "namespacePrefix": "" +} diff --git a/nebula-logger/plugins/big-object-archiving/plugin/lwc/logEntryArchives/__tests__/logEntryArchives.test.js b/nebula-logger/plugins/big-object-archiving/plugin/lwc/logEntryArchives/__tests__/logEntryArchives.test.js new file mode 100644 index 000000000..02ef174a2 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/lwc/logEntryArchives/__tests__/logEntryArchives.test.js @@ -0,0 +1,261 @@ +import { createElement } from 'lwc'; +import LogEntryArchives from 'c/logEntryArchives'; +import getLogEntryArchives from '@salesforce/apex/LogEntryArchiveController.getLogEntryArchives'; +import getSchemaForName from '@salesforce/apex/LoggerSObjectMetadata.getSchemaForName'; + +const MOCK_DATA = [{ Message__c: 'Some message', TransactionId__c: 'ABC-123', TransactionEntryNumber__c: 1 }]; +const MOCK_SCHEMA = require('./data/LoggerSObjectMetadata.getSchemaForName.json'); + +const SHOW_TOAST_EVENT_NAME = 'lightning__showtoast'; +const SHOW_TOAST_EVENT_HANDLER = jest.fn(); +jest.mock( + '@salesforce/apex/LogEntryArchiveController.getLogEntryArchives', + () => { + return { + default: jest.fn() + }; + }, + { virtual: true } +); +jest.mock( + '@salesforce/apex/LoggerSObjectMetadata.getSchemaForName', + () => { + return { + default: jest.fn() + }; + }, + { virtual: true } +); + +async function initializeElement() { + const element = createElement('c-log-entry-archives', { + is: LogEntryArchives + }); + element.addEventListener(SHOW_TOAST_EVENT_NAME, SHOW_TOAST_EVENT_HANDLER); + document.body.appendChild(element); + + await Promise.resolve('resolves connectedCallback()'); + await Promise.resolve('resolves getSchemaForName()'); + await Promise.resolve('resolves getLogEntryArchives()'); + await Promise.resolve('resolves getLogEntryArchives().then()'); + await Promise.resolve('resolves lightning-datatable re-render'); + + return element; +} + +describe('c-log-entry-archives', () => { + afterEach(() => { + while (document.body.firstChild) { + document.body.removeChild(document.body.firstChild); + } + jest.clearAllMocks(); + }); + + it('initializes component', async () => { + getSchemaForName.mockResolvedValue(MOCK_SCHEMA); + getLogEntryArchives.mockResolvedValue(MOCK_DATA); + + const element = await initializeElement(); + + expect(document.title).toEqual('Log Entry Archives'); + const expectedTableData = JSON.parse(JSON.stringify(MOCK_DATA)); + expectedTableData.forEach(record => { + record.compositeId = record.TransactionId__c + record.TransactionEntryNumber__c; + }); + const table = element.shadowRoot.querySelector('lightning-datatable'); + expect(table).toBeTruthy(); + expect(table.data).toEqual(expectedTableData); + expect(getSchemaForName).toHaveBeenCalledTimes(1); + expect(getLogEntryArchives).toHaveBeenCalledTimes(1); + const expectedApexParameters = { + endDate: element.shadowRoot.querySelector('[data-id="endDate"]').value, + messageSearchTerm: element.shadowRoot.querySelector('[data-id="messageSearch"]').value, + minimumLoggingLevelOrdinal: Number(element.shadowRoot.querySelector('[data-id="loggingLevelFilter"]').value), + rowLimit: Number(element.shadowRoot.querySelector('[data-id="rowLimitFilter"]').value), + startDate: element.shadowRoot.querySelector('[data-id="startDate"]').value + }; + expect(getLogEntryArchives.mock.calls[0][0]).toBeDefined(); + expect(getLogEntryArchives.mock.calls[0][0]).toEqual(expectedApexParameters); + }); + + it('shows toast message for apex controller error', async () => { + getSchemaForName.mockResolvedValue(MOCK_SCHEMA); + const mockApexError = new Error('It broke!'); + getLogEntryArchives.mockRejectedValue(mockApexError); + + const element = await initializeElement(); + + const table = element.shadowRoot.querySelector('lightning-datatable'); + expect(table).toBeTruthy(); + expect(table.data.length).toEqual(0); + expect(getSchemaForName).toHaveBeenCalledTimes(1); + expect(getLogEntryArchives).toHaveBeenCalledTimes(1); + const expectedApexParameters = { + endDate: element.shadowRoot.querySelector('[data-id="endDate"]').value, + messageSearchTerm: element.shadowRoot.querySelector('[data-id="messageSearch"]').value, + minimumLoggingLevelOrdinal: Number(element.shadowRoot.querySelector('[data-id="loggingLevelFilter"]').value), + rowLimit: Number(element.shadowRoot.querySelector('[data-id="rowLimitFilter"]').value), + startDate: element.shadowRoot.querySelector('[data-id="startDate"]').value + }; + expect(getLogEntryArchives.mock.calls[0][0]).toBeDefined(); + expect(getLogEntryArchives.mock.calls[0][0]).toEqual(expectedApexParameters); + expect(SHOW_TOAST_EVENT_HANDLER).toBeCalledTimes(1); + }); + + it('requeries when start date changes', async () => { + getSchemaForName.mockResolvedValue(MOCK_SCHEMA); + getLogEntryArchives.mockResolvedValue(MOCK_DATA); + const element = await initializeElement(); + const threeDaysAgo = new Date(new Date().getTime() + -3 * 24 * 60 * 60 * 1000).toISOString(); + expect(getLogEntryArchives).toHaveBeenCalledTimes(1); + expect(getLogEntryArchives.mock.calls[0][0]).toBeDefined(); + expect(getLogEntryArchives.mock.calls[0][0].startDate).toBeDefined(); + expect(getLogEntryArchives.mock.calls[0][0].startDate).not.toEqual(threeDaysAgo); + + const startDateInput = element.shadowRoot.querySelector('[data-id="startDate"]'); + startDateInput.dispatchEvent( + new CustomEvent('change', { + detail: { + value: threeDaysAgo + } + }) + ); + + await Promise.resolve('resolves getLogEntryArchives()'); + await Promise.resolve('resolves getLogEntryArchives().then()'); + await Promise.resolve('resolves lightning-datatable re-render'); + expect(getLogEntryArchives.mock.calls[1][0]).toBeDefined(); + expect(getLogEntryArchives.mock.calls[1][0].startDate).toEqual(threeDaysAgo); + }); + + it('requeries when end date changes', async () => { + getSchemaForName.mockResolvedValue(MOCK_SCHEMA); + getLogEntryArchives.mockResolvedValue(MOCK_DATA); + const element = await initializeElement(); + const threeDaysAgo = new Date(new Date().getTime() + -3 * 24 * 60 * 60 * 1000).toISOString(); + expect(getLogEntryArchives).toHaveBeenCalledTimes(1); + expect(getLogEntryArchives.mock.calls[0][0]).toBeDefined(); + expect(getLogEntryArchives.mock.calls[0][0].endDate).toBeDefined(); + expect(getLogEntryArchives.mock.calls[0][0].endDate).not.toEqual(threeDaysAgo); + + const endDateInput = element.shadowRoot.querySelector('[data-id="endDate"]'); + endDateInput.dispatchEvent( + new CustomEvent('change', { + detail: { + value: threeDaysAgo + } + }) + ); + + await Promise.resolve('resolves getLogEntryArchives()'); + await Promise.resolve('resolves getLogEntryArchives().then()'); + await Promise.resolve('resolves lightning-datatable re-render'); + expect(getLogEntryArchives.mock.calls[1][0]).toBeDefined(); + expect(getLogEntryArchives.mock.calls[1][0].endDate).toEqual(threeDaysAgo); + }); + + it('requeries when logging level changes', async () => { + getSchemaForName.mockResolvedValue(MOCK_SCHEMA); + getLogEntryArchives.mockResolvedValue(MOCK_DATA); + const element = await initializeElement(); + const errorLoggingLevelOrdinal = '8'; + expect(getLogEntryArchives).toHaveBeenCalledTimes(1); + expect(getLogEntryArchives.mock.calls[0][0]).toBeDefined(); + expect(getLogEntryArchives.mock.calls[0][0].minimumLoggingLevelOrdinal).toBeDefined(); + expect(getLogEntryArchives.mock.calls[0][0].minimumLoggingLevelOrdinal).not.toEqual(Number(errorLoggingLevelOrdinal)); + + const minimumLoggingLevelOrdinalInput = element.shadowRoot.querySelector('[data-id="loggingLevelFilter"]'); + minimumLoggingLevelOrdinalInput.value = errorLoggingLevelOrdinal; + minimumLoggingLevelOrdinalInput.dispatchEvent( + new CustomEvent('change', { + target: { + value: errorLoggingLevelOrdinal + } + }) + ); + + await Promise.resolve('resolves getLogEntryArchives()'); + await Promise.resolve('resolves getLogEntryArchives().then()'); + await Promise.resolve('resolves lightning-datatable re-render'); + expect(getLogEntryArchives.mock.calls[1][0]).toBeDefined(); + expect(getLogEntryArchives.mock.calls[1][0].minimumLoggingLevelOrdinal).toEqual(Number(errorLoggingLevelOrdinal)); + }); + + it('requeries when message search term changes', async () => { + getSchemaForName.mockResolvedValue(MOCK_SCHEMA); + getLogEntryArchives.mockResolvedValue(MOCK_DATA); + const element = await initializeElement(); + const newMessageSearchTerm = 'hello, is this thing working??'; + expect(getLogEntryArchives).toHaveBeenCalledTimes(1); + expect(getLogEntryArchives.mock.calls[0][0]).toBeDefined(); + expect(getLogEntryArchives.mock.calls[0][0].messageSearchTerm).toBeUndefined(); + expect(getLogEntryArchives.mock.calls[0][0].messageSearchTerm).not.toEqual(newMessageSearchTerm); + + const messageSearchTermFilterInput = element.shadowRoot.querySelector('[data-id="messageSearch"]'); + messageSearchTermFilterInput.value = newMessageSearchTerm; + messageSearchTermFilterInput.dispatchEvent( + new CustomEvent('change', { + target: { + value: newMessageSearchTerm + } + }) + ); + + await Promise.resolve('resolves getLogEntryArchives()'); + await Promise.resolve('resolves getLogEntryArchives().then()'); + await Promise.resolve('resolves lightning-datatable re-render'); + expect(getLogEntryArchives.mock.calls[1][0]).toBeDefined(); + expect(getLogEntryArchives.mock.calls[1][0].messageSearchTerm).toEqual(newMessageSearchTerm); + }); + + it('requeries when row limit changes', async () => { + getSchemaForName.mockResolvedValue(MOCK_SCHEMA); + getLogEntryArchives.mockResolvedValue(MOCK_DATA); + const element = await initializeElement(); + const newRowLimit = '987654321'; + expect(getLogEntryArchives).toHaveBeenCalledTimes(1); + expect(getLogEntryArchives.mock.calls[0][0]).toBeDefined(); + expect(getLogEntryArchives.mock.calls[0][0].rowLimit).toBeDefined(); + expect(getLogEntryArchives.mock.calls[0][0].rowLimit).not.toEqual(Number(newRowLimit)); + + const rowLimitFilterInput = element.shadowRoot.querySelector('[data-id="rowLimitFilter"]'); + rowLimitFilterInput.value = newRowLimit; + rowLimitFilterInput.dispatchEvent( + new CustomEvent('change', { + target: { + value: newRowLimit + } + }) + ); + + await Promise.resolve('resolves getLogEntryArchives()'); + await Promise.resolve('resolves getLogEntryArchives().then()'); + await Promise.resolve('resolves lightning-datatable re-render'); + expect(getLogEntryArchives.mock.calls[1][0]).toBeDefined(); + expect(getLogEntryArchives.mock.calls[1][0].rowLimit).toEqual(Number(newRowLimit)); + }); + + it('requeries when refresh button is clicked', async () => { + getSchemaForName.mockResolvedValue(MOCK_SCHEMA); + getLogEntryArchives.mockResolvedValue(MOCK_DATA); + const element = await initializeElement(); + const expectedApexParameters = { + endDate: element.shadowRoot.querySelector('[data-id="endDate"]').value, + messageSearchTerm: element.shadowRoot.querySelector('[data-id="messageSearch"]').value, + minimumLoggingLevelOrdinal: Number(element.shadowRoot.querySelector('[data-id="loggingLevelFilter"]').value), + rowLimit: Number(element.shadowRoot.querySelector('[data-id="rowLimitFilter"]').value), + startDate: element.shadowRoot.querySelector('[data-id="startDate"]').value + }; + expect(getLogEntryArchives.mock.calls[0][0]).toBeDefined(); + expect(getLogEntryArchives.mock.calls[0][0]).toEqual(expectedApexParameters); + + const refreshButton = element.shadowRoot.querySelector('[data-id="refresh-btn"]'); + refreshButton.click(); + + await Promise.resolve('resolves getLogEntryArchives()'); + await Promise.resolve('resolves getLogEntryArchives().then()'); + await Promise.resolve('resolves lightning-datatable re-render'); + expect(getLogEntryArchives.mock.calls[1][0]).toBeDefined(); + expect(getLogEntryArchives.mock.calls[1][0]).toEqual(expectedApexParameters); + }); +}); diff --git a/nebula-logger/plugins/big-object-archiving/plugin/lwc/logEntryArchives/logEntryArchives.html b/nebula-logger/plugins/big-object-archiving/plugin/lwc/logEntryArchives/logEntryArchives.html new file mode 100644 index 000000000..a69c6694e --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/lwc/logEntryArchives/logEntryArchives.html @@ -0,0 +1,88 @@ + + + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/lwc/logEntryArchives/logEntryArchives.js b/nebula-logger/plugins/big-object-archiving/plugin/lwc/logEntryArchives/logEntryArchives.js new file mode 100644 index 000000000..b03e435ed --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/lwc/logEntryArchives/logEntryArchives.js @@ -0,0 +1,195 @@ +/************************************************************************************************* + * This file is part of the Nebula Logger project, released under the MIT License. * + * See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. * + ************************************************************************************************/ + +import { LightningElement } from 'lwc'; +import { ShowToastEvent } from 'lightning/platformShowToastEvent'; +import getSchemaForName from '@salesforce/apex/LoggerSObjectMetadata.getSchemaForName'; +import getLogEntryArchives from '@salesforce/apex/LogEntryArchiveController.getLogEntryArchives'; + +export default class LogEntryArchives extends LightningElement { + isLoading = false; + logEntryArchives = []; + startDate = new Date(new Date().getTime() + -60 * 24 * 60 * 60 * 1000).toISOString(); // 60 days ago + endDate = new Date().toISOString(); + minimumLoggingLevelOrdinal; + rowLimit; + _schema = {}; + _messageSearchTerm; + + async connectedCallback() { + this.minimumLoggingLevelOrdinal = this.loggingLevelOptions[this.loggingLevelOptions.length - 1].value; + this.rowLimit = this.rowLimitOptions[0].value; + await getSchemaForName({ sobjectApiName: 'LogEntryArchive__b' }).then(data => { + this._schema = data; + document.title = this._schema.labelPlural; + }); + this._loadColumns(); + await this._loadLogEntryArchives(); + } + + get title() { + return this.logEntryArchives.length + ' ' + this._schema.labelPlural; + } + + get loggingLevelOptions() { + return [ + { label: 'ERROR', value: '8' }, + { label: 'WARN', value: '7' }, + { label: 'INFO', value: '6' }, + { label: 'DEBUG', value: '5' }, + { label: 'FINE', value: '4' }, + { label: 'FINER', value: '3' }, + { label: 'FINEST', value: '2' } + ]; + } + + get rowLimitOptions() { + return [ + { label: '50 Records', value: '50' }, + { label: '100 Records', value: '100' } + ]; + } + + handleDateChange(event) { + const updatedProperty = event.target.dataset.id; + this[updatedProperty] = !event.detail.value ? '' : new Date(event.detail.value).toISOString(); + this._loadLogEntryArchives(); + } + + handleLoggingLevelFilterChange(event) { + const selectedLoggingLevelOrdinal = event.target.value; + this.minimumLoggingLevelOrdinal = selectedLoggingLevelOrdinal; + this._loadLogEntryArchives(); + } + + handleRowLimitFilterChange(event) { + const selectedRowLimit = event.target.value; + this.rowLimit = selectedRowLimit; + this._loadLogEntryArchives(); + } + + handleSearch(event) { + this._messageSearchTerm = event.target.value; + this._loadLogEntryArchives(); + } + + handleRefresh() { + const searchTerm = this.template.querySelector('lightning-input').value; + this._loadLogEntryArchives(searchTerm); + } + + // TODO Future release, add 'View' action with ability to view more fields for a `LogEntryArchive__b` record (similar to loggerSettings LWC) + // handleRowAction(event) { + // const actionName = event.detail.action.name; + // const row = event.detail.row; + // /* eslint-disable-next-line default-case */ + // switch (actionName) { + // case 'view': + // alert('TODO!'); + // // this._viewCurrentRecord(row); + // break; + // } + // } + + async _loadLogEntryArchives() { + let hasInvalidInputs = false; + this.template.querySelectorAll('lightning-input, lightning-comboxbox').forEach(input => { + if (input.reportValidity() === false) { + hasInvalidInputs = true; + } + }); + + if (hasInvalidInputs === true) { + return; + } + + this.isLoading = true; + this.logEntryArchives = []; + getLogEntryArchives({ + startDate: this.startDate, + endDate: this.endDate, + rowLimit: Number(this.rowLimit), + messageSearchTerm: this._messageSearchTerm, + minimumLoggingLevelOrdinal: Number(this.minimumLoggingLevelOrdinal) + }) + .then(results => { + this.logEntryArchives = JSON.parse(JSON.stringify(results)); + + this.logEntryArchives.forEach(archive => { + archive.compositeId = archive.TransactionId__c + archive.TransactionEntryNumber__c; + }); + this.isLoading = false; + }) + .catch(this._handleError); + } + + _loadColumns() { + this.columns = []; + + const tableColumnNames = [ + 'LoggedByUsername__c', + 'TransactionId__c', + 'TransactionEntryNumber__c', + 'LoggingLevel__c', + 'OriginType__c', + 'OriginLocation__c', + 'Message__c', + 'Timestamp__c' + ]; + for (let i = 0; i < tableColumnNames.length; i++) { + const field = this._schema.fields[tableColumnNames[i]]; + const column = { + fieldName: field.localApiName, + label: field.label, + type: field.type.toLowerCase() + }; + if (column.type === 'datetime') { + column.type = 'date'; + // FIXME and make dynamic based on user prefences for datetimes + column.typeAttributes = { + month: '2-digit', + day: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + second: '2-digit' + }; + } else if (column.type === 'string') { + column.type = 'text'; + } else if (column.type === 'textarea') { + column.wrapText = true; + } + this.columns.push(column); + } + + // TODO Finish in a future release + // Append the row-level actions + // let tableRowActions = [{ label: 'View', name: 'view' }]; + // this.columns.push({ + // type: 'action', + // typeAttributes: { + // menuAlignment: 'auto' + // rowActions: tableRowActions, + // } + // }); + } + + _handleError = error => { + const errorMessage = error.body ? error.body.message : 'error.message'; + const errorStackTrace = error.body ? error.body.stackTrace : ''; + const errorExceptionType = error.body ? error.body.exceptionType + ' in ' : ''; + /* eslint-disable-next-line no-console */ + console.error({ error }); + this.dispatchEvent( + new ShowToastEvent({ + message: errorExceptionType + errorStackTrace, + mode: 'sticky', + title: errorMessage, + variant: 'error' + }) + ); + this.isLoading = false; + }; +} diff --git a/nebula-logger/plugins/big-object-archiving/plugin/lwc/logEntryArchives/logEntryArchives.js-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/lwc/logEntryArchives/logEntryArchives.js-meta.xml new file mode 100644 index 000000000..250bdecf9 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/lwc/logEntryArchives/logEntryArchives.js-meta.xml @@ -0,0 +1,9 @@ + + + 54.0 + false + Log Entry Archives + + lightning__Tab + + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/LogEntryArchive__b.object-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/LogEntryArchive__b.object-meta.xml new file mode 100644 index 000000000..01a7b7f72 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/LogEntryArchive__b.object-meta.xml @@ -0,0 +1,8 @@ + + + Deployed + Big Object representation of Logger data, used as an alternative to the platform event LogEntryEvent__e, as well as a way to archive Logger data stored in Log__c, LogEntry__, and LogEntryTag__c + + Log Entry Archives + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ApiReleaseNumber__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ApiReleaseNumber__c.field-meta.xml new file mode 100644 index 000000000..86c92f2ad --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ApiReleaseNumber__c.field-meta.xml @@ -0,0 +1,14 @@ + + + ApiReleaseNumber__c + Active + The release number for the org's instance - determined by making a callout to status.salesforce.com + false + The release number for the org's instance - determined by making a callout to status.salesforce.com + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ApiReleaseVersion__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ApiReleaseVersion__c.field-meta.xml new file mode 100644 index 000000000..3d5985c64 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ApiReleaseVersion__c.field-meta.xml @@ -0,0 +1,14 @@ + + + ApiReleaseVersion__c + Active + The release version for the org's instance - determined by making a callout to status.salesforce.com + false + The release version for the org's instance - determined by making a callout to status.salesforce.com + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ApiVersion__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ApiVersion__c.field-meta.xml new file mode 100644 index 000000000..6d5b6fc42 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ApiVersion__c.field-meta.xml @@ -0,0 +1,10 @@ + + + ApiVersion__c + false + + 5 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ArchiveRetentionDate__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ArchiveRetentionDate__c.field-meta.xml new file mode 100644 index 000000000..0f041325e --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ArchiveRetentionDate__c.field-meta.xml @@ -0,0 +1,11 @@ + + + ArchiveRetentionDate__c + Active + Reserved for future use + false + + false + Confidential + DateTime + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ArchivedById__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ArchivedById__c.field-meta.xml new file mode 100644 index 000000000..bf45424fe --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ArchivedById__c.field-meta.xml @@ -0,0 +1,10 @@ + + + ArchivedById__c + false + + 18 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ArchivedByUsername__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ArchivedByUsername__c.field-meta.xml new file mode 100644 index 000000000..c615e70a0 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ArchivedByUsername__c.field-meta.xml @@ -0,0 +1,12 @@ + + + ArchivedByUsername__c + Active + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ArchivedDate__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ArchivedDate__c.field-meta.xml new file mode 100644 index 000000000..fe628a97e --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ArchivedDate__c.field-meta.xml @@ -0,0 +1,10 @@ + + + ArchivedDate__c + Active + false + + false + Confidential + DateTime + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ClosedById__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ClosedById__c.field-meta.xml new file mode 100644 index 000000000..ff03d352b --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ClosedById__c.field-meta.xml @@ -0,0 +1,10 @@ + + + ClosedById__c + false + + 18 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ClosedByUsername__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ClosedByUsername__c.field-meta.xml new file mode 100644 index 000000000..a45874fe4 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ClosedByUsername__c.field-meta.xml @@ -0,0 +1,12 @@ + + + ClosedByUsername__c + Active + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ClosedDate__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ClosedDate__c.field-meta.xml new file mode 100644 index 000000000..7dc1533db --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ClosedDate__c.field-meta.xml @@ -0,0 +1,10 @@ + + + ClosedDate__c + Active + false + + false + Confidential + DateTime + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Comments__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Comments__c.field-meta.xml new file mode 100644 index 000000000..71b45059f --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Comments__c.field-meta.xml @@ -0,0 +1,11 @@ + + + Comments__c + Active + false + + 4000 + Confidential + LongTextArea + 8 + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ComponentType__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ComponentType__c.field-meta.xml new file mode 100644 index 000000000..8c1d1acf3 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ComponentType__c.field-meta.xml @@ -0,0 +1,10 @@ + + + ComponentType__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/DatabaseResultCollectionSize__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/DatabaseResultCollectionSize__c.field-meta.xml new file mode 100644 index 000000000..bbe1159fb --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/DatabaseResultCollectionSize__c.field-meta.xml @@ -0,0 +1,13 @@ + + + DatabaseResultCollectionSize__c + The number of items contained in the collection of database results + false + The number of items contained in the collection of database results + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/DatabaseResultCollectionType__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/DatabaseResultCollectionType__c.field-meta.xml new file mode 100644 index 000000000..810981951 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/DatabaseResultCollectionType__c.field-meta.xml @@ -0,0 +1,10 @@ + + + DatabaseResultCollectionType__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/DatabaseResultJson__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/DatabaseResultJson__c.field-meta.xml new file mode 100644 index 000000000..0df56c9cc --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/DatabaseResultJson__c.field-meta.xml @@ -0,0 +1,9 @@ + + + DatabaseResultJson__c + false + + 131072 + LongTextArea + 8 + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/DatabaseResultType__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/DatabaseResultType__c.field-meta.xml new file mode 100644 index 000000000..727a0c496 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/DatabaseResultType__c.field-meta.xml @@ -0,0 +1,10 @@ + + + DatabaseResultType__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/EpochTimestamp__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/EpochTimestamp__c.field-meta.xml new file mode 100644 index 000000000..921292c5e --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/EpochTimestamp__c.field-meta.xml @@ -0,0 +1,12 @@ + + + EpochTimestamp__c + Timestamp in milliseconds elapsed since 1 January 1970 of the log event + false + + 18 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/EventUuid__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/EventUuid__c.field-meta.xml new file mode 100644 index 000000000..81ade15d2 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/EventUuid__c.field-meta.xml @@ -0,0 +1,13 @@ + + + EventUuid__c + false + The UUID of the LogEntryEvent__e platform event that created this LogEntry__c record. + +For more details, refer to https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/platform_events_event_uuid.htm + + 36 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ExceptionMessage__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ExceptionMessage__c.field-meta.xml new file mode 100644 index 000000000..33edbb88f --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ExceptionMessage__c.field-meta.xml @@ -0,0 +1,9 @@ + + + ExceptionMessage__c + false + + 131072 + LongTextArea + 8 + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ExceptionStackTrace__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ExceptionStackTrace__c.field-meta.xml new file mode 100644 index 000000000..a6a1ea40f --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ExceptionStackTrace__c.field-meta.xml @@ -0,0 +1,9 @@ + + + ExceptionStackTrace__c + false + + 131072 + LongTextArea + 8 + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ExceptionType__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ExceptionType__c.field-meta.xml new file mode 100644 index 000000000..b9c80718f --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ExceptionType__c.field-meta.xml @@ -0,0 +1,10 @@ + + + ExceptionType__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpRequestBodyMasked__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpRequestBodyMasked__c.field-meta.xml new file mode 100644 index 000000000..94856d295 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpRequestBodyMasked__c.field-meta.xml @@ -0,0 +1,12 @@ + + + HttpRequestBodyMasked__c + Active + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpRequestBody__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpRequestBody__c.field-meta.xml new file mode 100644 index 000000000..50414a97a --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpRequestBody__c.field-meta.xml @@ -0,0 +1,11 @@ + + + HttpRequestBody__c + false + + 131072 + false + false + LongTextArea + 5 + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpRequestCompressed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpRequestCompressed__c.field-meta.xml new file mode 100644 index 000000000..a104eac3a --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpRequestCompressed__c.field-meta.xml @@ -0,0 +1,12 @@ + + + HttpRequestCompressed__c + Active + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpRequestEndpoint__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpRequestEndpoint__c.field-meta.xml new file mode 100644 index 000000000..f50bbbd77 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpRequestEndpoint__c.field-meta.xml @@ -0,0 +1,12 @@ + + + HttpRequestEndpoint__c + false + + 255 + false + false + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpRequestMethod__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpRequestMethod__c.field-meta.xml new file mode 100644 index 000000000..2523f3b51 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpRequestMethod__c.field-meta.xml @@ -0,0 +1,12 @@ + + + HttpRequestMethod__c + false + + 255 + false + false + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpResponseBodyMasked__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpResponseBodyMasked__c.field-meta.xml new file mode 100644 index 000000000..fd3396920 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpResponseBodyMasked__c.field-meta.xml @@ -0,0 +1,12 @@ + + + HttpResponseBodyMasked__c + Active + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpResponseBody__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpResponseBody__c.field-meta.xml new file mode 100644 index 000000000..b0f892ac1 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpResponseBody__c.field-meta.xml @@ -0,0 +1,11 @@ + + + HttpResponseBody__c + false + + 131072 + false + false + LongTextArea + 5 + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpResponseHeaderKeys__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpResponseHeaderKeys__c.field-meta.xml new file mode 100644 index 000000000..d5ca1263f --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpResponseHeaderKeys__c.field-meta.xml @@ -0,0 +1,11 @@ + + + HttpResponseHeaderKeys__c + false + + 1000 + false + false + LongTextArea + 5 + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpResponseStatusCode__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpResponseStatusCode__c.field-meta.xml new file mode 100644 index 000000000..d3f8431d7 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpResponseStatusCode__c.field-meta.xml @@ -0,0 +1,13 @@ + + + HttpResponseStatusCode__c + false + + 10 + false + 0 + false + false + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpResponseStatus__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpResponseStatus__c.field-meta.xml new file mode 100644 index 000000000..a12ff395e --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/HttpResponseStatus__c.field-meta.xml @@ -0,0 +1,12 @@ + + + HttpResponseStatus__c + false + + 255 + false + false + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/IsClosed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/IsClosed__c.field-meta.xml new file mode 100644 index 000000000..90ebebcb7 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/IsClosed__c.field-meta.xml @@ -0,0 +1,12 @@ + + + IsClosed__c + Active + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/IsResolved__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/IsResolved__c.field-meta.xml new file mode 100644 index 000000000..9d0f2903a --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/IsResolved__c.field-meta.xml @@ -0,0 +1,12 @@ + + + IsResolved__c + Active + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Issue__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Issue__c.field-meta.xml new file mode 100644 index 000000000..3638f0ea5 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Issue__c.field-meta.xml @@ -0,0 +1,12 @@ + + + Issue__c + Active + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsAggregateQueriesMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsAggregateQueriesMax__c.field-meta.xml new file mode 100644 index 000000000..1a5aa22ac --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsAggregateQueriesMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsAggregateQueriesMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsAggregateQueriesUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsAggregateQueriesUsed__c.field-meta.xml new file mode 100644 index 000000000..4d1708dbe --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsAggregateQueriesUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsAggregateQueriesUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsAggregateQueryMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsAggregateQueryMax__c.field-meta.xml new file mode 100644 index 000000000..395293700 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsAggregateQueryMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsAggregateQueryMax__c + false + + 18 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsAsyncCallsMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsAsyncCallsMax__c.field-meta.xml new file mode 100644 index 000000000..d8146ed36 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsAsyncCallsMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsAsyncCallsMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsAsyncCallsUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsAsyncCallsUsed__c.field-meta.xml new file mode 100644 index 000000000..d3deaa52b --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsAsyncCallsUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsAsyncCallsUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsCalloutsMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsCalloutsMax__c.field-meta.xml new file mode 100644 index 000000000..206538c47 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsCalloutsMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsCalloutsMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsCalloutsUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsCalloutsUsed__c.field-meta.xml new file mode 100644 index 000000000..a608f498b --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsCalloutsUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsCalloutsUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsCpuTimeMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsCpuTimeMax__c.field-meta.xml new file mode 100644 index 000000000..76f0eb2e8 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsCpuTimeMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsCpuTimeMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsCpuTimeUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsCpuTimeUsed__c.field-meta.xml new file mode 100644 index 000000000..6aca53f40 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsCpuTimeUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsCpuTimeUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsDmlRowsMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsDmlRowsMax__c.field-meta.xml new file mode 100644 index 000000000..6f048594d --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsDmlRowsMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsDmlRowsMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsDmlRowsUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsDmlRowsUsed__c.field-meta.xml new file mode 100644 index 000000000..0e7a9f58b --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsDmlRowsUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsDmlRowsUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsDmlStatementsMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsDmlStatementsMax__c.field-meta.xml new file mode 100644 index 000000000..8faebd4c7 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsDmlStatementsMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsDmlStatementsMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsDmlStatementsUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsDmlStatementsUsed__c.field-meta.xml new file mode 100644 index 000000000..c1286ddf2 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsDmlStatementsUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsDmlStatementsUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsEmailInvocationsMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsEmailInvocationsMax__c.field-meta.xml new file mode 100644 index 000000000..e1726086c --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsEmailInvocationsMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsEmailInvocationsMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsEmailInvocationsUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsEmailInvocationsUsed__c.field-meta.xml new file mode 100644 index 000000000..559264e47 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsEmailInvocationsUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsEmailInvocationsUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsFutureCallsMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsFutureCallsMax__c.field-meta.xml new file mode 100644 index 000000000..a4563ec30 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsFutureCallsMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsFutureCallsMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsFutureCallsUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsFutureCallsUsed__c.field-meta.xml new file mode 100644 index 000000000..132bf6a7a --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsFutureCallsUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsFutureCallsUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsHeapSizeMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsHeapSizeMax__c.field-meta.xml new file mode 100644 index 000000000..68f59cd51 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsHeapSizeMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsHeapSizeMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsHeapSizeUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsHeapSizeUsed__c.field-meta.xml new file mode 100644 index 000000000..3a1e4aaba --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsHeapSizeUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsHeapSizeUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsMobilePushApexCallsMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsMobilePushApexCallsMax__c.field-meta.xml new file mode 100644 index 000000000..8690db56c --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsMobilePushApexCallsMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsMobilePushApexCallsMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsMobilePushApexCallsUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsMobilePushApexCallsUsed__c.field-meta.xml new file mode 100644 index 000000000..dad758713 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsMobilePushApexCallsUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsMobilePushApexCallsUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsPublishImmediateDmlStatementsMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsPublishImmediateDmlStatementsMax__c.field-meta.xml new file mode 100644 index 000000000..ee331234c --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsPublishImmediateDmlStatementsMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsPublishImmediateDmlStatementsMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsPublishImmediateDmlStatementsUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsPublishImmediateDmlStatementsUsed__c.field-meta.xml new file mode 100644 index 000000000..62896e7ba --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsPublishImmediateDmlStatementsUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsPublishImmediateDmlStatementsUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsQueueableJobsMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsQueueableJobsMax__c.field-meta.xml new file mode 100644 index 000000000..6a88164c6 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsQueueableJobsMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsQueueableJobsMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsQueueableJobsUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsQueueableJobsUsed__c.field-meta.xml new file mode 100644 index 000000000..bdbe9d240 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsQueueableJobsUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsQueueableJobsUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueriesMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueriesMax__c.field-meta.xml new file mode 100644 index 000000000..cb1e6f3a5 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueriesMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsSoqlQueriesMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueriesUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueriesUsed__c.field-meta.xml new file mode 100644 index 000000000..49ca8daba --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueriesUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsSoqlQueriesUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueryLocatorRowsMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueryLocatorRowsMax__c.field-meta.xml new file mode 100644 index 000000000..ba3c7f87e --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueryLocatorRowsMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsSoqlQueryLocatorRowsMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueryLocatorRowsUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueryLocatorRowsUsed__c.field-meta.xml new file mode 100644 index 000000000..f714b5a4b --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueryLocatorRowsUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsSoqlQueryLocatorRowsUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueryRowsMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueryRowsMax__c.field-meta.xml new file mode 100644 index 000000000..ca9fb4a68 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueryRowsMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsSoqlQueryRowsMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueryRowsUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueryRowsUsed__c.field-meta.xml new file mode 100644 index 000000000..d787f60ba --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoqlQueryRowsUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsSoqlQueryRowsUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoslSearchesMax__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoslSearchesMax__c.field-meta.xml new file mode 100644 index 000000000..3be43682e --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoslSearchesMax__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsSoslSearchesMax__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoslSearchesUsed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoslSearchesUsed__c.field-meta.xml new file mode 100644 index 000000000..ef0b5b77d --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LimitsSoslSearchesUsed__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LimitsSoslSearchesUsed__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Locale__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Locale__c.field-meta.xml new file mode 100644 index 000000000..cc19b34b3 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Locale__c.field-meta.xml @@ -0,0 +1,10 @@ + + + Locale__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LogEntryName__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LogEntryName__c.field-meta.xml new file mode 100644 index 000000000..3906f4524 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LogEntryName__c.field-meta.xml @@ -0,0 +1,10 @@ + + + LogEntryName__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LogName__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LogName__c.field-meta.xml new file mode 100644 index 000000000..2b95ce579 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LogName__c.field-meta.xml @@ -0,0 +1,10 @@ + + + LogName__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LogPurgeAction__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LogPurgeAction__c.field-meta.xml new file mode 100644 index 000000000..c13fea9c8 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LogPurgeAction__c.field-meta.xml @@ -0,0 +1,12 @@ + + + LogPurgeAction__c + Active + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LogRetentionDate__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LogRetentionDate__c.field-meta.xml new file mode 100644 index 000000000..60f2877fa --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LogRetentionDate__c.field-meta.xml @@ -0,0 +1,13 @@ + + + LogRetentionDate__c + Active + The date that this log can be automatically deleted by the batch job LogBatchPurger. + +It defaults to 2 weeks after creation (configurable in Logger Settings), but the date can be set manually or via automation if certain logs need to be kept longer/indefinitely. + false + + false + Confidential + DateTime + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoggedById__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoggedById__c.field-meta.xml new file mode 100644 index 000000000..ff7bcee95 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoggedById__c.field-meta.xml @@ -0,0 +1,10 @@ + + + LoggedById__c + false + + 18 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoggedByUsername__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoggedByUsername__c.field-meta.xml new file mode 100644 index 000000000..3e15933a0 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoggedByUsername__c.field-meta.xml @@ -0,0 +1,10 @@ + + + LoggedByUsername__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoggerVersionNumber__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoggerVersionNumber__c.field-meta.xml new file mode 100644 index 000000000..489c64afe --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoggerVersionNumber__c.field-meta.xml @@ -0,0 +1,10 @@ + + + LoggerVersionNumber__c + false + + 14 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoggingLevelOrdinal__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoggingLevelOrdinal__c.field-meta.xml new file mode 100644 index 000000000..2d1c17756 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoggingLevelOrdinal__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LoggingLevelOrdinal__c + false + + 10 + true + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoggingLevel__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoggingLevel__c.field-meta.xml new file mode 100644 index 000000000..873c4debc --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoggingLevel__c.field-meta.xml @@ -0,0 +1,10 @@ + + + LoggingLevel__c + false + + 10 + true + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginApplication__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginApplication__c.field-meta.xml new file mode 100644 index 000000000..f245f5a00 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginApplication__c.field-meta.xml @@ -0,0 +1,10 @@ + + + LoginApplication__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginBrowser__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginBrowser__c.field-meta.xml new file mode 100644 index 000000000..90377e9f8 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginBrowser__c.field-meta.xml @@ -0,0 +1,10 @@ + + + LoginBrowser__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginDomain__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginDomain__c.field-meta.xml new file mode 100644 index 000000000..18e98770f --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginDomain__c.field-meta.xml @@ -0,0 +1,11 @@ + + + LoginDomain__c + DeprecateCandidate + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginHistoryId__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginHistoryId__c.field-meta.xml new file mode 100644 index 000000000..32682f462 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginHistoryId__c.field-meta.xml @@ -0,0 +1,10 @@ + + + LoginHistoryId__c + false + + 18 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginPlatform__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginPlatform__c.field-meta.xml new file mode 100644 index 000000000..d4f74610b --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginPlatform__c.field-meta.xml @@ -0,0 +1,10 @@ + + + LoginPlatform__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginType__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginType__c.field-meta.xml new file mode 100644 index 000000000..e403396d0 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LoginType__c.field-meta.xml @@ -0,0 +1,10 @@ + + + LoginType__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LogoutUrl__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LogoutUrl__c.field-meta.xml new file mode 100644 index 000000000..405dd0709 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/LogoutUrl__c.field-meta.xml @@ -0,0 +1,10 @@ + + + LogoutUrl__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/MessageMasked__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/MessageMasked__c.field-meta.xml new file mode 100644 index 000000000..7d0932a18 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/MessageMasked__c.field-meta.xml @@ -0,0 +1,12 @@ + + + MessageMasked__c + Active + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/MessageTruncated__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/MessageTruncated__c.field-meta.xml new file mode 100644 index 000000000..c75dd21aa --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/MessageTruncated__c.field-meta.xml @@ -0,0 +1,12 @@ + + + MessageTruncated__c + Active + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Message__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Message__c.field-meta.xml new file mode 100644 index 000000000..8a9dee90b --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Message__c.field-meta.xml @@ -0,0 +1,9 @@ + + + Message__c + false + + 131072 + LongTextArea + 8 + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkId__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkId__c.field-meta.xml new file mode 100644 index 000000000..958540dab --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkId__c.field-meta.xml @@ -0,0 +1,10 @@ + + + NetworkId__c + false + + 18 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkLoginUrl__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkLoginUrl__c.field-meta.xml new file mode 100644 index 000000000..0cefd5afb --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkLoginUrl__c.field-meta.xml @@ -0,0 +1,10 @@ + + + NetworkLoginUrl__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkLogoutUrl__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkLogoutUrl__c.field-meta.xml new file mode 100644 index 000000000..696e41da0 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkLogoutUrl__c.field-meta.xml @@ -0,0 +1,10 @@ + + + NetworkLogoutUrl__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkName__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkName__c.field-meta.xml new file mode 100644 index 000000000..026c6052e --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkName__c.field-meta.xml @@ -0,0 +1,11 @@ + + + NetworkName__c + The name of the user's Community site (based on NetworkId). + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkSelfRegistrationUrl__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkSelfRegistrationUrl__c.field-meta.xml new file mode 100644 index 000000000..dc6ebd30e --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkSelfRegistrationUrl__c.field-meta.xml @@ -0,0 +1,10 @@ + + + NetworkSelfRegistrationUrl__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkUrlPathPrefix__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkUrlPathPrefix__c.field-meta.xml new file mode 100644 index 000000000..1c2aa374e --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/NetworkUrlPathPrefix__c.field-meta.xml @@ -0,0 +1,12 @@ + + + NetworkUrlPathPrefix__c + The UrlPathPrefix is a unique string at the end of the URL for this community. For example, in the community URL CommunitiesSubdomainName.force.com/customers, customers is the UrlPathPrefix. + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationDomainUrl__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationDomainUrl__c.field-meta.xml new file mode 100644 index 000000000..35f55c010 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationDomainUrl__c.field-meta.xml @@ -0,0 +1,11 @@ + + + OrganizationDomainUrl__c + The value returned from Url..getOrgDomainUrl() + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationEnvironmentType__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationEnvironmentType__c.field-meta.xml new file mode 100644 index 000000000..119b07710 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationEnvironmentType__c.field-meta.xml @@ -0,0 +1,10 @@ + + + OrganizationEnvironmentType__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationId__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationId__c.field-meta.xml new file mode 100644 index 000000000..edf569108 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationId__c.field-meta.xml @@ -0,0 +1,10 @@ + + + OrganizationId__c + false + + 18 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationInstanceName__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationInstanceName__c.field-meta.xml new file mode 100644 index 000000000..8742bbd70 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationInstanceName__c.field-meta.xml @@ -0,0 +1,10 @@ + + + OrganizationInstanceName__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationInstanceReleaseCycle__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationInstanceReleaseCycle__c.field-meta.xml new file mode 100644 index 000000000..ae9380599 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationInstanceReleaseCycle__c.field-meta.xml @@ -0,0 +1,12 @@ + + + OrganizationInstanceReleaseCycle__c + DeprecateCandidate + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationName__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationName__c.field-meta.xml new file mode 100644 index 000000000..dc5ee2401 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationName__c.field-meta.xml @@ -0,0 +1,10 @@ + + + OrganizationName__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationNamespacePrefix__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationNamespacePrefix__c.field-meta.xml new file mode 100644 index 000000000..9b3d26997 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationNamespacePrefix__c.field-meta.xml @@ -0,0 +1,10 @@ + + + OrganizationNamespacePrefix__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationType__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationType__c.field-meta.xml new file mode 100644 index 000000000..3ec26cfd7 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OrganizationType__c.field-meta.xml @@ -0,0 +1,10 @@ + + + OrganizationType__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OriginLocation__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OriginLocation__c.field-meta.xml new file mode 100644 index 000000000..eab85c939 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OriginLocation__c.field-meta.xml @@ -0,0 +1,10 @@ + + + OriginLocation__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OriginType__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OriginType__c.field-meta.xml new file mode 100644 index 000000000..9577a3cbe --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/OriginType__c.field-meta.xml @@ -0,0 +1,10 @@ + + + OriginType__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ParentLogTransactionId__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ParentLogTransactionId__c.field-meta.xml new file mode 100644 index 000000000..bbeb28415 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ParentLogTransactionId__c.field-meta.xml @@ -0,0 +1,10 @@ + + + ParentLogTransactionId__c + false + + 36 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Priority__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Priority__c.field-meta.xml new file mode 100644 index 000000000..ec6f948a2 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Priority__c.field-meta.xml @@ -0,0 +1,12 @@ + + + Priority__c + Active + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ProfileId__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ProfileId__c.field-meta.xml new file mode 100644 index 000000000..1eeb511fe --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ProfileId__c.field-meta.xml @@ -0,0 +1,10 @@ + + + ProfileId__c + false + + 18 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ProfileName__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ProfileName__c.field-meta.xml new file mode 100644 index 000000000..e69ef87e7 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ProfileName__c.field-meta.xml @@ -0,0 +1,10 @@ + + + ProfileName__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordCollectionSize__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordCollectionSize__c.field-meta.xml new file mode 100644 index 000000000..127d1c711 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordCollectionSize__c.field-meta.xml @@ -0,0 +1,13 @@ + + + RecordCollectionSize__c + The number of items contained in the collection of database results + false + The number of items contained in the collection of database results + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordCollectionType__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordCollectionType__c.field-meta.xml new file mode 100644 index 000000000..487f3cd80 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordCollectionType__c.field-meta.xml @@ -0,0 +1,10 @@ + + + RecordCollectionType__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordId__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordId__c.field-meta.xml new file mode 100644 index 000000000..9f2403a04 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordId__c.field-meta.xml @@ -0,0 +1,12 @@ + + + RecordId__c + The ID of the record associated with a particular log entry. This is used for addRecordDebugEntry & addRecordExceptionEntry methods + false + + 18 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordJsonMasked__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordJsonMasked__c.field-meta.xml new file mode 100644 index 000000000..28c37cf52 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordJsonMasked__c.field-meta.xml @@ -0,0 +1,12 @@ + + + RecordJsonMasked__c + Active + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordJson__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordJson__c.field-meta.xml new file mode 100644 index 000000000..4b4eaf367 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordJson__c.field-meta.xml @@ -0,0 +1,9 @@ + + + RecordJson__c + false + + 131072 + LongTextArea + 8 + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordName__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordName__c.field-meta.xml new file mode 100644 index 000000000..224a54acc --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordName__c.field-meta.xml @@ -0,0 +1,12 @@ + + + RecordName__c + false + + 255 + false + false + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordSObjectClassification__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordSObjectClassification__c.field-meta.xml new file mode 100644 index 000000000..da3bf3ed4 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordSObjectClassification__c.field-meta.xml @@ -0,0 +1,10 @@ + + + RecordSObjectClassification__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordSObjectTypeNamespace__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordSObjectTypeNamespace__c.field-meta.xml new file mode 100644 index 000000000..e151071b5 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordSObjectTypeNamespace__c.field-meta.xml @@ -0,0 +1,10 @@ + + + RecordSObjectTypeNamespace__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordSObjectType__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordSObjectType__c.field-meta.xml new file mode 100644 index 000000000..3a13a7454 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/RecordSObjectType__c.field-meta.xml @@ -0,0 +1,10 @@ + + + RecordSObjectType__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Scenario__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Scenario__c.field-meta.xml new file mode 100644 index 000000000..828189a30 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Scenario__c.field-meta.xml @@ -0,0 +1,10 @@ + + + Scenario__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/SessionId__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/SessionId__c.field-meta.xml new file mode 100644 index 000000000..50230878b --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/SessionId__c.field-meta.xml @@ -0,0 +1,10 @@ + + + SessionId__c + false + + 120 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/SessionSecurityLevel__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/SessionSecurityLevel__c.field-meta.xml new file mode 100644 index 000000000..9eb785c97 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/SessionSecurityLevel__c.field-meta.xml @@ -0,0 +1,10 @@ + + + SessionSecurityLevel__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/SessionType__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/SessionType__c.field-meta.xml new file mode 100644 index 000000000..eb26425b5 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/SessionType__c.field-meta.xml @@ -0,0 +1,10 @@ + + + SessionType__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/SourceIp__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/SourceIp__c.field-meta.xml new file mode 100644 index 000000000..6c78057dd --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/SourceIp__c.field-meta.xml @@ -0,0 +1,10 @@ + + + SourceIp__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/StackTrace__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/StackTrace__c.field-meta.xml new file mode 100644 index 000000000..23390dbba --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/StackTrace__c.field-meta.xml @@ -0,0 +1,9 @@ + + + StackTrace__c + false + + 131072 + LongTextArea + 8 + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Status__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Status__c.field-meta.xml new file mode 100644 index 000000000..34d4c4f63 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Status__c.field-meta.xml @@ -0,0 +1,12 @@ + + + Status__c + Active + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/SystemMode__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/SystemMode__c.field-meta.xml new file mode 100644 index 000000000..fd2d2f399 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/SystemMode__c.field-meta.xml @@ -0,0 +1,10 @@ + + + SystemMode__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Tags__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Tags__c.field-meta.xml new file mode 100644 index 000000000..d8fa36708 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Tags__c.field-meta.xml @@ -0,0 +1,9 @@ + + + Tags__c + false + + 131072 + LongTextArea + 8 + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ThemeDisplayed__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ThemeDisplayed__c.field-meta.xml new file mode 100644 index 000000000..495f0517b --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/ThemeDisplayed__c.field-meta.xml @@ -0,0 +1,10 @@ + + + ThemeDisplayed__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TimeZoneId__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TimeZoneId__c.field-meta.xml new file mode 100644 index 000000000..75d3c06f8 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TimeZoneId__c.field-meta.xml @@ -0,0 +1,10 @@ + + + TimeZoneId__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TimeZoneName__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TimeZoneName__c.field-meta.xml new file mode 100644 index 000000000..93aa4401e --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TimeZoneName__c.field-meta.xml @@ -0,0 +1,10 @@ + + + TimeZoneName__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TimestampString__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TimestampString__c.field-meta.xml new file mode 100644 index 000000000..43313af95 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TimestampString__c.field-meta.xml @@ -0,0 +1,12 @@ + + + TimestampString__c + This field is used to circumvent a platform limitation - platform event datetimes are not accurately transferred to Apex triggers. This field stores a string version of the timestamp, which is then converted back to a datetime in Apex triggers. + false + + 40 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Timestamp__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Timestamp__c.field-meta.xml new file mode 100644 index 000000000..7832d4511 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/Timestamp__c.field-meta.xml @@ -0,0 +1,8 @@ + + + Timestamp__c + false + + true + DateTime + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TransactionEntryNumber__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TransactionEntryNumber__c.field-meta.xml new file mode 100644 index 000000000..840fd561d --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TransactionEntryNumber__c.field-meta.xml @@ -0,0 +1,12 @@ + + + TransactionEntryNumber__c + The sequential number of this log entry within the transaction + false + + 10 + true + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TransactionId__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TransactionId__c.field-meta.xml new file mode 100644 index 000000000..ba8b343d6 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TransactionId__c.field-meta.xml @@ -0,0 +1,10 @@ + + + TransactionId__c + false + + 36 + true + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TriggerIsExecuting__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TriggerIsExecuting__c.field-meta.xml new file mode 100644 index 000000000..5d645fd36 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TriggerIsExecuting__c.field-meta.xml @@ -0,0 +1,12 @@ + + + TriggerIsExecuting__c + Active + false + + 255 + false + Confidential + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TriggerOperationType__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TriggerOperationType__c.field-meta.xml new file mode 100644 index 000000000..d272d60d1 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TriggerOperationType__c.field-meta.xml @@ -0,0 +1,10 @@ + + + TriggerOperationType__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TriggerSObjectType__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TriggerSObjectType__c.field-meta.xml new file mode 100644 index 000000000..a4afe50cb --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/TriggerSObjectType__c.field-meta.xml @@ -0,0 +1,10 @@ + + + TriggerSObjectType__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserLicenseDefinitionKey__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserLicenseDefinitionKey__c.field-meta.xml new file mode 100644 index 000000000..7617b03e9 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserLicenseDefinitionKey__c.field-meta.xml @@ -0,0 +1,11 @@ + + + UserLicenseDefinitionKey__c + https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_userlicense.htm + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserLicenseId__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserLicenseId__c.field-meta.xml new file mode 100644 index 000000000..30f7a3593 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserLicenseId__c.field-meta.xml @@ -0,0 +1,10 @@ + + + UserLicenseId__c + false + + 18 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserLicenseName__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserLicenseName__c.field-meta.xml new file mode 100644 index 000000000..db1956cb3 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserLicenseName__c.field-meta.xml @@ -0,0 +1,10 @@ + + + UserLicenseName__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserLoggingLevelOrdinal__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserLoggingLevelOrdinal__c.field-meta.xml new file mode 100644 index 000000000..6fc350112 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserLoggingLevelOrdinal__c.field-meta.xml @@ -0,0 +1,11 @@ + + + UserLoggingLevelOrdinal__c + false + + 10 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserLoggingLevel__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserLoggingLevel__c.field-meta.xml new file mode 100644 index 000000000..66e885964 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserLoggingLevel__c.field-meta.xml @@ -0,0 +1,10 @@ + + + UserLoggingLevel__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserRoleId__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserRoleId__c.field-meta.xml new file mode 100644 index 000000000..137a32882 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserRoleId__c.field-meta.xml @@ -0,0 +1,10 @@ + + + UserRoleId__c + false + + 18 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserRoleName__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserRoleName__c.field-meta.xml new file mode 100644 index 000000000..913b5976e --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserRoleName__c.field-meta.xml @@ -0,0 +1,10 @@ + + + UserRoleName__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserType__c.field-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserType__c.field-meta.xml new file mode 100644 index 000000000..5b53cf39c --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/fields/UserType__c.field-meta.xml @@ -0,0 +1,10 @@ + + + UserType__c + false + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/indexes/LogEntryArchiveIndex.indexe-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/indexes/LogEntryArchiveIndex.indexe-meta.xml new file mode 100644 index 000000000..b8c0ff879 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/objects/LogEntryArchive__b/indexes/LogEntryArchiveIndex.indexe-meta.xml @@ -0,0 +1,17 @@ + + + LogEntryArchiveIndex + + Timestamp__c + DESC + + + TransactionId__c + ASC + + + TransactionEntryNumber__c + DESC + + + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/permissionsets/LoggerLogEntryArchiveAdmin.permissionset-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/permissionsets/LoggerLogEntryArchiveAdmin.permissionset-meta.xml new file mode 100644 index 000000000..1cc2bb531 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/permissionsets/LoggerLogEntryArchiveAdmin.permissionset-meta.xml @@ -0,0 +1,674 @@ + + + Provides admin access to the BigObject LogEntryEventArchive__b, included with the BigObject plugin for Nebula Logger + + true + LogEntryArchive__b.ApiReleaseNumber__c + true + + + true + LogEntryArchive__b.ApiReleaseVersion__c + true + + + true + LogEntryArchive__b.ApiVersion__c + true + + + true + LogEntryArchive__b.ClosedById__c + true + + + true + LogEntryArchive__b.ClosedByUsername__c + true + + + true + LogEntryArchive__b.ClosedDate__c + true + + + true + LogEntryArchive__b.Comments__c + true + + + true + LogEntryArchive__b.ComponentType__c + true + + + true + LogEntryArchive__b.DatabaseResultCollectionSize__c + true + + + true + LogEntryArchive__b.DatabaseResultCollectionType__c + true + + + true + LogEntryArchive__b.DatabaseResultJson__c + true + + + true + LogEntryArchive__b.DatabaseResultType__c + true + + + true + LogEntryArchive__b.EpochTimestamp__c + true + + + true + LogEntryArchive__b.ExceptionMessage__c + true + + + true + LogEntryArchive__b.ExceptionStackTrace__c + true + + + true + LogEntryArchive__b.ExceptionType__c + true + + + false + LogEntryArchive__b.HttpRequestBody__c + true + + + false + LogEntryArchive__b.HttpRequestBodyMasked__c + true + + + false + LogEntryArchive__b.HttpRequestEndpoint__c + true + + + false + LogEntryArchive__b.HttpRequestMethod__c + true + + + false + LogEntryArchive__b.HttpResponseBody__c + true + + + false + LogEntryArchive__b.HttpResponseBodyMasked__c + true + + + false + LogEntryArchive__b.HttpResponseHeaderKeys__c + true + + + false + LogEntryArchive__b.HttpResponseStatusCode__c + true + + + false + LogEntryArchive__b.HttpResponseStatus__c + true + + + true + LogEntryArchive__b.IsClosed__c + true + + + true + LogEntryArchive__b.IsResolved__c + true + + + true + LogEntryArchive__b.Issue__c + true + + + true + LogEntryArchive__b.LimitsAggregateQueriesMax__c + true + + + true + LogEntryArchive__b.LimitsAggregateQueriesUsed__c + true + + + true + LogEntryArchive__b.LimitsAggregateQueryMax__c + true + + + true + LogEntryArchive__b.LimitsAsyncCallsMax__c + true + + + true + LogEntryArchive__b.LimitsAsyncCallsUsed__c + true + + + true + LogEntryArchive__b.LimitsCalloutsMax__c + true + + + true + LogEntryArchive__b.LimitsCalloutsUsed__c + true + + + true + LogEntryArchive__b.LimitsCpuTimeMax__c + true + + + true + LogEntryArchive__b.LimitsCpuTimeUsed__c + true + + + true + LogEntryArchive__b.LimitsDmlRowsMax__c + true + + + true + LogEntryArchive__b.LimitsDmlRowsUsed__c + true + + + true + LogEntryArchive__b.LimitsDmlStatementsMax__c + true + + + true + LogEntryArchive__b.LimitsDmlStatementsUsed__c + true + + + true + LogEntryArchive__b.LimitsEmailInvocationsMax__c + true + + + true + LogEntryArchive__b.LimitsEmailInvocationsUsed__c + true + + + true + LogEntryArchive__b.LimitsFutureCallsMax__c + true + + + true + LogEntryArchive__b.LimitsFutureCallsUsed__c + true + + + true + LogEntryArchive__b.LimitsHeapSizeMax__c + true + + + true + LogEntryArchive__b.LimitsHeapSizeUsed__c + true + + + true + LogEntryArchive__b.LimitsMobilePushApexCallsMax__c + true + + + true + LogEntryArchive__b.LimitsMobilePushApexCallsUsed__c + true + + + true + LogEntryArchive__b.LimitsPublishImmediateDmlStatementsMax__c + true + + + true + LogEntryArchive__b.LimitsPublishImmediateDmlStatementsUsed__c + true + + + true + LogEntryArchive__b.LimitsQueueableJobsMax__c + true + + + true + LogEntryArchive__b.LimitsQueueableJobsUsed__c + true + + + true + LogEntryArchive__b.LimitsSoqlQueriesMax__c + true + + + true + LogEntryArchive__b.LimitsSoqlQueriesUsed__c + true + + + true + LogEntryArchive__b.LimitsSoqlQueryLocatorRowsMax__c + true + + + true + LogEntryArchive__b.LimitsSoqlQueryLocatorRowsUsed__c + true + + + true + LogEntryArchive__b.LimitsSoqlQueryRowsMax__c + true + + + true + LogEntryArchive__b.LimitsSoqlQueryRowsUsed__c + true + + + true + LogEntryArchive__b.LimitsSoslSearchesMax__c + true + + + true + LogEntryArchive__b.LimitsSoslSearchesUsed__c + true + + + true + LogEntryArchive__b.Locale__c + true + + + true + LogEntryArchive__b.LogEntryName__c + true + + + true + LogEntryArchive__b.LogName__c + true + + + true + LogEntryArchive__b.LogPurgeAction__c + true + + + true + LogEntryArchive__b.LogRetentionDate__c + true + + + true + LogEntryArchive__b.LoggedById__c + true + + + true + LogEntryArchive__b.LoggedByUsername__c + true + + + true + LogEntryArchive__b.LoggerVersionNumber__c + true + + + true + LogEntryArchive__b.LoginApplication__c + true + + + true + LogEntryArchive__b.LoginBrowser__c + true + + + true + LogEntryArchive__b.LoginDomain__c + true + + + true + LogEntryArchive__b.LoginHistoryId__c + true + + + true + LogEntryArchive__b.LoginPlatform__c + true + + + true + LogEntryArchive__b.LoginType__c + true + + + true + LogEntryArchive__b.LogoutUrl__c + true + + + true + LogEntryArchive__b.MessageMasked__c + true + + + true + LogEntryArchive__b.MessageTruncated__c + true + + + true + LogEntryArchive__b.Message__c + true + + + true + LogEntryArchive__b.NetworkId__c + true + + + true + LogEntryArchive__b.NetworkLoginUrl__c + true + + + true + LogEntryArchive__b.NetworkLogoutUrl__c + true + + + true + LogEntryArchive__b.NetworkName__c + true + + + true + LogEntryArchive__b.NetworkSelfRegistrationUrl__c + true + + + true + LogEntryArchive__b.NetworkUrlPathPrefix__c + true + + + true + LogEntryArchive__b.OrganizationDomainUrl__c + true + + + true + LogEntryArchive__b.OrganizationEnvironmentType__c + true + + + true + LogEntryArchive__b.OrganizationId__c + true + + + true + LogEntryArchive__b.OrganizationInstanceName__c + true + + + true + LogEntryArchive__b.OrganizationInstanceReleaseCycle__c + true + + + true + LogEntryArchive__b.OrganizationName__c + true + + + true + LogEntryArchive__b.OrganizationNamespacePrefix__c + true + + + true + LogEntryArchive__b.OrganizationType__c + true + + + true + LogEntryArchive__b.OriginLocation__c + true + + + true + LogEntryArchive__b.OriginType__c + true + + + true + LogEntryArchive__b.ParentLogTransactionId__c + true + + + true + LogEntryArchive__b.Priority__c + true + + + true + LogEntryArchive__b.ProfileId__c + true + + + true + LogEntryArchive__b.ProfileName__c + true + + + true + LogEntryArchive__b.RecordCollectionSize__c + true + + + true + LogEntryArchive__b.RecordCollectionType__c + true + + + true + LogEntryArchive__b.RecordId__c + true + + + true + LogEntryArchive__b.RecordJsonMasked__c + true + + + true + LogEntryArchive__b.RecordJson__c + true + + + true + LogEntryArchive__b.RecordSObjectClassification__c + true + + + true + LogEntryArchive__b.RecordSObjectTypeNamespace__c + true + + + true + LogEntryArchive__b.RecordSObjectType__c + true + + + true + LogEntryArchive__b.Scenario__c + true + + + true + LogEntryArchive__b.SessionId__c + true + + + true + LogEntryArchive__b.SessionSecurityLevel__c + true + + + true + LogEntryArchive__b.SessionType__c + true + + + true + LogEntryArchive__b.SourceIp__c + true + + + true + LogEntryArchive__b.StackTrace__c + true + + + true + LogEntryArchive__b.Status__c + true + + + true + LogEntryArchive__b.SystemMode__c + true + + + true + LogEntryArchive__b.Tags__c + true + + + true + LogEntryArchive__b.ThemeDisplayed__c + true + + + true + LogEntryArchive__b.TimeZoneId__c + true + + + true + LogEntryArchive__b.TimeZoneName__c + true + + + true + LogEntryArchive__b.TimestampString__c + true + + + true + LogEntryArchive__b.TriggerIsExecuting__c + true + + + true + LogEntryArchive__b.TriggerOperationType__c + true + + + true + LogEntryArchive__b.TriggerSObjectType__c + true + + + true + LogEntryArchive__b.UserLicenseDefinitionKey__c + true + + + true + LogEntryArchive__b.UserLicenseId__c + true + + + true + LogEntryArchive__b.UserLicenseName__c + true + + + true + LogEntryArchive__b.UserLoggingLevelOrdinal__c + true + + + true + LogEntryArchive__b.UserLoggingLevel__c + true + + + true + LogEntryArchive__b.UserRoleId__c + true + + + true + LogEntryArchive__b.UserRoleName__c + true + + + true + LogEntryArchive__b.UserType__c + true + + false + + + true + true + false + true + false + LogEntryArchive__b + false + + + LogEntryArchives + Visible + + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/tabs/LogEntryArchives.tab-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/tabs/LogEntryArchives.tab-meta.xml new file mode 100644 index 000000000..713f40dd2 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/tabs/LogEntryArchives.tab-meta.xml @@ -0,0 +1,6 @@ + + + + logEntryArchives + Custom13: Box + diff --git a/nebula-logger/plugins/big-object-archiving/plugin/testSuites/LoggerLogEntryArchivePlugin.testSuite-meta.xml b/nebula-logger/plugins/big-object-archiving/plugin/testSuites/LoggerLogEntryArchivePlugin.testSuite-meta.xml new file mode 100644 index 000000000..c1f33ed36 --- /dev/null +++ b/nebula-logger/plugins/big-object-archiving/plugin/testSuites/LoggerLogEntryArchivePlugin.testSuite-meta.xml @@ -0,0 +1,6 @@ + + + LogEntryArchiveBuilder_Tests + LogEntryArchiveController_Tests + LogEntryArchivePlugin_Tests + diff --git a/nebula-logger/plugins/log-retention-rules/.images/example-log-retention-rule-with-conditions.png b/nebula-logger/plugins/log-retention-rules/.images/example-log-retention-rule-with-conditions.png new file mode 100644 index 000000000..112a4e100 Binary files /dev/null and b/nebula-logger/plugins/log-retention-rules/.images/example-log-retention-rule-with-conditions.png differ diff --git a/nebula-logger/plugins/log-retention-rules/.images/example-log-retention-rules-list-view.png b/nebula-logger/plugins/log-retention-rules/.images/example-log-retention-rules-list-view.png new file mode 100644 index 000000000..78835b50c Binary files /dev/null and b/nebula-logger/plugins/log-retention-rules/.images/example-log-retention-rules-list-view.png differ diff --git a/nebula-logger/plugins/log-retention-rules/README.md b/nebula-logger/plugins/log-retention-rules/README.md new file mode 100644 index 000000000..a7d0c0817 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/README.md @@ -0,0 +1,42 @@ +# Log Retention Rules plugin for Nebula Logger + +> :information_source: This plugin requires `v4.7.1` or newer of Nebula Logger's unlocked package + +[![Install Unlocked Package Plugin](../.images/btn-install-unlocked-package-plugin-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015lgGQAQ) + +Adds the ability to create & deploy advanced, configurable rules for setting the retention date of `Log__c` records, using custom metadata types `LogRetentionRule__mdt` and `LogRetentionRuleCondition__mdt`. + +--- + +## What's Included + +This plugin includes some add-on metadata for Nebula Logger to support the Slack integration + +1. Plugin configuration details stored in Logger's CMDT objects `LoggerPlugin__mdt.LogRetentionRules` +2. New custom metadata types + - `LogRetentionRule__mdt` - Used to configure rules that set the value of `Log__c`.`LogRetentionDate__c`. Each rules consists of 1 or more conditions, stored in `LogRetentionRuleCondition__mdt`. + - `LogRetentionRuleCondition__mdt` - Used to configure field-level conditions for retention rules - each condition checks a `LogEntry__c` or `Log__c` field for a specific value, regular expression (regex), or field comparisons. +3. Apex class `LogRetentionRulesPlugin` (and corresponding tests in `LogRetentionRulesPlugin_Tests`). The plugin class reads the configured rules & conditions and automatically sets the field `Log__c.LogRetentionDate__c` when new `Log__c` records are inserted. + +--- + +## Installation Steps + +After installing the Nebula Logger's unlocked package, you can then install the Log Retention Rules plugin unlocked package in a sandbox. + +This plugin is currently in beta and cannot be installed in production - however, if you want to use it in your production org, you can deploy the metadata to your org using your preferred deployment tool (changes sets, sfdx, the metadata API, etc.). + +### Quick Start: Adding Log Retention Rules and Conditions + +After installing the plugin, you can add rules using the custom metadata types `LogRetentionRule__mdt` and `LogRetentionRuleCondition__mdt`. Multiple rules can be configured in your orgs, as shown below: + +![Log Retention Rules plugin: Example Rule](./content/example-log-retention-rules-list-view.png) + +In this example rule, for every inserted `LogEntry__c` record, 2 conditions are checked: + +1. Does the entry's parent `Log__c` record have 1 or more error? (based on the roll-up summary field `Log__c.TotalERRORLogEntries__c`) +2. Does the entry's parent `Log__c` record have the scenario 'feature B'? (based on the text field `Log__c.Scenario__c`) + +If any `LogEntry__c` record is inserted that meets these 2 conditions, then the parent `Log__c` record will have the field `LogRetentionDate__c` set to `System.today() + 30`. + +![Log Retention Rules plugin: Example Rule](./content/example-log-retention-rule-with-conditions.png) diff --git a/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionFilter.cls b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionFilter.cls new file mode 100644 index 000000000..5e52ba96a --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionFilter.cls @@ -0,0 +1,469 @@ +//-----------------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// The core functionality of this plugin's code originated in https://github.com/jongpie/ApexValidationRules // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//-----------------------------------------------------------------------------------------------------------// + +/** + * @group Plugins + * @description Evaluates an `SObject` record to see if it matches the condition(s) defined in `LogRetentionRule__mdt` and its related + * list of related `LogRetentionRuleCondition__mdt` records. The result is then used in `LogRententionRulesPlugin` to override + * the value of `Log__c.LogRetentionDate__c` for any records that match the filters. + * @see LogRententionRulesPlugin + */ +public without sharing class LogRetentionFilter { + private final SObject record; + private final LogRetentionRule__mdt rule; + private final List ruleFilterConditions; + + /** + * @description Creates a new instance of `LogRetentionFilter`, used to determine if an `SObject` record + * meets the criteria of the provided rule & filter conditions + * @param record The `SObject` record to compare + * @param rule The filter rule to apply to the `SObject` record, stored as an instance of `LogRetentionRule__mdt` + * @param ruleFilterConditions The list of `LogRetentionRuleCondition__mdt` for the rule that should be applied to the `SObject` record + */ + public LogRetentionFilter(SObject record, LogRetentionRule__mdt rule, List ruleFilterConditions) { + this.record = record; + this.rule = rule; + this.ruleFilterConditions = ruleFilterConditions; + } + + /** + * @description Returns an instance of `FilterResult` that provides information regarding + * if the `SObject` record matches the provided rule & filter conditions + * @return The new instance of `FilterResult` + */ + public FilterResult getFilterResult() { + return new FilterResult(this.record, this.rule, this.ruleFilterConditions); + } + + /** + * @description Inner class used to handle determining if the provided `SObject` record meets + * the criteria for the provided `LogRetentionRule__mdt` rule and associated `List` ruleFilterConditions + */ + public class FilterResult { + private List conditions; + private String conditionsLogic; + private String conditionsLogicType; + private Boolean matchesFilter; + private SObject record; + private LogRetentionRule__mdt rule; + private List ruleFilterConditions; + + private FilterResult(SObject record, LogRetentionRule__mdt rule, List ruleFilterConditions) { + this.record = record; + this.rule = rule; + this.ruleFilterConditions = ruleFilterConditions; + this.conditions = new List(); + this.conditionsLogic = this.getRuleFilterConditionsLogic(); + this.conditionsLogicType = rule.ConditionLogicType__c; + + this.process(); + } + + /** + * @description Returns the `LogRetentionRule__mdt` rule that was used to create the instance of `FilterResult` + * @return The instance of `LogRetentionRule__mdt` + */ + public LogRetentionRule__mdt getRule() { + return this.rule; + } + + /** + * @description Returns the `SObject` record that was used to create the instance of `FilterResult` + * @return The instance of `SObject` + */ + public SObject getRecord() { + return this.record; + } + + /** + * @description Indicates if the provided `SObject` record matches all of the criteria defined in + * the `LogRetentionRule__mdt` rule and associated `List` ruleFilterConditions + * @return The `Boolean` value that indicates if the `SObject` record matches the provided rule & conditions (`true`) + * or if the record does not match the rule & conditions (`false`) + */ + public Boolean matchesFilter() { + return this.matchesFilter; + } + + private void process() { + List booleanValues = new List(); + for (LogRetentionRuleCondition__mdt filterCondition : this.ruleFilterConditions) { + FilterConditionResult filterConditionResult = new FilterConditionResult(this.record, filterCondition); + this.conditions.add(filterConditionResult.getCondition()); + booleanValues.add(String.valueOf(filterConditionResult.matchesFilter)); + } + + String parsedConditionsLogic = String.format(this.getRuleFilterConditionsLogic(), booleanValues); + + this.matchesFilter = new BooleanExpression().evaluate(parsedConditionsLogic); + } + + @SuppressWarnings('PMD.CyclomaticComplexity') + private String getRuleFilterConditionsLogic() { + String conditionsLogic = String.isBlank(this.rule.CustomConditionLogic__c) ? '' : this.rule.CustomConditionLogic__c; + + if (this.rule.ConditionLogicType__c != 'Custom') { + List standardLogicPieces = new List(); + for (Integer i = 0; i < this.ruleFilterConditions.size(); i++) { + standardLogicPieces.add(String.valueOf(i + 1)); + } + conditionsLogic = '(' + String.join(standardLogicPieces, ' ' + this.rule.ConditionLogicType__c + ' ') + ')'; + } + + List parsedCharacters = new List(); + Boolean hasFoundNumbers = false; + String foundNumberString = ''; + + for (String character : conditionsLogic.split('')) { + if (!character.isNumeric() && !hasFoundNumbers) { + parsedCharacters.add(character); + } else if (!character.isNumeric() && hasFoundNumbers) { + hasFoundNumbers = false; + Integer foundNumber = Integer.valueOf(foundNumberString) - 1; + + parsedCharacters.add('{' + foundNumber + '}'); + foundNumberString = ''; + parsedCharacters.add(character); + } else if (character.isNumeric()) { + hasFoundNumbers = true; + foundNumberString += character; + } else if (hasFoundNumbers && !character.isNumeric() && !String.isBlank(foundNumberString)) { + Integer foundNumber = Integer.valueOf(foundNumberString) - 1; + + parsedCharacters.add('{' + foundNumber + '}'); + foundNumberString = ''; + } else { + parsedCharacters.add(character); + } + } + return String.join(parsedCharacters, '').toUpperCase(); + } + } + + @SuppressWarnings('PMD.ApexDoc') + @TestVisible + private class FilterConditionResult { + private Boolean matchesFilter; + private SObject record; + private LogRetentionRuleCondition__mdt filterCondition; + private Schema.SObjectType sobjectType; + + private FilterConditionResult(SObject record, LogRetentionRuleCondition__mdt filterCondition) { + this.sobjectType = record.getSObjectType(); + this.record = record; + this.filterCondition = filterCondition; + + this.matchesFilter = this.matchesFilter(); + } + + public String getCondition() { + return this.filterCondition.FieldPath__c + + ' ' + + this.filterCondition.Operator__c + + ' ' + + this.getComparisonValue() + + ' (' + + this.filterCondition.ValueType__c + + ')'; + } + + public Boolean matchesFilter() { + // TODO In a future release, it'd be great to switch to using a new private enum for ValueType__c values + if (this.filterCondition.ValueType__c == 'RegEx') { + return this.matchesRegEx(); + } + + Schema.SObjectField field = new FieldPath(this.sobjectType, this.filterCondition.FieldPath__c).getField(); + + Object recordFieldValue = this.getFieldValue(); + Object comparisonValue = this.getComparisonValue(); + + switch on field.getDescribe().getSoapType() { + when DATETIME { + return this.compareDatetime((Datetime) recordFieldValue, this.getAsDatetime(comparisonValue)); + } + when DOUBLE, INTEGER { + return this.compareDecimal((Decimal) recordFieldValue, this.getAsDecimal(comparisonValue)); + } + when STRING, ID { + return this.compareString((String) recordFieldValue, String.valueOf(comparisonValue)); + } + when else { + throw new IllegalArgumentException('Could not process field path: ' + this.filterCondition.FieldPath__c); + } + } + } + + private Boolean matchesRegEx() { + Pattern pattern = Pattern.compile(this.filterCondition.Value__c); + return pattern.matcher(String.valueOf(this.getFieldValue())).matches(); + } + + private Object getFieldValue() { + return new FieldPath(this.sobjectType, this.filterCondition.FieldPath__c).getValue(this.record); + } + + private Object getComparisonValue() { + switch on this.filterCondition.ValueType__c { + when 'Field' { + return new FieldPath(this.sobjectType, this.filterCondition.Value__c).getValue(this.record); + } + when 'RegEx' { + return this.filterCondition.Value__c; + } + when 'Value' { + return this.filterCondition.Value__c; + } + when else { + throw new IllegalArgumentException('Unknown Value Type, cannot parse comparison value'); + } + } + } + + // Helper methods for dealing with converting field values & strings + // (stored in CMDT) to the appropriate data type + private Datetime getAsDatetime(Object datetimeValue) { + if (datetimeValue == null) { + return null; + } else if (datetimeValue instanceof Datetime) { + return (Datetime) datetimeValue; + } else { + String datetimeString = (String) datetimeValue; + return (Datetime) JSON.deserialize(datetimeString, Datetime.class); + } + } + + private Decimal getAsDecimal(Object decimalValue) { + if (decimalValue == null) { + return null; + } else if (decimalValue instanceof Decimal) { + return (Decimal) decimalValue; + } else { + String decimalString = (String) decimalValue; + return (Decimal) JSON.deserialize(decimalString, Decimal.class); + } + } + + // In Apex, you can't use comparison operators on instances of Object, so several private methods are used for each data type + // Example of what you can't do in Apex: + // Object today = System.today(); + // Object yesterday = System.today().addDays(-1); + // System.assert(today > yesterday); // This line cannot execute since it's comparing Object + private Boolean compareDatetime(Datetime recordFieldValue, Datetime comparisonValue) { + // TODO In a future release, it'd be great to switch (ha!) these hardcoded strings to instead use + // a (new) private enum + switch on this.filterCondition.Operator__c { + when 'EQUAL_TO' { + return recordFieldValue == comparisonValue; + } + when 'NOT_EQUAL_TO' { + return recordFieldValue != comparisonValue; + } + when 'LESS_THAN' { + return recordFieldValue < comparisonValue; + } + when 'LESS_THAN_OR_EQUAL_TO' { + return recordFieldValue <= comparisonValue; + } + when 'GREATER_THAN' { + return recordFieldValue > comparisonValue; + } + when 'GREATER_THAN_OR_EQUAL_TO' { + return recordFieldValue >= comparisonValue; + } + when else { + throw new IllegalArgumentException('Unsupported operator for Datetime: ' + this.filterCondition.Operator__c); + } + } + } + + private Boolean compareDecimal(Decimal recordFieldValue, Decimal comparisonValue) { + // TODO In a future release, it'd be great to switch (ha!) these hardcoded strings to instead use + // a (new) private enum + switch on this.filterCondition.Operator__c { + when 'EQUAL_TO' { + return recordFieldValue == comparisonValue; + } + when 'NOT_EQUAL_TO' { + return recordFieldValue != comparisonValue; + } + when 'LESS_THAN' { + return recordFieldValue < comparisonValue; + } + when 'LESS_THAN_OR_EQUAL_TO' { + return recordFieldValue <= comparisonValue; + } + when 'GREATER_THAN' { + return recordFieldValue > comparisonValue; + } + when 'GREATER_THAN_OR_EQUAL_TO' { + return recordFieldValue >= comparisonValue; + } + when else { + throw new IllegalArgumentException('Unsupported operator for Decimal: ' + this.filterCondition.Operator__c); + } + } + } + + private Boolean compareString(String recordFieldValue, String comparisonValue) { + // TODO In a future release, it'd be great to switch (ha!) these hardcoded strings to instead use + // a (new) private enum + switch on this.filterCondition.Operator__c { + when 'EQUAL_TO' { + return recordFieldValue == comparisonValue; + } + when 'NOT_EQUAL_TO' { + return recordFieldValue != comparisonValue; + } + when 'STARTS_WITH' { + return recordFieldValue.startsWith(comparisonValue); + } + when 'CONTAINS' { + return recordFieldValue.contains(comparisonValue); + } + when 'ENDS_WITH' { + return recordFieldValue.endsWith(comparisonValue); + } + when else { + throw new IllegalArgumentException('Unsupported operator for String: ' + this.filterCondition.Operator__c); + } + } + } + } + + // Credit goes to this StackExchange post for the original BooleanExpression class - + // below is a modified version of the class + // https://salesforce.stackexchange.com/questions/113300/boolean-evaluation-in-apex/113308 + @SuppressWarnings('PMD.ApexDoc') + private class BooleanExpression { + public Boolean evaluate(String x) { + x = simplify(x); + + if (isSimpleExpression(x)) { + return Boolean.valueOf(x); + } + + if (x.contains('&&')) { + return andJoin(x.split('&&', 2)[0], x.split('&&', 2)[1]); + } + + if (x.contains('||')) { + String p1 = x.split('\\|\\|', 2)[0]; + String p2 = x.split('\\|\\|', 2)[1]; + + return orJoin(p1, p2); + } + + if (x.startsWith('!')) { + return !evaluate(x.substring(1)); + } + + return Boolean.valueOf(x); + } + + private Boolean orJoin(String x, String y) { + return evaluate(x) || evaluate(y); + } + + private Boolean andJoin(String x, String y) { + return evaluate(x) && evaluate(y); + } + + private Boolean isSimpleExpression(String x) { + return x == 'true' || x == 'false'; + } + + private String simplify(String x) { + x = x.trim(); + x = x.replace('AND', '&&'); + x = x.replace('OR', '||'); + while (x.contains('(') == true) { + String sub = x.substringAfterLast('(').substringBefore(')'); + x = x.replace('(' + sub + ')', String.valueOf(evaluate(sub))); + } + return x; + } + } + + @SuppressWarnings('PMD.ApexDoc') + private class FieldPath { + private List fieldChain; + private Schema.DescribeFieldResult fieldDescribe; + private String fieldPath; + private Schema.SObjectType sobjectType; + + public FieldPath(Schema.SObjectType sobjectType, String fieldPath) { + this.fieldChain = this.getFieldChain(sobjectType, fieldPath); + this.fieldPath = fieldPath; + + this.fieldDescribe = this.getLastFieldDescribe(); + } + + public Schema.SObjectField getField() { + return this.fieldChain[this.fieldChain.size() - 1]; + } + + public Object getValue(SObject record) { + Schema.SObjectType parentSObjectType = this.sobjectType; + SObject parentRecord = record; + + for (Schema.SObjectField field : this.fieldChain) { + Schema.DescribeFieldResult fieldDescribe = field.getDescribe(); + if (fieldDescribe.getSoapType() != Schema.SoapType.Id) { + return parentRecord.get(fieldDescribe.getName()); + } else { + parentSObjectType = fieldDescribe.getReferenceTo().get(0); + + SObject newParentRecord = parentRecord.getSObject(field); + if (newParentRecord == null) { + return null; + } else { + parentRecord = newParentRecord; + } + } + } + + return null; + } + + private List getFieldChain(Schema.SObjectType sobjectType, String fieldPath) { + Schema.SObjectType currentSObjectType = sobjectType; + + List fields = new List(); + List fieldPathPieces = fieldPath.split('\\.'); + Integer lastFieldIndex = fieldPathPieces.size() <= 1 ? 0 : fieldPathPieces.size() - 1; + + for (Integer i = 0; i < fieldPathPieces.size(); i++) { + String fieldPathPiece = fieldPathPieces[i]; + + String fieldApiName; + if (i == lastFieldIndex) { + fieldApiName = fieldPathPiece; + } else if (fieldPathPiece.endsWith('__r')) { + fieldApiName = fieldPathPiece.replace('__r', '__c'); + } else { + fieldApiName = fieldPathPiece + 'Id'; + } + + Schema.SObjectField field = currentSObjectType.getDescribe().fields.getMap().get(fieldApiName); + + // TODO add support for polymorphic fields + if (i < lastFieldIndex) { + currentSObjectType = field.getDescribe().getReferenceTo().get(0); + } + + fields.add(field); + } + + return fields; + } + + private Schema.DescribeFieldResult getLastFieldDescribe() { + Integer lastFieldIndex = this.fieldChain.size() - 1; + return this.fieldChain[lastFieldIndex].getDescribe(); + } + } +} diff --git a/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionFilter.cls-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionFilter.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionFilter.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionFilter_Tests.cls b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionFilter_Tests.cls new file mode 100644 index 000000000..5f22a9bf3 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionFilter_Tests.cls @@ -0,0 +1,476 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +@SuppressWarnings('PMD.ApexDoc, PMD.CyclomaticComplexity, PMD.ExcessiveParameterList, PMD.MethodNamingConventions') +@IsTest(IsParallel=true) +private class LogRetentionFilter_Tests { + @IsTest + static void it_should_match_one_condition_on_datetime_equal_to() { + Integer numberOfDaysToRetainLogs = 90; + Datetime mockTimestamp = System.now(); + LogRetentionRule__mdt rule = createMockRule('number_equal_to'); + rule.NumberOfDaysToRetainLogs__c = numberOfDaysToRetainLogs; + List conditions = new List{ + createMockRuleCondition('Timestamp__c', 'EQUAL_TO', 'Value', mockTimestamp) + }; + LogEntry__c matchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + matchingLogEntry.Timestamp__c = mockTimestamp; + LogEntry__c nonMatchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + nonMatchingLogEntry.Timestamp__c = mockTimestamp.addMinutes(-9); + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_match_one_condition_on_datetime_not_equal_to() { + Integer numberOfDaysToRetainLogs = 90; + Datetime mockTimestamp = System.now(); + LogRetentionRule__mdt rule = createMockRule('number_not_equal_to'); + rule.NumberOfDaysToRetainLogs__c = numberOfDaysToRetainLogs; + List conditions = new List{ + createMockRuleCondition('Timestamp__c', 'NOT_EQUAL_TO', 'Value', mockTimestamp) + }; + LogEntry__c matchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + matchingLogEntry.Timestamp__c = mockTimestamp.addMinutes(-9); + LogEntry__c nonMatchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + nonMatchingLogEntry.Timestamp__c = mockTimestamp; + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_match_one_condition_on_datetime_less_than() { + Integer numberOfDaysToRetainLogs = 90; + Datetime mockTimestamp = System.now(); + LogRetentionRule__mdt rule = createMockRule('number_less_than'); + rule.NumberOfDaysToRetainLogs__c = numberOfDaysToRetainLogs; + List conditions = new List{ + createMockRuleCondition('Timestamp__c', 'LESS_THAN', 'Value', mockTimestamp) + }; + LogEntry__c matchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + matchingLogEntry.Timestamp__c = mockTimestamp.addMinutes(-1); + LogEntry__c nonMatchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + nonMatchingLogEntry.Timestamp__c = mockTimestamp.addMinutes(+9); + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_match_one_condition_on_datetime_less_than_or_equal_to() { + Datetime mockTimestamp = System.now(); + LogRetentionRule__mdt rule = createMockRule('number_less_than_or_equal_to'); + List conditions = new List{ + createMockRuleCondition('Timestamp__c', 'LESS_THAN_OR_EQUAL_TO', 'Value', mockTimestamp) + }; + LogEntry__c matchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + matchingLogEntry.Timestamp__c = mockTimestamp; + LogEntry__c nonMatchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + nonMatchingLogEntry.Timestamp__c = mockTimestamp.addMinutes(+9); + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_match_one_condition_on_datetime_greater_than() { + Datetime mockTimestamp = System.now(); + LogRetentionRule__mdt rule = createMockRule('number_greater_than'); + List conditions = new List{ + createMockRuleCondition('Timestamp__c', 'GREATER_THAN', 'Value', mockTimestamp) + }; + LogEntry__c matchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + matchingLogEntry.Timestamp__c = mockTimestamp.addMinutes(+9); + LogEntry__c nonMatchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + nonMatchingLogEntry.Timestamp__c = mockTimestamp.addMinutes(-1); + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_match_one_condition_on_datetime_greater_than_or_equal_to() { + Datetime mockTimestamp = System.now(); + LogRetentionRule__mdt rule = createMockRule('number_greater_than_or_equal_to'); + List conditions = new List{ + createMockRuleCondition('Timestamp__c', 'GREATER_THAN_OR_EQUAL_TO', 'Value', mockTimestamp) + }; + LogEntry__c matchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + matchingLogEntry.Timestamp__c = mockTimestamp; + LogEntry__c nonMatchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + nonMatchingLogEntry.Timestamp__c = mockTimestamp.addMinutes(-9); + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_throw_illegal_argument_exception_on_datetime_when_invalid_operator() { + String invalidOperator = 'THIS_IS_AN_INVALID_OPERATOR'; + Datetime mockTimestamp = System.now(); + LogRetentionRule__mdt rule = createMockRule('number_with_invalid_operator'); + List conditions = new List{ + createMockRuleCondition('Timestamp__c', invalidOperator, 'Value', mockTimestamp) + }; + LogEntry__c mockLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType).populateRequiredFields().getRecord(); + mockLogEntry.Timestamp__c = mockTimestamp; + + Exception thrownIllegalArgumentException; + try { + new LogRetentionFilter(mockLogEntry, rule, conditions).getFilterResult(); + } catch (IllegalArgumentException ex) { + thrownIllegalArgumentException = ex; + } + + System.assertNotEquals(null, thrownIllegalArgumentException); + System.assertEquals('Unsupported operator for Datetime: ' + invalidOperator, thrownIllegalArgumentException.getMessage()); + } + + @IsTest + static void it_should_match_one_condition_on_decimal_equal_to() { + Integer exampleLoggingLevelOrdinal = LoggingLevel.INFO.ordinal(); + LogRetentionRule__mdt rule = createMockRule('number_equal_to'); + List conditions = new List{ + createMockRuleCondition('LoggingLevelOrdinal__c', 'EQUAL_TO', 'Value', exampleLoggingLevelOrdinal) + }; + LogEntry__c matchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + matchingLogEntry.LoggingLevelOrdinal__c = exampleLoggingLevelOrdinal; + LogEntry__c nonMatchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + nonMatchingLogEntry.LoggingLevelOrdinal__c = exampleLoggingLevelOrdinal - 9; + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_match_one_condition_on_decimal_not_equal_to() { + Integer exampleLoggingLevelOrdinal = LoggingLevel.INFO.ordinal(); + LogRetentionRule__mdt rule = createMockRule('number_not_equal_to'); + List conditions = new List{ + createMockRuleCondition('LoggingLevelOrdinal__c', 'NOT_EQUAL_TO', 'Value', exampleLoggingLevelOrdinal) + }; + LogEntry__c matchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + matchingLogEntry.LoggingLevelOrdinal__c = exampleLoggingLevelOrdinal - 9; + LogEntry__c nonMatchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + nonMatchingLogEntry.LoggingLevelOrdinal__c = exampleLoggingLevelOrdinal; + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_match_one_condition_on_decimal_less_than() { + Integer exampleLoggingLevelOrdinal = LoggingLevel.INFO.ordinal(); + LogRetentionRule__mdt rule = createMockRule('number_less_than'); + List conditions = new List{ + createMockRuleCondition('LoggingLevelOrdinal__c', 'LESS_THAN', 'Value', exampleLoggingLevelOrdinal) + }; + LogEntry__c matchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + matchingLogEntry.LoggingLevelOrdinal__c = exampleLoggingLevelOrdinal - 1; + LogEntry__c nonMatchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + nonMatchingLogEntry.LoggingLevelOrdinal__c = exampleLoggingLevelOrdinal + 9; + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_match_one_condition_on_decimal_less_than_or_equal_to() { + Integer exampleLoggingLevelOrdinal = LoggingLevel.INFO.ordinal(); + LogRetentionRule__mdt rule = createMockRule('number_less_than_or_equal_to'); + List conditions = new List{ + createMockRuleCondition('LoggingLevelOrdinal__c', 'LESS_THAN_OR_EQUAL_TO', 'Value', exampleLoggingLevelOrdinal) + }; + LogEntry__c matchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + matchingLogEntry.LoggingLevelOrdinal__c = exampleLoggingLevelOrdinal; + LogEntry__c nonMatchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + nonMatchingLogEntry.LoggingLevelOrdinal__c = exampleLoggingLevelOrdinal + 9; + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_match_one_condition_on_decimal_greater_than() { + Integer exampleLoggingLevelOrdinal = LoggingLevel.INFO.ordinal(); + LogRetentionRule__mdt rule = createMockRule('number_greater_than'); + List conditions = new List{ + createMockRuleCondition('LoggingLevelOrdinal__c', 'GREATER_THAN', 'Value', exampleLoggingLevelOrdinal) + }; + LogEntry__c matchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + matchingLogEntry.LoggingLevelOrdinal__c = exampleLoggingLevelOrdinal + 9; + LogEntry__c nonMatchingLogEntry = (LogEntry__c) LoggerMockDataCreator.createDataBuilder(Schema.LogEntry__c.SObjectType) + .populateRequiredFields() + .getRecord(); + nonMatchingLogEntry.LoggingLevelOrdinal__c = exampleLoggingLevelOrdinal - 1; + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_match_one_condition_on_decimal_greater_than_or_equal_to() { + Integer exampleLoggingLevelOrdinal = LoggingLevel.INFO.ordinal(); + LogRetentionRule__mdt rule = createMockRule('number_greater_than_or_equal_to'); + List conditions = new List{ + createMockRuleCondition('LoggingLevelOrdinal__c', 'GREATER_THAN_OR_EQUAL_TO', 'Value', exampleLoggingLevelOrdinal) + }; + LogEntry__c matchingLogEntry = new LogEntry__c(LoggingLevelOrdinal__c = exampleLoggingLevelOrdinal); + LogEntry__c nonMatchingLogEntry = new LogEntry__c(LoggingLevelOrdinal__c = exampleLoggingLevelOrdinal - 9); + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_throw_illegal_argument_exception_on_decimal_when_invalid_operator() { + String invalidOperator = 'THIS_IS_AN_INVALID_OPERATOR'; + Integer exampleLoggingLevelOrdinal = LoggingLevel.INFO.ordinal(); + LogRetentionRule__mdt rule = createMockRule('number_with_invalid_operator'); + List conditions = new List{ + createMockRuleCondition('LoggingLevelOrdinal__c', invalidOperator, 'Value', exampleLoggingLevelOrdinal) + }; + LogEntry__c mockLogEntry = new LogEntry__c(LoggingLevelOrdinal__c = exampleLoggingLevelOrdinal); + + Exception thrownIllegalArgumentException; + try { + new LogRetentionFilter(mockLogEntry, rule, conditions).getFilterResult(); + } catch (IllegalArgumentException ex) { + thrownIllegalArgumentException = ex; + } + + System.assertNotEquals(null, thrownIllegalArgumentException); + System.assertEquals('Unsupported operator for Decimal: ' + invalidOperator, thrownIllegalArgumentException.getMessage()); + } + + @IsTest + static void it_should_match_one_condition_on_string_equal_to() { + String mockStringValue = 'Some text'; + LogRetentionRule__mdt rule = createMockRule('string_equal_to'); + List conditions = new List{ + createMockRuleCondition('Message__c', 'EQUAL_TO', 'Value', mockStringValue) + }; + LogEntry__c matchingLogEntry = new LogEntry__c(Message__c = mockStringValue); + LogEntry__c nonMatchingLogEntry = new LogEntry__c(Message__c = mockStringValue + ' some extra text so it does not match'); + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_match_one_condition_on_string_not_equal_to() { + String mockStringValue = 'Some text'; + LogRetentionRule__mdt rule = createMockRule('string_not_equal_to'); + List conditions = new List{ + createMockRuleCondition('Message__c', 'NOT_EQUAL_TO', 'Value', mockStringValue) + }; + LogEntry__c matchingLogEntry = new LogEntry__c(Message__c = mockStringValue + ' some extra text so it does not match'); + LogEntry__c nonMatchingLogEntry = new LogEntry__c(Message__c = mockStringValue); + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_match_one_condition_on_string_starts_with() { + String mockStringValue = 'Some text'; + LogRetentionRule__mdt rule = createMockRule('string_starts_with'); + List conditions = new List{ + createMockRuleCondition('Message__c', 'STARTS_WITH', 'Value', mockStringValue) + }; + LogEntry__c matchingLogEntry = new LogEntry__c(Message__c = mockStringValue + ' some extra text, but this should still match using STARTS_WITH'); + LogEntry__c nonMatchingLogEntry = new LogEntry__c(Message__c = 'This starts with something that does not match! ' + mockStringValue); + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_match_one_condition_on_string_contains() { + String mockStringValue = 'Some text'; + LogRetentionRule__mdt rule = createMockRule('string_contains'); + List conditions = new List{ + createMockRuleCondition('Message__c', 'CONTAINS', 'Value', mockStringValue) + }; + LogEntry__c matchingLogEntry = new LogEntry__c( + Message__c = 'Some extra text at the beginning ' + mockStringValue + ' some extra text, but this should still match using STARTS_WITH' + ); + LogEntry__c nonMatchingLogEntry = new LogEntry__c(Message__c = 'This does not contain the matching text at all!'); + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_match_one_condition_on_string_ends_with() { + String mockStringValue = 'Some text'; + LogRetentionRule__mdt rule = createMockRule('string_ends_with', null); + List conditions = new List{ + createMockRuleCondition('Message__c', 'ENDS_WITH', 'Value', mockStringValue) + }; + LogEntry__c matchingLogEntry = new LogEntry__c(Message__c = 'Some extra text, but this should still match using ENDS_WITH' + mockStringValue); + LogEntry__c nonMatchingLogEntry = new LogEntry__c(Message__c = mockStringValue + ' and now this ends with something that does not match!'); + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + @IsTest + static void it_should_throw_illegal_argument_exception_on_string_when_invalid_operator() { + String invalidOperator = 'THIS_IS_AN_INVALID_OPERATOR'; + String mockStringValue = 'Some text'; + LogRetentionRule__mdt rule = createMockRule('string_with_invalid_operator'); + List conditions = new List{ + createMockRuleCondition('Message__c', invalidOperator, 'Value', mockStringValue) + }; + LogEntry__c mockLogEntry = new LogEntry__c(Message__c = mockStringValue); + + Exception thrownIllegalArgumentException; + try { + new LogRetentionFilter(mockLogEntry, rule, conditions).getFilterResult(); + } catch (IllegalArgumentException ex) { + thrownIllegalArgumentException = ex; + } + + System.assertNotEquals(null, thrownIllegalArgumentException); + System.assertEquals('Unsupported operator for String: ' + invalidOperator, thrownIllegalArgumentException.getMessage()); + } + + @IsTest + static void it_should_match_one_condition_for_parent_field() { + String mockProfileName = 'Some profile'; + LogRetentionRule__mdt rule = createMockRule('string_equal_to'); + List conditions = new List{ + createMockRuleCondition('Log__r.ProfileName__c', 'EQUAL_TO', 'Value', mockProfileName) + }; + LogEntry__c matchingLogEntry = new LogEntry__c(Log__r = new Log__c(ProfileName__c = mockProfileName)); + LogEntry__c nonMatchingLogEntry = new LogEntry__c(Log__r = new Log__c(ProfileName__c = 'Some other value, that should not match')); + + LogRetentionFilter.FilterResult expectedMatchResult = new LogRetentionFilter(matchingLogEntry, rule, conditions).getFilterResult(); + LogRetentionFilter.FilterResult expectedNonMatchResult = new LogRetentionFilter(nonMatchingLogEntry, rule, conditions).getFilterResult(); + + System.assertEquals(true, expectedMatchResult.matchesFilter()); + System.assertEquals(false, expectedNonMatchResult.matchesFilter()); + } + + static LogRetentionRule__mdt createMockRule(String developerName) { + return createMockRule(developerName, null); + } + + static LogRetentionRule__mdt createMockRule(String developerName, String conditionLogicType) { + return new LogRetentionRule__mdt( + ConditionLogicType__c = conditionLogicType, + CustomConditionLogic__c = null, + DeveloperName = developerName, + IsEnabled__c = true + ); + } + + static LogRetentionRuleCondition__mdt createMockRuleCondition(String fieldPath, String operator, String valueType, Object value) { + String valueString = value instanceof String ? (String) value : JSON.serialize(value); + return new LogRetentionRuleCondition__mdt( + FieldPath__c = fieldPath, + Operator__c = operator, + SortOrder__c = null, + Value__c = valueString, + ValueType__c = valueType + ); + } +} diff --git a/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionFilter_Tests.cls-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionFilter_Tests.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionFilter_Tests.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionRulesPlugin.cls b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionRulesPlugin.cls new file mode 100644 index 000000000..e6181852b --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionRulesPlugin.cls @@ -0,0 +1,130 @@ +//-----------------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// The core functionality of this plugin's code originated in https://github.com/jongpie/ApexValidationRules // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//-----------------------------------------------------------------------------------------------------------// + +/** + * @group Plugins + * @description Optional plugin that adds the ability to create & deploy advanced, configurable rules + * for setting the retention date of `Log__c` records, using custom metadata types + * `LogRetentionRule__mdt` and `LogRetentionRuleCondition__mdt`. + * @see LogRetentionFilter + */ +public without sharing class LogRetentionRulesPlugin implements LoggerPlugin.Triggerable { + private static final Map RULE_NAME_TO_RULE = new Map(); + private static final Map> RULE_NAME_TO_CONDITIONS = new Map>(); + + /** + * @description Handles converting Logger's buffer of `LogEntryEvent__e` records into `LogEntryArchive__b` records + * for any user with the included custom save method 'BIG_OBJECT' + * @param configuration The instance of `LoggerPlugin__mdt` configured for this specific plugin + * @param input The instance of `LoggerTriggerableContext`, provided by the logging system + */ + public void execute(LoggerPlugin__mdt configuration, LoggerTriggerableContext input) { + if (input.sobjectType != Schema.LogEntry__c.SObjectType) { + return; + } + + this.loadConfiguredFilters(); + + switch on input.triggerOperationType { + when AFTER_INSERT { + List logEntries = requeryLogEntries((List) input.triggerNew); + this.setLogRetentionDate(logEntries); + } + } + } + + private List requeryLogEntries(List logEntries) { + // Requery the LogEntry__c records so the parent Log__c fields can be included/used in rules + List logEntryFieldNames = new List(Schema.LogEntry__c.SObjectType.getDescribe().fields.getMap().keySet()); + + List logFieldNames = new List(Schema.Log__c.SObjectType.getDescribe().fields.getMap().keySet()); + logFieldNames.addAll(new List{ 'Owner.Name', 'Owner.Type' }); + for (String logFieldName : logFieldNames) { + String logRelationshipPrefix = Schema.LogEntry__c.Log__c.getDescribe().getName().substringBeforeLast('__c') + '__r'; + logEntryFieldNames.add(logRelationshipPrefix + '.' + logFieldName); + } + + String queryTemplate = 'SELECT {0} FROM {1} WHERE {2} IN :logEntries'; + List queryInputs = new List{ + String.join(logEntryFieldNames, ','), + Schema.LogEntry__c.SObjectType.getDescribe().getName(), + Schema.LogEntry__c.Id.getDescribe().getName() + }; + String logEntryQuery = String.escapeSingleQuotes(String.format(queryTemplate, queryInputs)); + return (List) Database.query(logEntryQuery); + } + + private void setLogRetentionDate(List logEntries) { + Map logIdToLog = new Map(); + List filterResults = this.runFilters(logEntries); + for (LogRetentionFilter.FilterResult filterResult : filterResults) { + if (filterResult.matchesFilter() == true) { + Id logId = (Id) filterResult.getRecord().get(Schema.LogEntry__c.Log__c); + Log__c log = logIdToLog.get(logId); + if (log == null) { + log = new Log__c(Id = logId); + } + + Integer numberOfDaysToRetainLogs = Integer.valueOf(filterResult.getRule().NumberOfDaysToRetainLogs__c); + log.LogRetentionDate__c = numberOfDaysToRetainLogs == null ? null : System.today().addDays(numberOfDaysToRetainLogs); + + logIdToLog.put(log.Id, log); + } + } + update logIdToLog.values(); + } + + @SuppressWarnings('PMD.ApexCRUDViolation') + private void loadConfiguredFilters() { + Map queriedRulesByDeveloperName = new Map(); + Map> queriedConditionsByRuleDeveloperName = new Map>(); + for (LogRetentionRule__mdt rule : [ + SELECT + DeveloperName, + ConditionLogicType__c, + CustomConditionLogic__c, + NumberOfDaysToRetainLogs__c, + (SELECT FieldPath__c, Operator__c, ValueType__c, Value__c FROM LogRetentionRuleConditions__r ORDER BY SortOrder__c NULLS LAST, DeveloperName) + FROM LogRetentionRule__mdt + WHERE IsEnabled__c = TRUE + ORDER BY ExecutionOrder__c NULLS LAST, DeveloperName + ]) { + queriedRulesByDeveloperName.put(rule.DeveloperName, rule); + queriedConditionsByRuleDeveloperName.put(rule.DeveloperName, rule.LogRetentionRuleConditions__r); + + if (System.Test.isRunningTest() == true) { + queriedRulesByDeveloperName.clear(); + queriedConditionsByRuleDeveloperName.clear(); + } + RULE_NAME_TO_RULE.putAll(queriedRulesByDeveloperName); + RULE_NAME_TO_CONDITIONS.putAll(queriedConditionsByRuleDeveloperName); + } + } + + private List runFilters(List records) { + List results = new List(); + for (SObject record : records) { + for (String filterDeveloperName : RULE_NAME_TO_RULE.keySet()) { + LogRetentionRule__mdt filter = RULE_NAME_TO_RULE.get(filterDeveloperName); + List filterConditions = RULE_NAME_TO_CONDITIONS.get(filter.DeveloperName); + LogRetentionFilter.FilterResult filterResult = new LogRetentionFilter(record, filter, filterConditions).getFilterResult(); + + results.add(filterResult); + } + } + return results; + } + + @TestVisible + private static void setMockRetentionRule(LogRetentionRule__mdt rule) { + RULE_NAME_TO_RULE.put(rule.DeveloperName, rule); + } + + @TestVisible + private static void setMockRetentionRuleConditions(LogRetentionRule__mdt rule, List conditions) { + RULE_NAME_TO_CONDITIONS.put(rule.DeveloperName, conditions); + } +} diff --git a/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionRulesPlugin.cls-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionRulesPlugin.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionRulesPlugin.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionRulesPlugin_Tests.cls b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionRulesPlugin_Tests.cls new file mode 100644 index 000000000..d40c190ad --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionRulesPlugin_Tests.cls @@ -0,0 +1,211 @@ +//-----------------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// The core functionality of this plugin's code originated in https://github.com/jongpie/ApexValidationRules // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//-----------------------------------------------------------------------------------------------------------// + +// TODO revise suppressed PMD rules/clean up code +@SuppressWarnings('PMD.ApexDoc, PMD.ExcessiveParameterList, PMD.MethodNamingConventions') +@IsTest(IsParallel=true) +private class LogRetentionRulesPlugin_Tests { + @IsTest + static void it_should_set_retention_date_for_rule_with_one_condition_when_datetime_less_than() { + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + enablePlugin(); + Date originalLogRetentionDate = System.today().addDays(Integer.valueOf(Logger.getUserSettings().DefaultNumberOfDaysToRetainLogs__c)); + Integer numberOfDaysToRetainLogs = 90; + Date expectedLogRetentionDate = System.today().addDays(numberOfDaysToRetainLogs); + Datetime now = System.now(); + LogRetentionRule__mdt rule = createMockRule('rule_with_multiple_AND_conditions', 'AND', numberOfDaysToRetainLogs); + rule.NumberOfDaysToRetainLogs__c = numberOfDaysToRetainLogs; + LogRetentionRulesPlugin.setMockRetentionRule(rule); + List conditions = new List{ + createMockRuleCondition('Log__r.CreatedDate', 'LESS_THAN', 'Value', now) + }; + LogRetentionRulesPlugin.setMockRetentionRuleConditions(rule, conditions); + Log__c log = new Log__c(TransactionId__c = '1234'); + insert log; + Test.setCreatedDate(log.Id, now.addDays(-1)); + log = [SELECT Id, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(originalLogRetentionDate, log.LogRetentionDate__c); + + LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, LoggingLevel__c = LoggingLevel.ERROR.name(), TransactionEntryNumber__c = 1); + insert logEntry; + + log = [SELECT Id, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(expectedLogRetentionDate, log.LogRetentionDate__c); + } + + @IsTest + static void it_should_set_retention_date_for_rule_with_one_condition_when_datetime_less_than_or_equal_to() { + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + enablePlugin(); + Date originalLogRetentionDate = System.today().addDays(Integer.valueOf(Logger.getUserSettings().DefaultNumberOfDaysToRetainLogs__c)); + Integer numberOfDaysToRetainLogs = 90; + Date expectedLogRetentionDate = System.today().addDays(numberOfDaysToRetainLogs); + Datetime now = System.now(); + LogRetentionRule__mdt rule = createMockRule('rule_with_multiple_AND_conditions', 'AND', numberOfDaysToRetainLogs); + rule.NumberOfDaysToRetainLogs__c = numberOfDaysToRetainLogs; + LogRetentionRulesPlugin.setMockRetentionRule(rule); + List conditions = new List{ + createMockRuleCondition('Log__r.CreatedDate', 'LESS_THAN_OR_EQUAL_TO', 'Value', now) + }; + LogRetentionRulesPlugin.setMockRetentionRuleConditions(rule, conditions); + + Log__c log = new Log__c(TransactionId__c = '1234'); + insert log; + Test.setCreatedDate(log.Id, now); + log = [SELECT Id, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(originalLogRetentionDate, log.LogRetentionDate__c); + + LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, LoggingLevel__c = LoggingLevel.ERROR.name(), TransactionEntryNumber__c = 1); + insert logEntry; + log = [SELECT Id, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(expectedLogRetentionDate, log.LogRetentionDate__c); + } + + @IsTest + static void it_should_set_retention_date_for_rule_with_one_string_equality_condition() { + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + enablePlugin(); + Date originalLogRetentionDate = System.today().addDays(Integer.valueOf(Logger.getUserSettings().DefaultNumberOfDaysToRetainLogs__c)); + Integer numberOfDaysToRetainLogs = 90; + Date expectedLogRetentionDate = System.today().addDays(numberOfDaysToRetainLogs); + String scenario = 'Some scenario'; + LogRetentionRule__mdt rule = createMockRule('rule_with_multiple_AND_conditions', 'AND', numberOfDaysToRetainLogs); + rule.NumberOfDaysToRetainLogs__c = numberOfDaysToRetainLogs; + LogRetentionRulesPlugin.setMockRetentionRule(rule); + List conditions = new List{ + createMockRuleCondition('Log__r.Scenario__c', 'EQUAL_TO', 'Value', scenario) + }; + LogRetentionRulesPlugin.setMockRetentionRuleConditions(rule, conditions); + + Log__c log = new Log__c(Scenario__c = scenario, TransactionId__c = '1234'); + insert log; + log = [SELECT Id, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(originalLogRetentionDate, log.LogRetentionDate__c); + + LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, LoggingLevel__c = LoggingLevel.ERROR.name(), TransactionEntryNumber__c = 1); + insert logEntry; + log = [SELECT Id, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(expectedLogRetentionDate, log.LogRetentionDate__c); + } + + @IsTest + static void it_should_set_retention_date_for_rule_with_multiple_and_conditions() { + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + enablePlugin(); + Date originalLogRetentionDate = System.today().addDays(Integer.valueOf(Logger.getUserSettings().DefaultNumberOfDaysToRetainLogs__c)); + Integer numberOfDaysToRetainLogs = 90; + Date expectedLogRetentionDate = System.today().addDays(numberOfDaysToRetainLogs); + String scenario = 'Some scenario'; + Integer userLoggingLevelOrdinal = LoggingLevel.WARN.ordinal(); + LogRetentionRule__mdt rule = createMockRule('rule_with_multiple_AND_conditions', 'AND', numberOfDaysToRetainLogs); + LogRetentionRulesPlugin.setMockRetentionRule(rule); + List conditions = new List{ + createMockRuleCondition('Log__r.Scenario__c', 'EQUAL_TO', 'Value', scenario), + createMockRuleCondition('Log__r.UserLoggingLevelOrdinal__c', 'GREATER_THAN_OR_EQUAL_TO', 'Value', userLoggingLevelOrdinal) + }; + LogRetentionRulesPlugin.setMockRetentionRuleConditions(rule, conditions); + + Log__c log = new Log__c(Scenario__c = scenario, TransactionId__c = '1234', UserLoggingLevelOrdinal__c = userLoggingLevelOrdinal); + insert log; + log = [SELECT Id, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(originalLogRetentionDate, log.LogRetentionDate__c); + LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, LoggingLevel__c = LoggingLevel.ERROR.name(), TransactionEntryNumber__c = 1); + insert logEntry; + + log = [SELECT Id, LogRetentionDate__c, Scenario__c, TotalERRORLogEntries__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(expectedLogRetentionDate, log.LogRetentionDate__c, log); + } + + @IsTest + static void it_should_set_retention_date_for_rule_with_multiple_or_conditions() { + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + enablePlugin(); + Date originalLogRetentionDate = System.today().addDays(Integer.valueOf(Logger.getUserSettings().DefaultNumberOfDaysToRetainLogs__c)); + Integer numberOfDaysToRetainLogs = 90; + Date expectedLogRetentionDate = System.today().addDays(numberOfDaysToRetainLogs); + String scenario1 = 'Some scenario'; + String scenario2 = 'Another scenario'; + LogRetentionRule__mdt rule = createMockRule('rule_with_multiple_OR_conditions', 'OR', numberOfDaysToRetainLogs); + LogRetentionRulesPlugin.setMockRetentionRule(rule); + List conditions = new List{ + createMockRuleCondition('Log__r.Scenario__c', 'EQUAL_TO', 'Value', scenario1), + createMockRuleCondition('Log__r.Scenario__c', 'EQUAL_TO', 'Value', scenario2) + }; + LogRetentionRulesPlugin.setMockRetentionRuleConditions(rule, conditions); + + Log__c log = new Log__c(Scenario__c = scenario1, TransactionId__c = '1234'); + insert log; + log = [SELECT Id, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(originalLogRetentionDate, log.LogRetentionDate__c); + LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, LoggingLevel__c = LoggingLevel.ERROR.name(), TransactionEntryNumber__c = 1); + insert logEntry; + + log = [SELECT Id, LogRetentionDate__c, Scenario__c, TotalERRORLogEntries__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(expectedLogRetentionDate, log.LogRetentionDate__c, log); + } + + @IsTest + static void it_should_set_retention_date_for_rule_with_multiple_custom_conditions() { + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + enablePlugin(); + Date originalLogRetentionDate = System.today().addDays(Integer.valueOf(Logger.getUserSettings().DefaultNumberOfDaysToRetainLogs__c)); + Integer numberOfDaysToRetainLogs = 90; + Date expectedLogRetentionDate = System.today().addDays(numberOfDaysToRetainLogs); + String scenario1 = 'Some scenario'; + String scenario2 = 'Another scenario'; + Integer userLoggingLevelOrdinal = LoggingLevel.WARN.ordinal(); + LogRetentionRule__mdt rule = createMockRule('rule_with_multiple_OR_conditions', 'Custom', numberOfDaysToRetainLogs); + rule.CustomConditionLogic__c = '((1 OR 2) AND 3)'; + LogRetentionRulesPlugin.setMockRetentionRule(rule); + List conditions = new List{ + createMockRuleCondition('Log__r.Scenario__c', 'EQUAL_TO', 'Value', scenario1), + createMockRuleCondition('Log__r.Scenario__c', 'EQUAL_TO', 'Value', scenario2), + createMockRuleCondition('Log__r.UserLoggingLevelOrdinal__c', 'GREATER_THAN_OR_EQUAL_TO', 'Value', userLoggingLevelOrdinal) + }; + LogRetentionRulesPlugin.setMockRetentionRuleConditions(rule, conditions); + + Log__c log = new Log__c(Scenario__c = scenario1, TransactionId__c = '1234', UserLoggingLevelOrdinal__c = userLoggingLevelOrdinal); + insert log; + log = [SELECT Id, LogRetentionDate__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(originalLogRetentionDate, log.LogRetentionDate__c); + LogEntry__c logEntry = new LogEntry__c(Log__c = log.Id, LoggingLevel__c = LoggingLevel.ERROR.name(), TransactionEntryNumber__c = 1); + insert logEntry; + + log = [SELECT Id, LogRetentionDate__c, Scenario__c, TotalERRORLogEntries__c FROM Log__c WHERE Id = :log.Id]; + System.assertEquals(expectedLogRetentionDate, log.LogRetentionDate__c, log); + } + + static void enablePlugin() { + // Set the plugin's parameters + LoggerPlugin__mdt pluginConfiguration = new LoggerPlugin__mdt( + DeveloperName = 'LogRetentionRulesPlugin', + IsEnabled__c = true, + SObjectHandlerApexClass__c = LogRetentionRulesPlugin.class.getName() + ); + LoggerTestConfigurator.setMock(pluginConfiguration); + } + + static LogRetentionRule__mdt createMockRule(String developerName, String conditionLogicType, Integer numberOfDaysToRetainLogs) { + return new LogRetentionRule__mdt( + ConditionLogicType__c = conditionLogicType, + CustomConditionLogic__c = null, + DeveloperName = developerName, + IsEnabled__c = true, + NumberOfDaysToRetainLogs__c = numberOfDaysToRetainLogs + ); + } + + static LogRetentionRuleCondition__mdt createMockRuleCondition(String fieldPath, String operator, String valueType, Object value) { + String valueString = value instanceof String ? (String) value : JSON.serialize(value); + return new LogRetentionRuleCondition__mdt( + FieldPath__c = fieldPath, + Operator__c = operator, + SortOrder__c = null, + Value__c = valueString, + ValueType__c = valueType + ); + } +} diff --git a/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionRulesPlugin_Tests.cls-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionRulesPlugin_Tests.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/classes/LogRetentionRulesPlugin_Tests.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRule.Sample_Rule_1_Error_Logs.md-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRule.Sample_Rule_1_Error_Logs.md-meta.xml new file mode 100644 index 000000000..ea8af3388 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRule.Sample_Rule_1_Error_Logs.md-meta.xml @@ -0,0 +1,29 @@ + + + + false + + ConditionLogicType__c + AND + + + CustomConditionLogic__c + + + + ExecutionOrder__c + + + + IsEnabled__c + true + + + NumberOfDaysToRetainLogs__c + 60.0 + + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRule.Sample_Rule_1_Scenarios_With_Errors.md-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRule.Sample_Rule_1_Scenarios_With_Errors.md-meta.xml new file mode 100644 index 000000000..6cab5ffdf --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRule.Sample_Rule_1_Scenarios_With_Errors.md-meta.xml @@ -0,0 +1,29 @@ + + + + false + + ConditionLogicType__c + Custom + + + CustomConditionLogic__c + 1 AND (2 OR 3) + + + ExecutionOrder__c + 1.0 + + + IsEnabled__c + true + + + NumberOfDaysToRetainLogs__c + 90.0 + + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRule.Sample_Rule_2_Additional_Error_Logs.md-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRule.Sample_Rule_2_Additional_Error_Logs.md-meta.xml new file mode 100644 index 000000000..dfadbb02c --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRule.Sample_Rule_2_Additional_Error_Logs.md-meta.xml @@ -0,0 +1,29 @@ + + + + false + + ConditionLogicType__c + AND + + + CustomConditionLogic__c + + + + ExecutionOrder__c + 2.0 + + + IsEnabled__c + true + + + NumberOfDaysToRetainLogs__c + 60.0 + + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRuleCondition.Sample_Rule_1_Error_Condition.md-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRuleCondition.Sample_Rule_1_Error_Condition.md-meta.xml new file mode 100644 index 000000000..6d3257d3c --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRuleCondition.Sample_Rule_1_Error_Condition.md-meta.xml @@ -0,0 +1,33 @@ + + + + false + + FieldPath__c + Log__r.TotalERRORLogEntries__c + + + LogRetentionRule__c + Sample_Rule_1_Scenarios_With_Errors + + + Operator__c + GREATER_THAN_OR_EQUAL_TO + + + SortOrder__c + 1.0 + + + ValueType__c + Value + + + Value__c + 1 + + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRuleCondition.Sample_Rule_1_Scenario_A_Condition.md-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRuleCondition.Sample_Rule_1_Scenario_A_Condition.md-meta.xml new file mode 100644 index 000000000..3295e724e --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRuleCondition.Sample_Rule_1_Scenario_A_Condition.md-meta.xml @@ -0,0 +1,33 @@ + + + + false + + FieldPath__c + Log__r.Scenario__c + + + LogRetentionRule__c + Sample_Rule_1_Scenarios_With_Errors + + + Operator__c + EQUAL_TO + + + SortOrder__c + 2.0 + + + ValueType__c + Value + + + Value__c + feature A + + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRuleCondition.Sample_Rule_1_Scenario_B_Condition.md-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRuleCondition.Sample_Rule_1_Scenario_B_Condition.md-meta.xml new file mode 100644 index 000000000..8354ab432 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRuleCondition.Sample_Rule_1_Scenario_B_Condition.md-meta.xml @@ -0,0 +1,33 @@ + + + + false + + FieldPath__c + Log__r.Scenario__c + + + LogRetentionRule__c + Sample_Rule_1_Scenarios_With_Errors + + + Operator__c + EQUAL_TO + + + SortOrder__c + 3.0 + + + ValueType__c + Value + + + Value__c + feature B + + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRuleCondition.Sample_Rule_1_condition.md-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRuleCondition.Sample_Rule_1_condition.md-meta.xml new file mode 100644 index 000000000..9ba8cdc0f --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRuleCondition.Sample_Rule_1_condition.md-meta.xml @@ -0,0 +1,33 @@ + + + + false + + FieldPath__c + Log__r.TotalERRORLogEntries__c + + + LogRetentionRule__c + Sample_Rule_1_Error_Logs + + + Operator__c + GREATER_THAN + + + SortOrder__c + + + + ValueType__c + Value + + + Value__c + 1 + + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRuleCondition.Sample_Rule_2_Error_Condition.md-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRuleCondition.Sample_Rule_2_Error_Condition.md-meta.xml new file mode 100644 index 000000000..d40504c77 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LogRetentionRuleCondition.Sample_Rule_2_Error_Condition.md-meta.xml @@ -0,0 +1,33 @@ + + + + false + + FieldPath__c + Log__r.TotalERRORLogEntries__c + + + LogRetentionRule__c + Sample_Rule_2_Additional_Error_Logs + + + Operator__c + GREATER_THAN + + + SortOrder__c + + + + ValueType__c + Value + + + Value__c + 1 + + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LoggerPlugin.LogRetentionRules.md-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LoggerPlugin.LogRetentionRules.md-meta.xml new file mode 100644 index 000000000..867b48be3 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/customMetadata/LoggerPlugin.LogRetentionRules.md-meta.xml @@ -0,0 +1,51 @@ + + + + false + + BatchPurgerApexClass__c + + + + BatchPurgerExecutionOrder__c + + + + BatchPurgerFlowName__c + + + + Description__c + Adds the ability to create & deploy advanced, configurable rules for setting the retention date of Log__c records, using custom metadata types LogRetentionRule__mdt and LogRetentionRuleCondition__mdt. + + + IsEnabled__c + true + + + Link__c + + + + SObjectHandlerApexClass__c + + + + SObjectHandlerExecutionOrder__c + + + + SObjectHandlerFlowName__c + + + + VersionNumber__c + v0.9.0 + + diff --git a/nebula-logger/core/main/plugin-framework/layouts/LoggerPlugin__mdt-Logger Plugin Layout.layout-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/layouts/LogRetentionRuleCondition__mdt-Log Retention Rule Condition Layout.layout-meta.xml similarity index 82% rename from nebula-logger/core/main/plugin-framework/layouts/LoggerPlugin__mdt-Logger Plugin Layout.layout-meta.xml rename to nebula-logger/plugins/log-retention-rules/plugin/layouts/LogRetentionRuleCondition__mdt-Log Retention Rule Condition Layout.layout-meta.xml index 3f2bf15a1..e36a1256d 100644 --- a/nebula-logger/core/main/plugin-framework/layouts/LoggerPlugin__mdt-Logger Plugin Layout.layout-meta.xml +++ b/nebula-logger/plugins/log-retention-rules/plugin/layouts/LogRetentionRuleCondition__mdt-Log Retention Rule Condition Layout.layout-meta.xml @@ -16,9 +16,13 @@ + + Required + LogRetentionRule__c + Edit - IsEnabled__c + SortOrder__c @@ -27,41 +31,28 @@ true true true - + Required - SObjectType__c + FieldPath__c - Edit - ExecutionOrder__c + Required + Operator__c Required - PluginType__c - - - Required - PluginApiName__c + ValueType__c - - - - - true - false - false - - Edit - Description__c + Value__c - + false @@ -70,8 +61,8 @@ - Required - NamespacePrefix + Edit + IsProtected Readonly @@ -80,8 +71,8 @@ - Edit - IsProtected + Required + NamespacePrefix Readonly @@ -106,7 +97,7 @@ false false - 00h17000007ebex + 00h1F000005cUjP 4 0 Default diff --git a/nebula-logger/plugins/log-retention-rules/plugin/layouts/LogRetentionRule__mdt-Log Retention Rule Layout.layout-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/layouts/LogRetentionRule__mdt-Log Retention Rule Layout.layout-meta.xml new file mode 100644 index 000000000..958d04dad --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/layouts/LogRetentionRule__mdt-Log Retention Rule Layout.layout-meta.xml @@ -0,0 +1,116 @@ + + + + false + true + true + + + + Required + MasterLabel + + + Required + DeveloperName + + + + + Edit + IsEnabled__c + + + Edit + ExecutionOrder__c + + + + + + true + true + true + + + + Edit + NumberOfDaysToRetainLogs__c + + + + + Required + ConditionLogicType__c + + + Edit + CustomConditionLogic__c + + + + + + false + true + true + + + + Edit + IsProtected + + + Readonly + CreatedById + + + + + Edit + NamespacePrefix + + + Readonly + LastModifiedById + + + + + + true + true + false + + + + + + + + NumberOfDaysToRetainLogs__c + + + MasterLabel + DeveloperName + SortOrder__c + FieldPath__c + Operator__c + ValueType__c + Value__c + LogRetentionRuleCondition__mdt.LogRetentionRule__c + SortOrder__c + Asc + + false + false + false + false + false + + 00h17000007xeHS + 4 + 0 + Default + + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/LogRetentionRuleCondition__mdt.object-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/LogRetentionRuleCondition__mdt.object-meta.xml new file mode 100644 index 000000000..24cdcfb5d --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/LogRetentionRuleCondition__mdt.object-meta.xml @@ -0,0 +1,8 @@ + + + Used to configure field-level conditions for retention rules - each condition checks a LogEntry__c or Log__c field for a specific value, regular expression (regex), or field comparisons. + + Log Retention Rule Conditions + Public + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/FieldPath__c.field-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/FieldPath__c.field-meta.xml new file mode 100644 index 000000000..4724e4a9e --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/FieldPath__c.field-meta.xml @@ -0,0 +1,12 @@ + + + FieldPath__c + false + SubscriberControlled + The API name of the LogEntryEvent__e field. Note: parent field, such as CreatedBy.Name, are not supported. + + 255 + true + Text + false + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/LogRetentionRule__c.field-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/LogRetentionRule__c.field-meta.xml new file mode 100644 index 000000000..d89974c73 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/LogRetentionRule__c.field-meta.xml @@ -0,0 +1,13 @@ + + + LogRetentionRule__c + false + SubscriberControlled + + LogRetentionRule__mdt + Log Retention Rule Conditions + LogRetentionRuleConditions + true + MetadataRelationship + false + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/Operator__c.field-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/Operator__c.field-meta.xml new file mode 100644 index 000000000..b62486bba --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/Operator__c.field-meta.xml @@ -0,0 +1,60 @@ + + + Operator__c + false + SubscriberControlled + + true + Picklist + + true + + false + + EQUAL_TO + false + + + + NOT_EQUAL_TO + false + + + + LESS_THAN + false + + + + GREATER_THAN + false + + + + LESS_THAN_OR_EQUAL_TO + false + + + + GREATER_THAN_OR_EQUAL_TO + false + + + + STARTS_WITH + false + + + + CONTAINS + false + + + + ENDS_WITH + false + + + + + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/SortOrder__c.field-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/SortOrder__c.field-meta.xml new file mode 100644 index 000000000..78d7b35b1 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/SortOrder__c.field-meta.xml @@ -0,0 +1,12 @@ + + + SortOrder__c + false + SubscriberControlled + + 3 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/ValueType__c.field-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/ValueType__c.field-meta.xml new file mode 100644 index 000000000..54ea1d6d1 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/ValueType__c.field-meta.xml @@ -0,0 +1,30 @@ + + + ValueType__c + false + SubscriberControlled + + true + Picklist + + true + + false + + Value + false + + + + Field + false + + + + RegEx + false + + + + + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/Value__c.field-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/Value__c.field-meta.xml new file mode 100644 index 000000000..0e1738715 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/fields/Value__c.field-meta.xml @@ -0,0 +1,11 @@ + + + Value__c + false + SubscriberControlled + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/listViews/All.listView-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/listViews/All.listView-meta.xml new file mode 100644 index 000000000..0b411c06f --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRuleCondition__mdt/listViews/All.listView-meta.xml @@ -0,0 +1,14 @@ + + + All + MasterLabel + DeveloperName + LogRetentionRule__c + SortOrder__c + FieldPath__c + Operator__c + ValueType__c + Value__c + Everything + + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/LogRetentionRule__mdt.object-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/LogRetentionRule__mdt.object-meta.xml new file mode 100644 index 000000000..95a15408d --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/LogRetentionRule__mdt.object-meta.xml @@ -0,0 +1,8 @@ + + + Used to configure rules that set the value of Log__c.LogRetentionDate__c. Each rules consists of 1 or more conditions, stored in LogRetentionRuleCondition__mdt. + + Log Retention Rules + Public + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/fields/ConditionLogicType__c.field-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/fields/ConditionLogicType__c.field-meta.xml new file mode 100644 index 000000000..e122b5298 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/fields/ConditionLogicType__c.field-meta.xml @@ -0,0 +1,30 @@ + + + ConditionLogicType__c + false + SubscriberControlled + + true + Picklist + + true + + false + + AND + false + + + + OR + false + + + + Custom + false + + + + + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/fields/CustomConditionLogic__c.field-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/fields/CustomConditionLogic__c.field-meta.xml new file mode 100644 index 000000000..cb30f8610 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/fields/CustomConditionLogic__c.field-meta.xml @@ -0,0 +1,11 @@ + + + CustomConditionLogic__c + false + SubscriberControlled + + 255 + false + Text + false + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/fields/ExecutionOrder__c.field-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/fields/ExecutionOrder__c.field-meta.xml new file mode 100644 index 000000000..d37bda01f --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/fields/ExecutionOrder__c.field-meta.xml @@ -0,0 +1,14 @@ + + + ExecutionOrder__c + false + SubscriberControlled + The specific order to execute the retention rules in the org. Rules are executed in order by sorting by execution order, then rule name (ORDER BY ExecutionOrder__c NULLS LAST, DeveloperName). In the event that multiple rules apply to a record, the first matching rule is used to set the log retention date. + + 3 + false + 0 + Number + false + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/fields/IsEnabled__c.field-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/fields/IsEnabled__c.field-meta.xml new file mode 100644 index 000000000..7c3dca299 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/fields/IsEnabled__c.field-meta.xml @@ -0,0 +1,9 @@ + + + IsEnabled__c + true + false + SubscriberControlled + + Checkbox + diff --git a/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/fields/NumberOfDaysToRetainLogs__c.field-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/fields/NumberOfDaysToRetainLogs__c.field-meta.xml new file mode 100644 index 000000000..613a84788 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/fields/NumberOfDaysToRetainLogs__c.field-meta.xml @@ -0,0 +1,14 @@ + + + NumberOfDaysToRetainLogs__c + false + SubscriberControlled + This value is used to set the field Log__c.LogRetentionDate__c, which is then used by LogBatchPurger to delete old logs. To keep logs indefinitely, set this field to blank (null). + + 18 + false + 0 + Number + false + diff --git a/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/listViews/All.listView-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/listViews/All.listView-meta.xml similarity index 69% rename from nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/listViews/All.listView-meta.xml rename to nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/listViews/All.listView-meta.xml index eaa65e95c..ab54559ea 100644 --- a/nebula-logger/core/main/plugin-framework/objects/LoggerPlugin__mdt/listViews/All.listView-meta.xml +++ b/nebula-logger/plugins/log-retention-rules/plugin/objects/LogRetentionRule__mdt/listViews/All.listView-meta.xml @@ -4,11 +4,10 @@ MasterLabel DeveloperName IsEnabled__c + ConditionLogicType__c + CustomConditionLogic__c + NumberOfDaysToRetainLogs__c ExecutionOrder__c - SObjectType__c - PluginType__c - PluginApiName__c - Description__c Everything diff --git a/nebula-logger/plugins/log-retention-rules/plugin/testSuites/LoggerLogRetentionRulesPlugin.testSuite-meta.xml b/nebula-logger/plugins/log-retention-rules/plugin/testSuites/LoggerLogRetentionRulesPlugin.testSuite-meta.xml new file mode 100644 index 000000000..aa8f4f1c9 --- /dev/null +++ b/nebula-logger/plugins/log-retention-rules/plugin/testSuites/LoggerLogRetentionRulesPlugin.testSuite-meta.xml @@ -0,0 +1,5 @@ + + + LogRetentionFilter_Tests + LogRetentionRulesPlugin_Tests + diff --git a/nebula-logger/plugins/Slack/images/btn-install-unlocked-package-plugin.png b/nebula-logger/plugins/logger-admin-dashboard/.images/btn-install-unlocked-package-plugin.png similarity index 100% rename from nebula-logger/plugins/Slack/images/btn-install-unlocked-package-plugin.png rename to nebula-logger/plugins/logger-admin-dashboard/.images/btn-install-unlocked-package-plugin.png diff --git a/nebula-logger/plugins/Logger-Admin-Dashboard/images/logger-admin-dashboard.png b/nebula-logger/plugins/logger-admin-dashboard/.images/logger-admin-dashboard.png similarity index 100% rename from nebula-logger/plugins/Logger-Admin-Dashboard/images/logger-admin-dashboard.png rename to nebula-logger/plugins/logger-admin-dashboard/.images/logger-admin-dashboard.png diff --git a/nebula-logger/plugins/Logger-Admin-Dashboard/README.md b/nebula-logger/plugins/logger-admin-dashboard/README.md similarity index 64% rename from nebula-logger/plugins/Logger-Admin-Dashboard/README.md rename to nebula-logger/plugins/logger-admin-dashboard/README.md index e5674cfbf..c463c7c88 100644 --- a/nebula-logger/plugins/Logger-Admin-Dashboard/README.md +++ b/nebula-logger/plugins/logger-admin-dashboard/README.md @@ -1,8 +1,8 @@ # Logger Admin Dashboard for Nebula Logger -> :information_source: Requires Nebula Logger v4.6.12 or newer +> :information_source: This plugin requires `v4.6.12` or newer of Nebula Logger's unlocked package -[![Install Unlocked Package Plugin](./images/btn-install-unlocked-package-plugin.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015l3yQAA) +[![Install Unlocked Package Plugin](../.images/btn-install-unlocked-package-plugin-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015l3yQAA) To help monitor logs in your org, this plugin includes a new Logger Admin dynamic dashboard, as well as several new reports. The dashboard displays several report charts to quickly see summary info about your logs. It supports filtering on: diff --git a/nebula-logger/plugins/Logger-Admin-Dashboard/plugin/dashboards/LogDashboards.dashboardFolder-meta.xml b/nebula-logger/plugins/logger-admin-dashboard/plugin/dashboards/LogDashboards.dashboardFolder-meta.xml similarity index 100% rename from nebula-logger/plugins/Logger-Admin-Dashboard/plugin/dashboards/LogDashboards.dashboardFolder-meta.xml rename to nebula-logger/plugins/logger-admin-dashboard/plugin/dashboards/LogDashboards.dashboardFolder-meta.xml diff --git a/nebula-logger/plugins/Logger-Admin-Dashboard/plugin/dashboards/LogDashboards/LoggerAdmin.dashboard-meta.xml b/nebula-logger/plugins/logger-admin-dashboard/plugin/dashboards/LogDashboards/LoggerAdmin.dashboard-meta.xml similarity index 99% rename from nebula-logger/plugins/Logger-Admin-Dashboard/plugin/dashboards/LogDashboards/LoggerAdmin.dashboard-meta.xml rename to nebula-logger/plugins/logger-admin-dashboard/plugin/dashboards/LogDashboards/LoggerAdmin.dashboard-meta.xml index e0d4d6f2f..55ee66a79 100644 --- a/nebula-logger/plugins/Logger-Admin-Dashboard/plugin/dashboards/LogDashboards/LoggerAdmin.dashboard-meta.xml +++ b/nebula-logger/plugins/logger-admin-dashboard/plugin/dashboards/LogDashboards/LoggerAdmin.dashboard-meta.xml @@ -335,6 +335,7 @@ LoggedInUser true + test-ghsv1imtoehu@example.com #000000 Logger Admin Dashboard #000000 diff --git a/nebula-logger/plugins/Logger-Admin-Dashboard/plugin/reports/LogReports/LogEntryDailyRetentionSummary.report-meta.xml b/nebula-logger/plugins/logger-admin-dashboard/plugin/reports/LogReports/LogEntryDailyRetentionSummary.report-meta.xml similarity index 100% rename from nebula-logger/plugins/Logger-Admin-Dashboard/plugin/reports/LogReports/LogEntryDailyRetentionSummary.report-meta.xml rename to nebula-logger/plugins/logger-admin-dashboard/plugin/reports/LogReports/LogEntryDailyRetentionSummary.report-meta.xml diff --git a/nebula-logger/plugins/Logger-Admin-Dashboard/plugin/reports/LogReports/LogEntryDailySummary.report-meta.xml b/nebula-logger/plugins/logger-admin-dashboard/plugin/reports/LogReports/LogEntryDailySummary.report-meta.xml similarity index 100% rename from nebula-logger/plugins/Logger-Admin-Dashboard/plugin/reports/LogReports/LogEntryDailySummary.report-meta.xml rename to nebula-logger/plugins/logger-admin-dashboard/plugin/reports/LogReports/LogEntryDailySummary.report-meta.xml diff --git a/nebula-logger/plugins/Logger-Admin-Dashboard/plugin/reports/LogReports/LogEntryOriginSummary.report-meta.xml b/nebula-logger/plugins/logger-admin-dashboard/plugin/reports/LogReports/LogEntryOriginSummary.report-meta.xml similarity index 100% rename from nebula-logger/plugins/Logger-Admin-Dashboard/plugin/reports/LogReports/LogEntryOriginSummary.report-meta.xml rename to nebula-logger/plugins/logger-admin-dashboard/plugin/reports/LogReports/LogEntryOriginSummary.report-meta.xml diff --git a/nebula-logger/plugins/Logger-Admin-Dashboard/plugin/reports/LogReports/LogEntryScenarioSummary.report-meta.xml b/nebula-logger/plugins/logger-admin-dashboard/plugin/reports/LogReports/LogEntryScenarioSummary.report-meta.xml similarity index 100% rename from nebula-logger/plugins/Logger-Admin-Dashboard/plugin/reports/LogReports/LogEntryScenarioSummary.report-meta.xml rename to nebula-logger/plugins/logger-admin-dashboard/plugin/reports/LogReports/LogEntryScenarioSummary.report-meta.xml diff --git a/nebula-logger/plugins/Logger-Admin-Dashboard/plugin/reports/LogReports/LogEntrySummary.report-meta.xml b/nebula-logger/plugins/logger-admin-dashboard/plugin/reports/LogReports/LogEntrySummary.report-meta.xml similarity index 100% rename from nebula-logger/plugins/Logger-Admin-Dashboard/plugin/reports/LogReports/LogEntrySummary.report-meta.xml rename to nebula-logger/plugins/logger-admin-dashboard/plugin/reports/LogReports/LogEntrySummary.report-meta.xml diff --git a/nebula-logger/plugins/Slack/images/slack-plugin-notification.png b/nebula-logger/plugins/slack/.images/slack-plugin-notification.png similarity index 100% rename from nebula-logger/plugins/Slack/images/slack-plugin-notification.png rename to nebula-logger/plugins/slack/.images/slack-plugin-notification.png diff --git a/nebula-logger/plugins/Slack/images/slack-plugin-parameters.png b/nebula-logger/plugins/slack/.images/slack-plugin-parameters.png similarity index 100% rename from nebula-logger/plugins/Slack/images/slack-plugin-parameters.png rename to nebula-logger/plugins/slack/.images/slack-plugin-parameters.png diff --git a/nebula-logger/plugins/Slack/README.md b/nebula-logger/plugins/slack/README.md similarity index 79% rename from nebula-logger/plugins/Slack/README.md rename to nebula-logger/plugins/slack/README.md index 7f5c5646c..07fdb637f 100644 --- a/nebula-logger/plugins/Slack/README.md +++ b/nebula-logger/plugins/slack/README.md @@ -1,8 +1,10 @@ # Slack plugin for Nebula Logger -Adds a Slack integration for the unlocked package edition of Nebula Logger v4.6.9 or newer. Any logs with log entries that meet a certain (configurable) logging level will automatically be posted to your Slack channel via an asynchronous `Queueable` job. +> :information_source: This plugin requires `v4.7.1` or newer of Nebula Logger's unlocked package -[![Install Unlocked Package](./images/btn-install-unlocked-package-plugin.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015l2WQAQ) +[![Install Unlocked Package](../.images/btn-install-unlocked-package-plugin-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y0000015lgQQAQ) + +Adds a Slack integration for the unlocked package edition of Nebula Logger. Any logs with log entries that meet a certain (configurable) logging level will automatically be posted to your Slack channel via an asynchronous `Queueable` job. ![Slack plugin: notification](./images/slack-plugin-notification.png) @@ -10,13 +12,13 @@ Adds a Slack integration for the unlocked package edition of Nebula Logger v4.6. ## What's Included -This plugin includes some add-on metadata for Logger to support the Slack integration +This plugin includes some add-on metadata for Nebula Logger to support the Slack integration 1. Apex class `SlackLoggerPlugin` and corresponding tests in `SlackLoggerPlugin_Tests` 2. Plugin configuration details stored in Logger's CMDT objects `LoggerPlugin__mdt` and `LoggerParameter__mdt` 3. Custom fields `Log__c.SendSlackNotification__c` and `Log__c.SlackNotificationDate__c` 4. Field-level security (FLS) via a new permission set `LoggerSlackPluginAdmin` to provide access to the custom Slack fields -5. Custom list views for the `Log__c` and `LoggerParameter__mdt` objects +5. Two custom list views for the `Log__c` object to see any `Log__c` records that have, or should be, sent to Slack 6. Remote site setting for Slack's API --- diff --git a/nebula-logger/plugins/Slack/plugin/core/main/README.md b/nebula-logger/plugins/slack/plugin/core/main/README.md similarity index 100% rename from nebula-logger/plugins/Slack/plugin/core/main/README.md rename to nebula-logger/plugins/slack/plugin/core/main/README.md diff --git a/nebula-logger/plugins/Slack/plugin/core/main/log-management/objects/Log__c/fields/SendSlackNotification__c.field-meta.xml b/nebula-logger/plugins/slack/plugin/core/main/log-management/objects/Log__c/fields/SendSlackNotification__c.field-meta.xml similarity index 100% rename from nebula-logger/plugins/Slack/plugin/core/main/log-management/objects/Log__c/fields/SendSlackNotification__c.field-meta.xml rename to nebula-logger/plugins/slack/plugin/core/main/log-management/objects/Log__c/fields/SendSlackNotification__c.field-meta.xml diff --git a/nebula-logger/plugins/Slack/plugin/core/main/log-management/objects/Log__c/fields/SlackNotificationDate__c.field-meta.xml b/nebula-logger/plugins/slack/plugin/core/main/log-management/objects/Log__c/fields/SlackNotificationDate__c.field-meta.xml similarity index 100% rename from nebula-logger/plugins/Slack/plugin/core/main/log-management/objects/Log__c/fields/SlackNotificationDate__c.field-meta.xml rename to nebula-logger/plugins/slack/plugin/core/main/log-management/objects/Log__c/fields/SlackNotificationDate__c.field-meta.xml diff --git a/nebula-logger/plugins/Slack/plugin/core/main/log-management/objects/Log__c/listViews/AllLogsSentToSlack.listView-meta.xml b/nebula-logger/plugins/slack/plugin/core/main/log-management/objects/Log__c/listViews/AllLogsSentToSlack.listView-meta.xml similarity index 100% rename from nebula-logger/plugins/Slack/plugin/core/main/log-management/objects/Log__c/listViews/AllLogsSentToSlack.listView-meta.xml rename to nebula-logger/plugins/slack/plugin/core/main/log-management/objects/Log__c/listViews/AllLogsSentToSlack.listView-meta.xml diff --git a/nebula-logger/plugins/Slack/plugin/core/main/log-management/objects/Log__c/listViews/AllLogsToBeSentToSlack.listView-meta.xml b/nebula-logger/plugins/slack/plugin/core/main/log-management/objects/Log__c/listViews/AllLogsToBeSentToSlack.listView-meta.xml similarity index 100% rename from nebula-logger/plugins/Slack/plugin/core/main/log-management/objects/Log__c/listViews/AllLogsToBeSentToSlack.listView-meta.xml rename to nebula-logger/plugins/slack/plugin/core/main/log-management/objects/Log__c/listViews/AllLogsToBeSentToSlack.listView-meta.xml diff --git a/nebula-logger/plugins/Slack/plugin/slack/classes/SlackLoggerPlugin.cls b/nebula-logger/plugins/slack/plugin/slack/classes/SlackLoggerPlugin.cls similarity index 77% rename from nebula-logger/plugins/Slack/plugin/slack/classes/SlackLoggerPlugin.cls rename to nebula-logger/plugins/slack/plugin/slack/classes/SlackLoggerPlugin.cls index 37c2228d6..5fc0dc945 100644 --- a/nebula-logger/plugins/Slack/plugin/slack/classes/SlackLoggerPlugin.cls +++ b/nebula-logger/plugins/slack/plugin/slack/classes/SlackLoggerPlugin.cls @@ -8,16 +8,14 @@ * @description Optional plugin that integrates with Slack to send alerts for important logs */ @SuppressWarnings('PMD.ExcessivePublicCount') -public without sharing class SlackLoggerPlugin extends LoggerSObjectHandlerPlugin implements Queueable, Database.AllowsCallouts { +public without sharing class SlackLoggerPlugin implements LoggerPlugin.Triggerable, Queueable, Database.AllowsCallouts { @TestVisible - private static String endpoint = LoggerParameter.getString('SlackEndpoint', null); + private static final String ENDPOINT = LoggerParameter.getString('SlackEndpoint', null); @TestVisible - private static LoggingLevel notificationLoggingLevel = Logger.getLoggingLevel(LoggerParameter.getString('SlackNotificationLoggingLevel', null)); + private static final LoggingLevel NOTIFICATION_LOGGING_LEVEL = Logger.getLoggingLevel(LoggerParameter.getString('SlackNotificationLoggingLevel', null)); private List logs; - // Constructors - /** * @description Default constructor */ @@ -30,27 +28,20 @@ public without sharing class SlackLoggerPlugin extends LoggerSObjectHandlerPlugi this.logs = unsentLogs; } - // Instance methods - /** - * @description Handles the queuable execute logic. - * @param triggerOperationType Defines the trigger operation type - * @param triggerNew contains a list of the new trigger context / records. - * @param triggerNewMap contains a map of ids to new trigger records. - * @param triggerOld old contains a list of the old trigger context / records. - * @param triggerOldMap contains a map of ids to old trigger records. + * @description Handles the integration with Slack. This method is automatically called by Nebula Logger's plugin framework. + * @param configuration The instance of `LoggerPlugin__mdt` configured for this specific plugin + * @param input The instance of `LoggerTriggerableContext`, provided by the logging system */ @SuppressWarnings('PMD.ExcessiveParameterList') - public override void execute( - TriggerOperation triggerOperationType, - List triggerNew, - Map triggerNewMap, - List triggerOld, - Map triggerOldMap - ) { - this.logs = (List) triggerNew; - - switch on triggerOperationType { + public void execute(LoggerPlugin__mdt configuration, LoggerTriggerableContext input) { + if (input.sobjectType != Schema.Log__c.SObjectType || String.isBlank(ENDPOINT) == true) { + return; + } + + this.logs = (List) input.triggerNew; + + switch on input.triggerOperationType { when BEFORE_INSERT, BEFORE_UPDATE { this.flagLogsForSlackNotification(); } @@ -66,7 +57,7 @@ public without sharing class SlackLoggerPlugin extends LoggerSObjectHandlerPlugi */ @SuppressWarnings('PMD.AvoidDebugStatements') public void execute(System.QueueableContext queueableContext) { - // SInce this runs in an async context, requery the logs just in case any field values have changed + // Since this runs in an async context, requery the logs just in case any field values have changed this.requeryLogs(); if (this.logs.isEmpty() == true) { @@ -90,15 +81,20 @@ public without sharing class SlackLoggerPlugin extends LoggerSObjectHandlerPlugi // 'Short' is a reserved word in Apex, but used in Slack's API, so the conversion happens in JSON String notificationJson = JSON.serialize(notification).replace('"isShort"', '"short"'); request.setBody(notificationJson); + if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { + Logger.finest('Sending log entries to Slack endpoint').setHttpRequestDetails(request); + } HttpResponse response = new Http().send(request); - System.debug(notificationLoggingLevel, 'response.getStatusCode()==' + response.getStatusCode()); - System.debug(notificationLoggingLevel, 'response.getStatus()==' + response.getStatus()); + if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { + Logger.finest('Sent log entries to Slack endpoint').setHttpResponseDetails(response); + } log.SlackNotificationDate__c = System.now(); sentLogs.add(log); } } + Logger.saveLog(); update sentLogs; // If any logs couldn't be sent due to governor limits, start a new instance of the job @@ -108,12 +104,12 @@ public without sharing class SlackLoggerPlugin extends LoggerSObjectHandlerPlugi } private void flagLogsForSlackNotification() { - if (notificationLoggingLevel == null) { + if (NOTIFICATION_LOGGING_LEVEL == null) { return; } for (Log__c log : this.logs) { - if (log.MaxLogEntryLoggingLevelOrdinal__c >= notificationLoggingLevel.ordinal()) { + if (log.MaxLogEntryLoggingLevelOrdinal__c >= NOTIFICATION_LOGGING_LEVEL.ordinal()) { log.SendSlackNotification__c = true; } } @@ -161,33 +157,35 @@ public without sharing class SlackLoggerPlugin extends LoggerSObjectHandlerPlugi TotalWARNLogEntries__c, TransactionId__c, ( - SELECT Id, LoggingLevel__c, Message__c + SELECT Id, LoggingLevel__c, Message__c, ExceptionStackTrace__c, StackTrace__c FROM LogEntries__r - WHERE LoggingLevelOrdinal__c >= :notificationLoggingLevel.ordinal() + WHERE LoggingLevelOrdinal__c >= :NOTIFICATION_LOGGING_LEVEL.ordinal() ORDER BY Timestamp__c DESC LIMIT 1 ) FROM Log__c WHERE Id IN :this.logs - AND MaxLogEntryLoggingLevelOrdinal__c >= :notificationLoggingLevel.ordinal() + AND MaxLogEntryLoggingLevelOrdinal__c >= :NOTIFICATION_LOGGING_LEVEL.ordinal() AND SendSlackNotification__c = TRUE AND SlackNotificationDate__c = NULL ]; } - @SuppressWarnings('PMD.AvoidDebugStatements') private HttpRequest createSlackHttpRequest() { - System.debug(notificationLoggingLevel, 'endpoint==' + endpoint); - HttpRequest request = new HttpRequest(); - request.setEndpoint(endpoint); + request.setEndpoint(ENDPOINT); request.setMethod('POST'); request.setHeader('Content-Type', 'application/json'); + if (LoggerParameter.ENABLE_SYSTEM_MESSAGES == true) { + Logger.finest('Created Slack HTTP Request').setHttpRequestDetails(request); + } + return request; } + @SuppressWarnings('PMD.NcssMethodCount') private LogDto convertLog(Log__c log) { LogEntry__c lastLogEntry = log.LogEntries__r.get(0); String messageText = 'Last Log Entry Message' + '\n`' + lastLogEntry.LoggingLevel__c + ': ' + lastLogEntry.Message__c + '`'; @@ -201,6 +199,20 @@ public without sharing class SlackLoggerPlugin extends LoggerSObjectHandlerPlugi notification.title = log.Name; notification.title_link = Url.getSalesforceBaseUrl().toExternalForm() + '/' + log.Id; + if (String.isNotBlank(lastLogEntry.ExceptionStackTrace__c) == true) { + FieldDto exceptionStackTraceField = new FieldDto(); + exceptionStackTraceField.isShort = false; + exceptionStackTraceField.title = Schema.LogEntry__c.ExceptionStackTrace__c.getDescribe().getLabel(); + exceptionStackTraceField.value = '`' + lastLogEntry.ExceptionStackTrace__c + '`'; + notification.fields.add(exceptionStackTraceField); + } + + FieldDto stackTraceField = new FieldDto(); + stackTraceField.isShort = false; + stackTraceField.title = Schema.LogEntry__c.StackTrace__c.getDescribe().getLabel(); + stackTraceField.value = '`' + lastLogEntry.StackTrace__c + '`'; + notification.fields.add(stackTraceField); + // TODO: switch to dynamically creating Slack DTO fields based on a new `Log__c` field set parameter FieldDto startTimeField = new FieldDto(); startTimeField.isShort = true; @@ -226,6 +238,8 @@ public without sharing class SlackLoggerPlugin extends LoggerSObjectHandlerPlugi totalWARNEntriesField.value = '`' + String.valueOf(log.TotalWARNLogEntries__c) + '`'; notification.fields.add(totalWARNEntriesField); + // TODO Add Scenario__c field + String logOwnerType = log.OwnerId.getSObjectType().getDescribe().getName(); FieldDto logOwnerNameField = new FieldDto(); logOwnerNameField.isShort = true; @@ -263,20 +277,7 @@ public without sharing class SlackLoggerPlugin extends LoggerSObjectHandlerPlugi orgApiVersion.value = '`' + log.ApiVersion__c + '`'; notification.fields.add(orgApiVersion); - List topicNames = new List(); - // TODO - dynamically get either LogEntryTag__c or TopicAssignment (based on handler parameter) - for (TopicAssignment topicAssignment : log.TopicAssignments) { - topicNames.add(topicAssignment.Topic.Name); - } - topicNames.sort(); - - if (topicNames.isEmpty() == false) { - FieldDto topicsField = new FieldDto(); - topicsField.isShort = false; - topicsField.title = 'Topics'; - topicsField.value = '`' + String.join(topicNames, '`, `') + '`'; - notification.fields.add(topicsField); - } + // TODO Possible include to LogEntryTag__c (tag names) return notification; } diff --git a/nebula-logger/plugins/slack/plugin/slack/classes/SlackLoggerPlugin.cls-meta.xml b/nebula-logger/plugins/slack/plugin/slack/classes/SlackLoggerPlugin.cls-meta.xml new file mode 100644 index 000000000..871a8cfea --- /dev/null +++ b/nebula-logger/plugins/slack/plugin/slack/classes/SlackLoggerPlugin.cls-meta.xml @@ -0,0 +1,5 @@ + + + 53.0 + Active + diff --git a/nebula-logger/plugins/slack/plugin/slack/classes/SlackLoggerPlugin_Tests.cls b/nebula-logger/plugins/slack/plugin/slack/classes/SlackLoggerPlugin_Tests.cls new file mode 100644 index 000000000..555548494 --- /dev/null +++ b/nebula-logger/plugins/slack/plugin/slack/classes/SlackLoggerPlugin_Tests.cls @@ -0,0 +1,229 @@ +//------------------------------------------------------------------------------------------------// +// This file is part of the Nebula Logger project, released under the MIT License. // +// See LICENSE file or go to https://github.com/jongpie/NebulaLogger for full license details. // +//------------------------------------------------------------------------------------------------// + +@SuppressWarnings('PMD.ApexDoc, PMD.MethodNamingConventions') +@IsTest(IsParallel=true) +private class SlackLoggerPlugin_Tests { + @IsTest + static void it_should_not_push_log_when_logging_level_is_not_met() { + verifyLogEntryCountEquals(0); + Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), SendSlackNotification__c = false, TransactionId__c = '1234'); + insert log; + LoggingLevel logEntryLoggingLevel = LoggingLevel.WARN; + LogEntry__c logEntry = new LogEntry__c( + ExceptionStackTrace__c = 'Some exception stack trace', + Log__c = log.Id, + LoggingLevel__c = logEntryLoggingLevel.name(), + LoggingLevelOrdinal__c = logEntryLoggingLevel.ordinal(), + StackTrace__c = 'A stack trace', + Timestamp__c = System.now() + ); + insert logEntry; + verifyLogEntryCountEquals(1); + List logs = queryLogs(logEntryLoggingLevel); + System.assertEquals(1, logs.size(), 'Logs size did not match expected value of 1.'); + log = logs.get(0); + System.assertEquals(1, log.LogEntries__r.size(), 'Log entries size was not equal to 1.'); + System.assertEquals(false, log.SendSlackNotification__c, 'SendSlackNotification was incorrectly set to true.'); + System.assertEquals(null, log.SlackNotificationDate__c, 'SlackNotificationDate was not null.'); + Test.startTest(); + LoggerMockDataCreator.MockHttpCallout calloutMock = LoggerMockDataCreator.createHttpCallout().setStatusCode(200); + Test.setMock(HttpCalloutMock.class, calloutMock); + // Load the mock configurations - the plugin framework won't load actual CMDT records during tests + LoggingLevel slackLoggingLevel = LoggingLevel.ERROR; + System.assert(logEntryLoggingLevel.ordinal() < slackLoggingLevel.ordinal(), 'Slack logging level ordinal was incorrect.'); + mockConfigurations(slackLoggingLevel); + System.assert(logEntryLoggingLevel.ordinal() < SlackLoggerPlugin.NOTIFICATION_LOGGING_LEVEL.ordinal(), 'Slack logging level ordinal was incorrect.'); + LoggerSObjectHandler.shouldExecute(true); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + + // Update the records to trigger the handler framework, which will then run the Slack plugin + update log; + + // Verify that the internal queueable job has been enqueued + System.assertEquals(0, Limits.getAsyncCalls(), 'The queueable job should not have been enqueued'); + // Stop the test so the internal queueable job runs + Test.stopTest(); + log = queryLogs(logEntryLoggingLevel).get(0); + System.assertEquals(1, log.LogEntries__r.size(), 'Log entries size was not equal to 1.'); + System.assertEquals(false, log.SendSlackNotification__c, 'SendSlackNotification incorrectly set to true.'); + System.assertEquals(null, log.SlackNotificationDate__c, 'SlackNotificationDate was not null.'); + } + + @IsTest + static void it_should_push_log_when_logging_level_is_met_for_error() { + verifyLogEntryCountEquals(0); + LoggerSObjectHandler.shouldExecute(false); + Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), SendSlackNotification__c = false, TransactionId__c = '1234'); + insert log; + LoggingLevel logEntryLoggingLevel = LoggingLevel.ERROR; + LogEntry__c logEntry = new LogEntry__c( + ExceptionStackTrace__c = 'Some exception stack trace', + Log__c = log.Id, + LoggingLevel__c = logEntryLoggingLevel.name(), + LoggingLevelOrdinal__c = logEntryLoggingLevel.ordinal(), + StackTrace__c = 'A stack trace', + Timestamp__c = System.now() + ); + insert logEntry; + verifyLogEntryCountEquals(1); + List logs = queryLogs(logEntryLoggingLevel); + System.assertEquals(1, logs.size(), 'Logs size did not match expected value of 1.'); + log = logs.get(0); + System.assertEquals(1, log.LogEntries__r.size(), 'Log entries did not match the expected count of 1.'); + System.assertEquals(false, log.SendSlackNotification__c, 'SendSlackNotification was incorrectly set to true.'); + System.assertEquals(null, log.SlackNotificationDate__c, 'SlackNotificationDate was not null.'); + Test.startTest(); + LoggerMockDataCreator.MockHttpCallout calloutMock = LoggerMockDataCreator.createHttpCallout().setStatusCode(200); + Test.setMock(HttpCalloutMock.class, calloutMock); + // Load the mock configurations - the plugin framework won't load actual CMDT records during tests + mockConfigurations(logEntryLoggingLevel); + System.assert( + logEntryLoggingLevel.ordinal() >= SlackLoggerPlugin.NOTIFICATION_LOGGING_LEVEL.ordinal(), + 'The notification logging level ordinal was incorrect.' + ); + LoggerSObjectHandler.shouldExecute(true); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + + // Update the records to trigger the handler framework, which will then run the Slack plugin + update log; + + // Verify that the internal queueable job has been enqueued + System.assertEquals(1, Limits.getAsyncCalls(), 'The queueable job should have been enqueued'); + // Stop the test so the internal queueable job runs + Test.stopTest(); + log = [SELECT Id, MaxLogEntryLoggingLevelOrdinal__c, SendSlackNotification__c, SlackNotificationDate__c FROM Log__c]; + System.assertEquals(true, log.SendSlackNotification__c, 'SendSlackNotification was incorrectly set to false.'); + System.assertNotEquals(null, log.SlackNotificationDate__c, 'SlackNotificationDate was null.'); + System.assertEquals(System.today(), log.SlackNotificationDate__c.date(), 'SlackNotificationDate was not set to TODAY.'); + } + + @IsTest + static void it_should_push_log_when_logging_level_is_met_for_warn() { + verifyLogEntryCountEquals(0); + LoggerSObjectHandler.shouldExecute(false); + Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), SendSlackNotification__c = false, TransactionId__c = '1234'); + insert log; + LoggingLevel logEntryLoggingLevel = LoggingLevel.WARN; + LogEntry__c logEntry = new LogEntry__c( + ExceptionStackTrace__c = 'Some exception stack trace', + Log__c = log.Id, + LoggingLevel__c = logEntryLoggingLevel.name(), + LoggingLevelOrdinal__c = logEntryLoggingLevel.ordinal(), + StackTrace__c = 'A stack trace', + Timestamp__c = System.now() + ); + insert logEntry; + verifyLogEntryCountEquals(1); + List logs = queryLogs(logEntryLoggingLevel); + System.assertEquals(1, logs.size(), 'Logs size did not match expected value of 1.'); + log = logs.get(0); + System.assertEquals(1, log.LogEntries__r.size(), 'Log entries did not match the expected count of 1.'); + System.assertEquals(false, log.SendSlackNotification__c, 'SendSlackNotification was incorrectly set to true.'); + System.assertEquals(null, log.SlackNotificationDate__c, 'SlackNotificationDate was not null.'); + Test.startTest(); + LoggerMockDataCreator.MockHttpCallout calloutMock = LoggerMockDataCreator.createHttpCallout().setStatusCode(200); + Test.setMock(HttpCalloutMock.class, calloutMock); + // Load the mock configurations - the plugin framework won't load actual CMDT records during tests + mockConfigurations(logEntryLoggingLevel); + System.assert( + logEntryLoggingLevel.ordinal() >= SlackLoggerPlugin.NOTIFICATION_LOGGING_LEVEL.ordinal(), + 'The notification logging level ordinal was incorrect.' + ); + LoggerSObjectHandler.shouldExecute(true); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + + // Update the records to trigger the handler framework, which will then run the Slack plugin + update log; + + // Verify that the internal queueable job has been enqueued + System.assertEquals(1, Limits.getAsyncCalls(), 'The queueable job should have been enqueued'); + // Stop the test so the internal queueable job runs + Test.stopTest(); + log = [SELECT Id, MaxLogEntryLoggingLevelOrdinal__c, SendSlackNotification__c, SlackNotificationDate__c FROM Log__c]; + System.assertEquals(true, log.SendSlackNotification__c, 'SendSlackNotification was incorrectly set to false.'); + System.assertNotEquals(null, log.SlackNotificationDate__c, 'SlackNotificationDate was null.'); + System.assertEquals(System.today(), log.SlackNotificationDate__c.date(), 'SlackNotificationDate was not set to TODAY.'); + } + + @IsTest + static void it_should_push_log_when_logging_level_is_met_for_info() { + verifyLogEntryCountEquals(0); + LoggerSObjectHandler.shouldExecute(false); + Log__c log = new Log__c(LoggedBy__c = UserInfo.getUserId(), SendSlackNotification__c = false, TransactionId__c = '1234'); + insert log; + LoggingLevel logEntryLoggingLevel = LoggingLevel.INFO; + LogEntry__c logEntry = new LogEntry__c( + ExceptionStackTrace__c = 'Some exception stack trace', + Log__c = log.Id, + LoggingLevel__c = logEntryLoggingLevel.name(), + LoggingLevelOrdinal__c = logEntryLoggingLevel.ordinal(), + StackTrace__c = 'A stack trace', + Timestamp__c = System.now() + ); + insert logEntry; + verifyLogEntryCountEquals(1); + List logs = queryLogs(logEntryLoggingLevel); + System.assertEquals(1, logs.size(), 'Logs size did not match expected value of 1.'); + log = logs.get(0); + System.assertEquals(1, log.LogEntries__r.size(), 'Log entries did not match the expected count of 1.'); + System.assertEquals(false, log.SendSlackNotification__c, 'SendSlackNotification was incorrectly set to true.'); + System.assertEquals(null, log.SlackNotificationDate__c, 'SlackNotificationDate was not null.'); + Test.startTest(); + LoggerMockDataCreator.MockHttpCallout calloutMock = LoggerMockDataCreator.createHttpCallout().setStatusCode(200); + Test.setMock(HttpCalloutMock.class, calloutMock); + // Load the mock configurations - the plugin framework won't load actual CMDT records during tests + mockConfigurations(logEntryLoggingLevel); + System.assert( + logEntryLoggingLevel.ordinal() >= SlackLoggerPlugin.NOTIFICATION_LOGGING_LEVEL.ordinal(), + 'The notification logging level ordinal was incorrect.' + ); + LoggerSObjectHandler.shouldExecute(true); + LoggerTestConfigurator.setupMockSObjectHandlerConfigurations(); + + // Update the records to trigger the handler framework, which will then run the Slack plugin + update log; + + // Verify that the internal queueable job has been enqueued + System.assertEquals(1, Limits.getAsyncCalls(), 'The queueable job should have been enqueued'); + // Stop the test so the internal queueable job runs + Test.stopTest(); + log = [SELECT Id, MaxLogEntryLoggingLevelOrdinal__c, SendSlackNotification__c, SlackNotificationDate__c FROM Log__c]; + System.assertEquals(true, log.SendSlackNotification__c, 'SendSlackNotification was incorrectly set to false.'); + System.assertNotEquals(null, log.SlackNotificationDate__c, 'SlackNotificationDate was null.'); + System.assertEquals(System.today(), log.SlackNotificationDate__c.date(), 'SlackNotificationDate was not set to TODAY.'); + } + + static void mockConfigurations(LoggingLevel notificationLoggingLevel) { + LoggerTestConfigurator.setMock( + new LoggerPlugin__mdt(DeveloperName = 'SlackPlugin', IsEnabled__c = true, SObjectHandlerApexClass__c = SlackLoggerPlugin.class.getName()) + ); + LoggerTestConfigurator.setMock(new LoggerParameter__mdt(DeveloperName = 'SlackEndpoint', Value__c = 'https://fake.slack.com/')); + LoggerTestConfigurator.setMock(new LoggerParameter__mdt(DeveloperName = 'SlackNotificationLoggingLevel', Value__c = notificationLoggingLevel.name())); + } + + static void verifyLogEntryCountEquals(Integer expectedCount) { + Integer existingLogEntriesCount = [SELECT COUNT() FROM LogEntry__c]; + System.assertEquals(expectedCount, existingLogEntriesCount, 'Existing log entries did NOT match the expected count.'); + } + + static List queryLogs(LoggingLevel notificationLoggingLevel) { + return [ + SELECT + Id, + MaxLogEntryLoggingLevelOrdinal__c, + SendSlackNotification__c, + SlackNotificationDate__c, + ( + SELECT Id, LoggingLevel__c, Message__c, ExceptionStackTrace__c, StackTrace__c + FROM LogEntries__r + WHERE LoggingLevelOrdinal__c >= :notificationLoggingLevel.ordinal() + ORDER BY Timestamp__c DESC + LIMIT 1 + ) + FROM Log__c + ]; + } +} diff --git a/nebula-logger/plugins/slack/plugin/slack/classes/SlackLoggerPlugin_Tests.cls-meta.xml b/nebula-logger/plugins/slack/plugin/slack/classes/SlackLoggerPlugin_Tests.cls-meta.xml new file mode 100644 index 000000000..871a8cfea --- /dev/null +++ b/nebula-logger/plugins/slack/plugin/slack/classes/SlackLoggerPlugin_Tests.cls-meta.xml @@ -0,0 +1,5 @@ + + + 53.0 + Active + diff --git a/nebula-logger/plugins/Slack/plugin/slack/customMetadata/LoggerParameter.SlackEndpoint.md-meta.xml b/nebula-logger/plugins/slack/plugin/slack/customMetadata/LoggerParameter.SlackEndpoint.md-meta.xml similarity index 100% rename from nebula-logger/plugins/Slack/plugin/slack/customMetadata/LoggerParameter.SlackEndpoint.md-meta.xml rename to nebula-logger/plugins/slack/plugin/slack/customMetadata/LoggerParameter.SlackEndpoint.md-meta.xml diff --git a/nebula-logger/plugins/Slack/plugin/slack/customMetadata/LoggerParameter.SlackNotificationLoggingLevel.md-meta.xml b/nebula-logger/plugins/slack/plugin/slack/customMetadata/LoggerParameter.SlackNotificationLoggingLevel.md-meta.xml similarity index 100% rename from nebula-logger/plugins/Slack/plugin/slack/customMetadata/LoggerParameter.SlackNotificationLoggingLevel.md-meta.xml rename to nebula-logger/plugins/slack/plugin/slack/customMetadata/LoggerParameter.SlackNotificationLoggingLevel.md-meta.xml diff --git a/nebula-logger/plugins/slack/plugin/slack/customMetadata/LoggerPlugin.Slack.md-meta.xml b/nebula-logger/plugins/slack/plugin/slack/customMetadata/LoggerPlugin.Slack.md-meta.xml new file mode 100644 index 000000000..a3f0dadc5 --- /dev/null +++ b/nebula-logger/plugins/slack/plugin/slack/customMetadata/LoggerPlugin.Slack.md-meta.xml @@ -0,0 +1,51 @@ + + + + false + + BatchPurgerApexClass__c + + + + BatchPurgerExecutionOrder__c + + + + BatchPurgerFlowName__c + + + + Description__c + Adds a Slack integration for Nebula Logger. + +Any logs with MaxLogEntryLoggingLevelOrdinal__c >= the parameter 'SlackLoggingLevelThreshold' will send a notification to Slack + + + IsEnabled__c + true + + + Link__c + https://github.com/jongpie/NebulaLogger/tree/main/nebula-logger/plugins/Slack + + + SObjectHandlerApexClass__c + SlackLoggerPlugin + + + SObjectHandlerExecutionOrder__c + + + + SObjectHandlerFlowName__c + + + + VersionNumber__c + v0.9.0 + + diff --git a/nebula-logger/plugins/Slack/plugin/slack/permissionsets/LoggerSlackPluginAdmin.permissionset-meta.xml b/nebula-logger/plugins/slack/plugin/slack/permissionsets/LoggerSlackPluginAdmin.permissionset-meta.xml similarity index 100% rename from nebula-logger/plugins/Slack/plugin/slack/permissionsets/LoggerSlackPluginAdmin.permissionset-meta.xml rename to nebula-logger/plugins/slack/plugin/slack/permissionsets/LoggerSlackPluginAdmin.permissionset-meta.xml diff --git a/nebula-logger/plugins/Slack/plugin/slack/remoteSiteSettings/Slack.remoteSite-meta.xml b/nebula-logger/plugins/slack/plugin/slack/remoteSiteSettings/Slack.remoteSite-meta.xml similarity index 100% rename from nebula-logger/plugins/Slack/plugin/slack/remoteSiteSettings/Slack.remoteSite-meta.xml rename to nebula-logger/plugins/slack/plugin/slack/remoteSiteSettings/Slack.remoteSite-meta.xml diff --git a/nebula-logger/recipes/classes/ExampleBigObjectDataGenerator.cls b/nebula-logger/recipes/classes/ExampleBigObjectDataGenerator.cls new file mode 100644 index 000000000..0bab3522b --- /dev/null +++ b/nebula-logger/recipes/classes/ExampleBigObjectDataGenerator.cls @@ -0,0 +1,22 @@ +@SuppressWarnings('PMD.ApexDoc') +public with sharing class ExampleBigObjectDataGenerator implements System.Queueable { + private Integer targetRecordCountToCreate; + + public ExampleBigObjectDataGenerator(Integer targetRecordCountToCreate) { + this.targetRecordCountToCreate = targetRecordCountToCreate; + } + + public void execute(System.QueueableContext queueableContext) { + // Integer target = targetRecordCountToCreate <= 200 ? 200 : targetRecordCountToCreate; + for (Integer i = 0; i < 150; i++) { + Logger.info('hello, testing some bulk logging into big object via queueable job, record index is: ' + i); + this.targetRecordCountToCreate--; + } + Logger.getUserSettings().DefaultSaveMethod__c = 'BIG_OBJECT_IMMEDIATE'; + Logger.saveLog(); + + if (this.targetRecordCountToCreate > 0) { + System.enqueueJob(new ExampleBigObjectDataGenerator(this.targetRecordCountToCreate)); + } + } +} diff --git a/nebula-logger/recipes/classes/ExampleBigObjectDataGenerator.cls-meta.xml b/nebula-logger/recipes/classes/ExampleBigObjectDataGenerator.cls-meta.xml new file mode 100644 index 000000000..891916bb0 --- /dev/null +++ b/nebula-logger/recipes/classes/ExampleBigObjectDataGenerator.cls-meta.xml @@ -0,0 +1,5 @@ + + + 54.0 + Active + diff --git a/nebula-logger/recipes/profiles/Admin.profile-meta.xml b/nebula-logger/recipes/profiles/Admin.profile-meta.xml index 697fc95eb..949410f39 100644 --- a/nebula-logger/recipes/profiles/Admin.profile-meta.xml +++ b/nebula-logger/recipes/profiles/Admin.profile-meta.xml @@ -2,22 +2,9 @@ LoggerConsole - true - true - - - LoggerRecipes false - true + false - - Account_Batch_Logger_Example - true - - - Account_Queueable_Logger_Example - true - ComponentLogger true @@ -26,10 +13,6 @@ ComponentLogger_Tests true - - ExampleClassWithLogging - true - ExampleInboundEmailHandler true @@ -83,17 +66,45 @@ true - LogEntryEventBuilder + LogBatchPurger_Tests_Integration true - LogEntryEventBuilder_Tests_Integration + LogEntryArchiveBuilder + true + + + LogEntryArchiveBuilder_Tests + true + + + LogEntryArchiveController + true + + + LogEntryArchiveController_Tests + true + + + LogEntryArchivePlugin + true + + + LogEntryArchivePlugin_Tests + true + + + LogEntryEventBuilder true LogEntryEventBuilder_Tests true + + LogEntryEventBuilder_Tests_Integration + true + LogEntryEventHandler true @@ -139,15 +150,15 @@ true - LogHandler_Tests_Flow + LogMassDeleteExtension true - LogMassDeleteExtension + LogMassDeleteExtension_Tests true - LogMassDeleteExtension_Tests + LogMassDeleteExtension_Tests_Integration true @@ -158,10 +169,26 @@ LogMessage_Tests true + + LogRetentionRulesPlugin + true + + + LogRetentionRulesPlugin_Tests + true + Logger true + + LoggerEmailSender + true + + + LoggerEmailSender_Tests + true + LoggerParameter true @@ -170,16 +197,40 @@ LoggerParameter_Tests true + + LoggerPlugin + true + + + LoggerPlugin_Tests + true + LoggerSObjectHandler true - LoggerSObjectHandlerPlugin + LoggerSObjectHandler_Tests + true + + + LoggerSObjectMetadata + true + + + LoggerSObjectMetadata_Tests true - LoggerSObjectHandlerPlugin_Tests + LoggerSettingsController + true + + + LoggerSettingsController_Tests + true + + + LoggerSettingsController_Tests_Security true @@ -191,7 +242,7 @@ true - LoggerTestUtils + LoggerMockDataCreator true @@ -229,717 +280,1222 @@ false false - LogEntryDataMaskRule__mdt.ApplyToMessage__c + LogEntryArchive__b.ApiVersion__c true false - LogEntryDataMaskRule__mdt.ApplyToRecordJson__c + LogEntryArchive__b.ComponentType__c true false - LogEntryDataMaskRule__mdt.IsEnabled__c + LogEntryArchive__b.DatabaseResultCollectionType__c true false - LogEntryEvent__e.ApiVersion__c + LogEntryArchive__b.DatabaseResultJson__c true false - LogEntryEvent__e.ComponentType__c + LogEntryArchive__b.DatabaseResultType__c true false - LogEntryEvent__e.DatabaseResultCollectionType__c + LogEntryArchive__b.EpochTimestamp__c true false - LogEntryEvent__e.DatabaseResultJson__c + LogEntryArchive__b.ExceptionMessage__c true false - LogEntryEvent__e.DatabaseResultType__c + LogEntryArchive__b.ExceptionStackTrace__c true false - LogEntryEvent__e.EpochTimestamp__c + LogEntryArchive__b.ExceptionType__c true false - LogEntryEvent__e.ExceptionMessage__c + LogEntryArchive__b.LimitsAggregateQueriesMax__c true false - LogEntryEvent__e.ExceptionStackTrace__c + LogEntryArchive__b.LimitsAggregateQueriesUsed__c true false - LogEntryEvent__e.ExceptionType__c + LogEntryArchive__b.LimitsAggregateQueryMax__c true false - LogEntryEvent__e.LimitsAggregateQueriesMax__c + LogEntryArchive__b.LimitsAsyncCallsMax__c true false - LogEntryEvent__e.LimitsAggregateQueriesUsed__c + LogEntryArchive__b.LimitsAsyncCallsUsed__c true false - LogEntryEvent__e.LimitsAggregateQueryMax__c + LogEntryArchive__b.LimitsCalloutsMax__c true false - LogEntryEvent__e.LimitsAsyncCallsMax__c + LogEntryArchive__b.LimitsCalloutsUsed__c true false - LogEntryEvent__e.LimitsAsyncCallsUsed__c + LogEntryArchive__b.LimitsCpuTimeMax__c true false - LogEntryEvent__e.LimitsCalloutsMax__c + LogEntryArchive__b.LimitsCpuTimeUsed__c true false - LogEntryEvent__e.LimitsCalloutsUsed__c + LogEntryArchive__b.LimitsDmlRowsMax__c true false - LogEntryEvent__e.LimitsCpuTimeMax__c + LogEntryArchive__b.LimitsDmlRowsUsed__c true false - LogEntryEvent__e.LimitsCpuTimeUsed__c + LogEntryArchive__b.LimitsDmlStatementsMax__c true false - LogEntryEvent__e.LimitsDmlRowsMax__c + LogEntryArchive__b.LimitsDmlStatementsUsed__c true false - LogEntryEvent__e.LimitsDmlRowsUsed__c + LogEntryArchive__b.LimitsEmailInvocationsMax__c true false - LogEntryEvent__e.LimitsDmlStatementsMax__c + LogEntryArchive__b.LimitsEmailInvocationsUsed__c true false - LogEntryEvent__e.LimitsDmlStatementsUsed__c + LogEntryArchive__b.LimitsFutureCallsMax__c true false - LogEntryEvent__e.LimitsEmailInvocationsMax__c + LogEntryArchive__b.LimitsFutureCallsUsed__c true false - LogEntryEvent__e.LimitsEmailInvocationsUsed__c + LogEntryArchive__b.LimitsHeapSizeMax__c true false - LogEntryEvent__e.LimitsFutureCallsMax__c + LogEntryArchive__b.LimitsHeapSizeUsed__c true false - LogEntryEvent__e.LimitsFutureCallsUsed__c + LogEntryArchive__b.LimitsMobilePushApexCallsMax__c true false - LogEntryEvent__e.LimitsHeapSizeMax__c + LogEntryArchive__b.LimitsMobilePushApexCallsUsed__c true false - LogEntryEvent__e.LimitsHeapSizeUsed__c + LogEntryArchive__b.LimitsPublishImmediateDmlStatementsMax__c true false - LogEntryEvent__e.LimitsMobilePushApexCallsMax__c + LogEntryArchive__b.LimitsPublishImmediateDmlStatementsUsed__c true false - LogEntryEvent__e.LimitsMobilePushApexCallsUsed__c + LogEntryArchive__b.LimitsQueueableJobsMax__c true false - LogEntryEvent__e.LimitsPublishImmediateDmlStatementsMax__c + LogEntryArchive__b.LimitsQueueableJobsUsed__c true false - LogEntryEvent__e.LimitsPublishImmediateDmlStatementsUsed__c + LogEntryArchive__b.LimitsSoqlQueriesMax__c true false - LogEntryEvent__e.LimitsQueueableJobsMax__c + LogEntryArchive__b.LimitsSoqlQueriesUsed__c true false - LogEntryEvent__e.LimitsQueueableJobsUsed__c + LogEntryArchive__b.LimitsSoqlQueryLocatorRowsMax__c true false - LogEntryEvent__e.LimitsSoqlQueriesMax__c + LogEntryArchive__b.LimitsSoqlQueryLocatorRowsUsed__c true false - LogEntryEvent__e.LimitsSoqlQueriesUsed__c + LogEntryArchive__b.LimitsSoqlQueryRowsMax__c true false - LogEntryEvent__e.LimitsSoqlQueryLocatorRowsMax__c + LogEntryArchive__b.LimitsSoqlQueryRowsUsed__c true false - LogEntryEvent__e.LimitsSoqlQueryLocatorRowsUsed__c + LogEntryArchive__b.LimitsSoslSearchesMax__c true false - LogEntryEvent__e.LimitsSoqlQueryRowsMax__c + LogEntryArchive__b.LimitsSoslSearchesUsed__c true false - LogEntryEvent__e.LimitsSoqlQueryRowsUsed__c + LogEntryArchive__b.Locale__c true false - LogEntryEvent__e.LimitsSoslSearchesMax__c + LogEntryArchive__b.LoggedById__c true false - LogEntryEvent__e.LimitsSoslSearchesUsed__c + LogEntryArchive__b.LoggedByUsername__c true false - LogEntryEvent__e.Locale__c + LogEntryArchive__b.LoggerVersionNumber__c true false - LogEntryEvent__e.LoggedById__c + LogEntryArchive__b.LoginApplication__c true false - LogEntryEvent__e.LoggedByUsername__c + LogEntryArchive__b.LoginBrowser__c true false - LogEntryEvent__e.LoggingLevelOrdinal__c + LogEntryArchive__b.LoginDomain__c true false - LogEntryEvent__e.LoggingLevel__c + LogEntryArchive__b.LoginHistoryId__c true false - LogEntryEvent__e.LoggerVersionNumber__c + LogEntryArchive__b.LoginPlatform__c true false - LogEntryEvent__e.LoginApplication__c + LogEntryArchive__b.LoginType__c true false - LogEntryEvent__e.LoginBrowser__c + LogEntryArchive__b.LogoutUrl__c true false - LogEntryEvent__e.LoginDomain__c + LogEntryArchive__b.Message__c true false - LogEntryEvent__e.LoginHistoryId__c + LogEntryArchive__b.NetworkId__c true false - LogEntryEvent__e.LoginPlatform__c + LogEntryArchive__b.NetworkLoginUrl__c true false - LogEntryEvent__e.LoginType__c + LogEntryArchive__b.NetworkLogoutUrl__c true false - LogEntryEvent__e.LogoutUrl__c + LogEntryArchive__b.NetworkName__c true false - LogEntryEvent__e.MessageMasked__c + LogEntryArchive__b.NetworkSelfRegistrationUrl__c true false - LogEntryEvent__e.MessageTruncated__c + LogEntryArchive__b.NetworkUrlPathPrefix__c true false - LogEntryEvent__e.Message__c + LogEntryArchive__b.OrganizationDomainUrl__c true false - LogEntryEvent__e.NetworkId__c + LogEntryArchive__b.OrganizationEnvironmentType__c true false - LogEntryEvent__e.NetworkLoginUrl__c + LogEntryArchive__b.OrganizationId__c true false - LogEntryEvent__e.NetworkLogoutUrl__c + LogEntryArchive__b.OrganizationInstanceName__c true false - LogEntryEvent__e.NetworkName__c + LogEntryArchive__b.OrganizationName__c true false - LogEntryEvent__e.NetworkSelfRegistrationUrl__c + LogEntryArchive__b.OrganizationNamespacePrefix__c true false - LogEntryEvent__e.NetworkUrlPathPrefix__c + LogEntryArchive__b.OrganizationType__c true false - LogEntryEvent__e.OrganizationDomainUrl__c + LogEntryArchive__b.OriginLocation__c true false - LogEntryEvent__e.OrganizationEnvironmentType__c + LogEntryArchive__b.OriginType__c true false - LogEntryEvent__e.OrganizationId__c + LogEntryArchive__b.ParentLogTransactionId__c true false - LogEntryEvent__e.OrganizationInstanceName__c + LogEntryArchive__b.ProfileId__c true false - LogEntryEvent__e.OrganizationName__c + LogEntryArchive__b.ProfileName__c true false - LogEntryEvent__e.OrganizationNamespacePrefix__c + LogEntryArchive__b.RecordCollectionType__c true false - LogEntryEvent__e.OrganizationType__c + LogEntryArchive__b.RecordId__c true false - LogEntryEvent__e.OriginLocation__c + LogEntryArchive__b.RecordJson__c true false - LogEntryEvent__e.OriginType__c + LogEntryArchive__b.RecordSObjectClassification__c true false - LogEntryEvent__e.ParentLogTransactionId__c + LogEntryArchive__b.RecordSObjectTypeNamespace__c true false - LogEntryEvent__e.ProfileId__c + LogEntryArchive__b.RecordSObjectType__c true false - LogEntryEvent__e.ProfileName__c + LogEntryArchive__b.Scenario__c true false - LogEntryEvent__e.RecordCollectionType__c + LogEntryArchive__b.SessionId__c true false - LogEntryEvent__e.RecordId__c + LogEntryArchive__b.SessionSecurityLevel__c true false - LogEntryEvent__e.RecordJsonMasked__c + LogEntryArchive__b.SessionType__c true false - LogEntryEvent__e.RecordJson__c + LogEntryArchive__b.SourceIp__c true false - LogEntryEvent__e.RecordSObjectClassification__c + LogEntryArchive__b.StackTrace__c true false - LogEntryEvent__e.RecordSObjectTypeNamespace__c + LogEntryArchive__b.SystemMode__c true false - LogEntryEvent__e.RecordSObjectType__c + LogEntryArchive__b.Tags__c true false - LogEntryEvent__e.SessionId__c + LogEntryArchive__b.ThemeDisplayed__c true false - LogEntryEvent__e.SessionSecurityLevel__c + LogEntryArchive__b.TimeZoneId__c true false - LogEntryEvent__e.SessionType__c + LogEntryArchive__b.TimeZoneName__c true false - LogEntryEvent__e.SourceIp__c + LogEntryArchive__b.TimestampString__c true false - LogEntryEvent__e.StackTrace__c + LogEntryArchive__b.TriggerOperationType__c true false - LogEntryEvent__e.SystemMode__c + LogEntryArchive__b.TriggerSObjectType__c true false - LogEntryEvent__e.Tags__c + LogEntryArchive__b.UserLicenseDefinitionKey__c true false - LogEntryEvent__e.ThemeDisplayed__c + LogEntryArchive__b.UserLicenseId__c true false - LogEntryEvent__e.TimeZoneId__c + LogEntryArchive__b.UserLicenseName__c true false - LogEntryEvent__e.TimeZoneName__c + LogEntryArchive__b.UserLoggingLevelOrdinal__c true false - LogEntryEvent__e.TimestampString__c + LogEntryArchive__b.UserLoggingLevel__c true false - LogEntryEvent__e.Topics__c + LogEntryArchive__b.UserRoleId__c true false - LogEntryEvent__e.TriggerIsExecuting__c + LogEntryArchive__b.UserRoleName__c true false - LogEntryEvent__e.TriggerOperationType__c + LogEntryArchive__b.UserType__c true false - LogEntryEvent__e.TriggerSObjectType__c + LogEntryDataMaskRule__mdt.ApplyToMessage__c true false - LogEntryEvent__e.UserLicenseDefinitionKey__c + LogEntryDataMaskRule__mdt.ApplyToRecordJson__c true false - LogEntryEvent__e.UserLicenseId__c + LogEntryDataMaskRule__mdt.IsEnabled__c true false - LogEntryEvent__e.UserLicenseName__c + LogEntryEvent__e.ApiVersion__c true false - LogEntryEvent__e.UserLoggingLevelOrdinal__c + LogEntryEvent__e.ComponentType__c true false - LogEntryEvent__e.UserLoggingLevel__c + LogEntryEvent__e.DatabaseResultCollectionType__c true false - LogEntryEvent__e.UserRoleId__c + LogEntryEvent__e.DatabaseResultJson__c true false - LogEntryEvent__e.UserRoleName__c + LogEntryEvent__e.DatabaseResultType__c true false - LogEntryEvent__e.UserType__c + LogEntryEvent__e.EpochTimestamp__c true false - LogEntryTagRule__mdt.ComparisonValue__c + LogEntryEvent__e.ExceptionMessage__c true false - LogEntryTagRule__mdt.IsEnabled__c + LogEntryEvent__e.ExceptionStackTrace__c true false - LogEntryTagRule__mdt.Tags__c + LogEntryEvent__e.ExceptionType__c true false - LogEntryTag__c.LogEntryOrigin__c + LogEntryEvent__e.LimitsAggregateQueriesMax__c true false - LogEntryTag__c.LogEntryTimestamp__c + LogEntryEvent__e.LimitsAggregateQueriesUsed__c true false - LogEntryTag__c.LogLink__c + LogEntryEvent__e.LimitsAggregateQueryMax__c true false - LogEntryTag__c.LoggedByUsernameLink__c + LogEntryEvent__e.LimitsAsyncCallsMax__c true false - LogEntryTag__c.UniqueId__c + LogEntryEvent__e.LimitsAsyncCallsUsed__c true false - LogEntry__c.ApexClassApiVersion__c + LogEntryEvent__e.LimitsCalloutsMax__c true false - LogEntry__c.ApexClassCreatedDate__c + LogEntryEvent__e.LimitsCalloutsUsed__c true false - LogEntry__c.ApexClassId__c + LogEntryEvent__e.LimitsCpuTimeMax__c true false - LogEntry__c.ApexClassLastModifiedDate__c + LogEntryEvent__e.LimitsCpuTimeUsed__c true false - LogEntry__c.ApexClassName__c + LogEntryEvent__e.LimitsDmlRowsMax__c true false - LogEntry__c.ApexInnerClassName__c + LogEntryEvent__e.LimitsDmlRowsUsed__c true false - LogEntry__c.ApexMethodName__c + LogEntryEvent__e.LimitsDmlStatementsMax__c true false - LogEntry__c.ComponentApiName__c + LogEntryEvent__e.LimitsDmlStatementsUsed__c true false - LogEntry__c.ComponentFunctionName__c + LogEntryEvent__e.LimitsEmailInvocationsMax__c true false - LogEntry__c.ComponentType__c + LogEntryEvent__e.LimitsEmailInvocationsUsed__c true false - LogEntry__c.DatabaseResultCollectionType__c + LogEntryEvent__e.LimitsFutureCallsMax__c true false - LogEntry__c.DatabaseResultJson__c + LogEntryEvent__e.LimitsFutureCallsUsed__c true false - LogEntry__c.DatabaseResultType__c + LogEntryEvent__e.LimitsHeapSizeMax__c true false - LogEntry__c.EpochTimestamp__c + LogEntryEvent__e.LimitsHeapSizeUsed__c true false - LogEntry__c.EventUuid__c + LogEntryEvent__e.LimitsMobilePushApexCallsMax__c true false - LogEntry__c.ExceptionMessage__c + LogEntryEvent__e.LimitsMobilePushApexCallsUsed__c true false - LogEntry__c.ExceptionStackTrace__c + LogEntryEvent__e.LimitsPublishImmediateDmlStatementsMax__c true false - LogEntry__c.ExceptionType__c + LogEntryEvent__e.LimitsPublishImmediateDmlStatementsUsed__c true false - LogEntry__c.FlowActiveVersionId__c + LogEntryEvent__e.LimitsQueueableJobsMax__c true false - LogEntry__c.FlowDescription__c + LogEntryEvent__e.LimitsQueueableJobsUsed__c true false - LogEntry__c.FlowDurableId__c + LogEntryEvent__e.LimitsSoqlQueriesMax__c true false - LogEntry__c.FlowLabel__c + LogEntryEvent__e.LimitsSoqlQueriesUsed__c true false - LogEntry__c.FlowLastModifiedByName__c + LogEntryEvent__e.LimitsSoqlQueryLocatorRowsMax__c true false - LogEntry__c.FlowLastModifiedDate__c + LogEntryEvent__e.LimitsSoqlQueryLocatorRowsUsed__c true false - LogEntry__c.FlowProcessType__c + LogEntryEvent__e.LimitsSoqlQueryRowsMax__c true false - LogEntry__c.FlowTriggerType__c + LogEntryEvent__e.LimitsSoqlQueryRowsUsed__c + true + + + false + LogEntryEvent__e.LimitsSoslSearchesMax__c + true + + + false + LogEntryEvent__e.LimitsSoslSearchesUsed__c + true + + + false + LogEntryEvent__e.Locale__c + true + + + false + LogEntryEvent__e.LoggedById__c + true + + + false + LogEntryEvent__e.LoggedByUsername__c + true + + + false + LogEntryEvent__e.LoggerVersionNumber__c + true + + + false + LogEntryEvent__e.LoggingLevelOrdinal__c + true + + + false + LogEntryEvent__e.LoggingLevel__c + true + + + false + LogEntryEvent__e.LoginApplication__c + true + + + false + LogEntryEvent__e.LoginBrowser__c + true + + + false + LogEntryEvent__e.LoginDomain__c + true + + + false + LogEntryEvent__e.LoginHistoryId__c + true + + + false + LogEntryEvent__e.LoginPlatform__c + true + + + false + LogEntryEvent__e.LoginType__c + true + + + false + LogEntryEvent__e.LogoutUrl__c + true + + + false + LogEntryEvent__e.MessageMasked__c + true + + + false + LogEntryEvent__e.MessageTruncated__c + true + + + false + LogEntryEvent__e.Message__c + true + + + false + LogEntryEvent__e.NetworkId__c + true + + + false + LogEntryEvent__e.NetworkLoginUrl__c + true + + + false + LogEntryEvent__e.NetworkLogoutUrl__c + true + + + false + LogEntryEvent__e.NetworkName__c + true + + + false + LogEntryEvent__e.NetworkSelfRegistrationUrl__c + true + + + false + LogEntryEvent__e.NetworkUrlPathPrefix__c + true + + + false + LogEntryEvent__e.OrganizationDomainUrl__c + true + + + false + LogEntryEvent__e.OrganizationEnvironmentType__c + true + + + false + LogEntryEvent__e.OrganizationId__c + true + + + false + LogEntryEvent__e.OrganizationInstanceName__c + true + + + false + LogEntryEvent__e.OrganizationName__c + true + + + false + LogEntryEvent__e.OrganizationNamespacePrefix__c + true + + + false + LogEntryEvent__e.OrganizationType__c + true + + + false + LogEntryEvent__e.OriginLocation__c + true + + + false + LogEntryEvent__e.OriginType__c + true + + + false + LogEntryEvent__e.ParentLogTransactionId__c + true + + + false + LogEntryEvent__e.ProfileId__c + true + + + false + LogEntryEvent__e.ProfileName__c + true + + + false + LogEntryEvent__e.RecordCollectionType__c + true + + + false + LogEntryEvent__e.RecordId__c + true + + + false + LogEntryEvent__e.RecordJsonMasked__c + true + + + false + LogEntryEvent__e.RecordJson__c + true + + + false + LogEntryEvent__e.RecordSObjectClassification__c + true + + + false + LogEntryEvent__e.RecordSObjectTypeNamespace__c + true + + + false + LogEntryEvent__e.RecordSObjectType__c + true + + + false + LogEntryEvent__e.Scenario__c + true + + + false + LogEntryEvent__e.SessionId__c + true + + + false + LogEntryEvent__e.SessionSecurityLevel__c + true + + + false + LogEntryEvent__e.SessionType__c + true + + + false + LogEntryEvent__e.SourceIp__c + true + + + false + LogEntryEvent__e.StackTrace__c + true + + + false + LogEntryEvent__e.SystemMode__c + true + + + false + LogEntryEvent__e.Tags__c + true + + + false + LogEntryEvent__e.ThemeDisplayed__c + true + + + false + LogEntryEvent__e.TimeZoneId__c + true + + + false + LogEntryEvent__e.TimeZoneName__c + true + + + false + LogEntryEvent__e.TimestampString__c + true + + + false + LogEntryEvent__e.Topics__c + true + + + false + LogEntryEvent__e.TriggerIsExecuting__c + true + + + false + LogEntryEvent__e.TriggerOperationType__c + true + + + false + LogEntryEvent__e.TriggerSObjectType__c + true + + + false + LogEntryEvent__e.UserLicenseDefinitionKey__c + true + + + false + LogEntryEvent__e.UserLicenseId__c + true + + + false + LogEntryEvent__e.UserLicenseName__c + true + + + false + LogEntryEvent__e.UserLoggingLevelOrdinal__c + true + + + false + LogEntryEvent__e.UserLoggingLevel__c + true + + + false + LogEntryEvent__e.UserRoleId__c + true + + + false + LogEntryEvent__e.UserRoleName__c + true + + + false + LogEntryEvent__e.UserType__c + true + + + false + LogEntryTagRule__mdt.ComparisonValue__c + true + + + false + LogEntryTagRule__mdt.IsEnabled__c + true + + + false + LogEntryTagRule__mdt.Tags__c + true + + + false + LogEntryTag__c.LogEntryOrigin__c + true + + + false + LogEntryTag__c.LogEntryTimestamp__c + true + + + false + LogEntryTag__c.LogLink__c + true + + + false + LogEntryTag__c.LoggedByUsernameLink__c + true + + + false + LogEntryTag__c.UniqueId__c + true + + + false + LogEntry__c.ApexClassApiVersion__c + true + + + false + LogEntry__c.ApexClassCreatedDate__c + true + + + false + LogEntry__c.ApexClassId__c + true + + + false + LogEntry__c.ApexClassLastModifiedDate__c + true + + + false + LogEntry__c.ApexClassName__c + true + + + false + LogEntry__c.ApexInnerClassName__c + true + + + false + LogEntry__c.ApexMethodName__c + true + + + false + LogEntry__c.ComponentApiName__c + true + + + false + LogEntry__c.ComponentFunctionName__c + true + + + false + LogEntry__c.ComponentType__c + true + + + false + LogEntry__c.DatabaseResultCollectionType__c + true + + + false + LogEntry__c.DatabaseResultJson__c + true + + + false + LogEntry__c.DatabaseResultType__c + true + + + false + LogEntry__c.EpochTimestamp__c + true + + + false + LogEntry__c.EventUuid__c + true + + + false + LogEntry__c.ExceptionMessage__c + true + + + false + LogEntry__c.ExceptionStackTrace__c + true + + + false + LogEntry__c.ExceptionType__c + true + + + false + LogEntry__c.FlowActiveVersionId__c + true + + + false + LogEntry__c.FlowDescription__c + true + + + false + LogEntry__c.FlowDurableId__c + true + + + false + LogEntry__c.FlowLabel__c + true + + + false + LogEntry__c.FlowLastModifiedByName__c + true + + + false + LogEntry__c.FlowLastModifiedDate__c + true + + + false + LogEntry__c.FlowProcessType__c + true + + + false + LogEntry__c.FlowTriggerType__c true @@ -1274,97 +1830,137 @@ false - LogEntry__c.OriginType__c + LogEntry__c.OriginType__c + true + + + false + LogEntry__c.Origin__c + true + + + false + LogEntry__c.RecordCollectionType__c + true + + + false + LogEntry__c.RecordDetailedLink__c + true + + + false + LogEntry__c.RecordId__c + true + + + false + LogEntry__c.RecordJsonMasked__c + true + + + false + LogEntry__c.RecordJson__c + true + + + false + LogEntry__c.RecordLink__c + true + + + false + LogEntry__c.RecordName__c true false - LogEntry__c.Origin__c + LogEntry__c.RecordSObjectClassification__c true false - LogEntry__c.RecordCollectionType__c + LogEntry__c.RecordSObjectTypeNamespace__c true false - LogEntry__c.RecordDetailedLink__c + LogEntry__c.RecordSObjectType__c true false - LogEntry__c.RecordId__c + LogEntry__c.StackTrace__c true false - LogEntry__c.RecordJsonMasked__c + LogEntry__c.Timestamp__c true false - LogEntry__c.RecordJson__c + LogEntry__c.TransactionEntryNumber__c true false - LogEntry__c.RecordLink__c + LogEntry__c.TriggerIsExecuting__c true false - LogEntry__c.RecordName__c + LogEntry__c.TriggerOperationType__c true false - LogEntry__c.RecordSObjectClassification__c + LogEntry__c.TriggerSObjectType__c true false - LogEntry__c.RecordSObjectTypeNamespace__c + LogEntry__c.Trigger__c true false - LogEntry__c.RecordSObjectType__c + LogRetentionRuleCondition__mdt.SortOrder__c true false - LogEntry__c.StackTrace__c + LogRetentionRuleCondition__mdt.Value__c true false - LogEntry__c.Timestamp__c + LogRetentionRule__mdt.CustomConditionLogic__c true false - LogEntry__c.TransactionEntryNumber__c + LogRetentionRule__mdt.ExecutionOrder__c true false - LogEntry__c.TriggerIsExecuting__c + LogRetentionRule__mdt.IsEnabled__c true false - LogEntry__c.TriggerOperationType__c + LogRetentionRule__mdt.NumberOfDaysToRetainLogs__c true false - LogEntry__c.TriggerSObjectType__c + LogScenarioRule__mdt.IsEnabled__c true false - LogEntry__c.Trigger__c + LogScenarioRule__mdt.NumberOfDaysToRetainLogs__c true @@ -1442,6 +2038,11 @@ Log__c.LogEntriesSummary__c true + + false + Log__c.LogPurgeAction__c + true + false Log__c.LogRetentionDate__c @@ -1784,12 +2385,22 @@ false - LoggerPlugin__mdt.Description__c + LoggerPlugin__mdt.BatchPurgerApexClass__c + true + + + false + LoggerPlugin__mdt.BatchPurgerExecutionOrder__c + true + + + false + LoggerPlugin__mdt.BatchPurgerFlowName__c true false - LoggerPlugin__mdt.ExecutionOrder__c + LoggerPlugin__mdt.Description__c true @@ -1797,6 +2408,31 @@ LoggerPlugin__mdt.IsEnabled__c true + + false + LoggerPlugin__mdt.Link__c + true + + + false + LoggerPlugin__mdt.SObjectHandlerApexClass__c + true + + + false + LoggerPlugin__mdt.SObjectHandlerExecutionOrder__c + true + + + false + LoggerPlugin__mdt.SObjectHandlerFlowName__c + true + + + false + LoggerPlugin__mdt.VersionNumber__c + true + false LoggerTag__c.TotalLogEntries__c @@ -1819,6 +2455,15 @@ LogEntry__c-Log Entry Layout + + LogRetentionRuleCondition__mdt-Log Retention Rule Condition Layout + + + LogRetentionRule__mdt-Log Retention Rule Layout + + + LogScenarioRule__mdt-Log Scenario Rule Layout + LogStatus__mdt-Log Status Layout @@ -1834,6 +2479,15 @@ LoggerTag__c-Logger Tag Layout + + true + true + true + true + true + LogEntryArchive__b + true + true true @@ -1883,32 +2537,729 @@ LogMassDelete true + + LogEntryArchives + Hidden + LogEntryEventStream - DefaultOn + Hidden LogEntryTag__c - DefaultOn + Hidden LogEntry__c - DefaultOn + Hidden Log__c - DefaultOn + Hidden - LoggerAuraDemo - DefaultOn + LoggerSettings + Hidden LoggerTag__c - DefaultOn + Hidden - - Logger_lwc_demo - DefaultOn - - + Salesforce + + true + ActivateContract + + + true + ActivateOrder + + + true + ActivitiesAccess + + + true + AddDirectMessageMembers + + + true + AllowUniversalSearch + + + true + AllowViewKnowledge + + + true + ApexRestServices + + + true + ApiEnabled + + + true + ApproveContract + + + true + AssignPermissionSets + + + true + AssignTopics + + + true + AuthorApex + + + true + BulkMacrosAllowed + + + true + CanInsertFeedSystemFields + + + true + CanUseNewDashboardBuilder + + + true + CanVerifyComment + + + true + ChangeDashboardColors + + + true + ChatterEditOwnPost + + + true + ChatterEditOwnRecordPost + + + true + ChatterFileLink + + + true + ChatterInternalUser + + + true + ChatterInviteExternalUsers + + + true + ChatterOwnGroups + + + true + ConnectOrgToEnvironmentHub + + + true + ConsentApiUpdate + + + true + ContentAdministrator + + + true + ContentWorkspaces + + + true + ConvertLeads + + + true + CreateCustomizeDashboards + + + true + CreateCustomizeFilters + + + true + CreateCustomizeReports + + + true + CreateDashboardFolders + + + true + CreateLtngTempFolder + + + true + CreateReportFolders + + + true + CreateTopics + + + true + CreateWorkspaces + + + true + CustomizeApplication + + + true + DataExport + + + true + DelegatedTwoFactor + + + true + DeleteActivatedContract + + + true + DeleteTopics + + + true + DistributeFromPersWksp + + + true + EditActivatedOrders + + + true + EditBrandTemplates + + + true + EditCaseComments + + + true + EditEvent + + + true + EditHtmlTemplates + + + true + EditKnowledge + + + true + EditMyDashboards + + + true + EditMyReports + + + true + EditOppLineItemUnitPrice + + + true + EditPublicDocuments + + + true + EditPublicFilters + + + true + EditPublicTemplates + + + true + EditReadonlyFields + + + true + EditTask + + + true + EditTopics + + + true + EmailMass + + + true + EmailSingle + + + true + EnableCommunityAppLauncher + + + true + EnableNotifications + + + true + ExportReport + + + true + GiveRecognitionBadge + + + true + ImportCustomObjects + + + true + ImportLeads + + + true + ImportPersonal + + + true + InboundMigrationToolsUser + + + true + InstallPackaging + + + true + LightningConsoleAllowedForUser + + + true + LightningExperienceUser + + + true + ListEmailSend + + + true + ManageAnalyticSnapshots + + + true + ManageAuthProviders + + + true + ManageBusinessHourHolidays + + + true + ManageC360AConnections + + + true + ManageCMS + + + true + ManageCallCenters + + + true + ManageCases + + + true + ManageCategories + + + true + ManageCertificates + + + true + ManageContentPermissions + + + true + ManageContentProperties + + + true + ManageContentTypes + + + true + ManageCustomPermissions + + + true + ManageCustomReportTypes + + + true + ManageDashbdsInPubFolders + + + true + ManageDataCategories + + + true + ManageDataIntegrations + + + true + ManageDynamicDashboards + + + true + ManageEmailClientConfig + + + true + ManageEntitlements + + + true + ManageExchangeConfig + + + true + ManageHealthCheck + + + true + ManageHubConnections + + + true + ManageInteraction + + + true + ManageInternalUsers + + + true + ManageIpAddresses + + + true + ManageKnowledge + + + true + ManageKnowledgeImportExport + + + true + ManageLeads + + + true + ManageLoginAccessPolicies + + + true + ManageMobile + + + true + ManageNetworks + + + true + ManagePackageLicenses + + + true + ManagePasswordPolicies + + + true + ManageProfilesPermissionsets + + + true + ManagePropositions + + + true + ManagePvtRptsAndDashbds + + + true + ManageRecommendationStrategies + + + true + ManageReleaseUpdates + + + true + ManageRemoteAccess + + + true + ManageReportsInPubFolders + + + true + ManageRoles + + + true + ManageSearchPromotionRules + + + true + ManageSharing + + + true + ManageSolutions + + + true + ManageSubscriptions + + + true + ManageSynonyms + + + true + ManageTrustMeasures + + + true + ManageUnlistedGroups + + + true + ManageUsers + + + true + MassInlineEdit + + + true + MergeTopics + + + true + ModerateChatter + + + true + ModifyAllData + + + true + ModifyDataClassification + + + true + ModifyMetadata + + + true + NewReportBuilder + + + true + OutboundMigrationToolsUser + + + true + Packaging2 + + + true + Packaging2Delete + + + true + PrivacyDataAccess + + + true + RemoveDirectMessageMembers + + + true + ResetPasswords + + + true + RunReports + + + true + ScheduleJob + + + true + ScheduleReports + + + true + SelectFilesFromSalesforce + + + true + SendCustomNotifications + + + true + SendSitRequests + + + true + ShareInternalArticles + + + true + ShowCompanyNameAsUserBadge + + + true + SolutionImport + + + true + SubmitMacrosAllowed + + + true + SubscribeDashboardRolesGrps + + + true + SubscribeDashboardToOtherUsers + + + true + SubscribeReportRolesGrps + + + true + SubscribeReportToOtherUsers + + + true + SubscribeReportsRunAsUser + + + true + SubscribeToLightningDashboards + + + true + SubscribeToLightningReports + + + true + TransactionalEmailSend + + + true + TransferAnyCase + + + true + TransferAnyEntity + + + true + TransferAnyLead + + + true + UseTeamReassignWizards + + + true + UseWebLink + + + true + ViewAllData + + + true + ViewAllProfiles + + + true + ViewAllUsers + + + true + ViewDataAssessment + + + true + ViewDataCategories + + + true + ViewDeveloperName + + + true + ViewEventLogFiles + + + true + ViewFlowUsageAndFlowEventData + + + true + ViewHealthCheck + + + true + ViewHelpLink + + + true + ViewMyTeamsDashboards + + + true + ViewPublicDashboards + + + true + ViewPublicReports + + + true + ViewRoles + + + true + ViewSetup + + + true + ViewTrustMeasures + + + true + ViewUserPII + + diff --git a/package-lock.json b/package-lock.json index e86426c37..048973be6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,18 @@ { "name": "nebula-logger", - "version": "4.7.0", + "version": "4.7.1", "lockfileVersion": 1, "requires": true, "dependencies": { + "@ampproject/remapping": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", + "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.0" + } + }, "@babel/code-frame": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", @@ -14,38 +23,38 @@ } }, "@babel/compat-data": { - "version": "7.16.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz", - "integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.7.tgz", + "integrity": "sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==", "dev": true }, "@babel/core": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz", - "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.9.tgz", + "integrity": "sha512-5ug+SfZCpDAkVp9SFIZAzlW18rlzsOcJGaetCjkySnrXXDUw9AR8cDUm1iByTmdWM6yxX6/zycaV76w3YTF2gw==", "dev": true, "requires": { + "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.16.7", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.16.7", - "@babel/parser": "^7.16.7", + "@babel/generator": "^7.17.9", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helpers": "^7.17.9", + "@babel/parser": "^7.17.9", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7", + "@babel/traverse": "^7.17.9", + "@babel/types": "^7.17.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" + "json5": "^2.2.1", + "semver": "^6.3.0" } }, "@babel/eslint-parser": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.16.5.tgz", - "integrity": "sha512-mUqYa46lgWqHKQ33Q6LNCGp/wPR3eqOYTUixHFsfrSQqRxH0+WOzca75iEjFr5RDGH1dDz622LaHhLOzOuQRUA==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", + "integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", "dev": true, "requires": { "eslint-scope": "^5.1.1", @@ -54,12 +63,12 @@ } }, "@babel/generator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.7.tgz", - "integrity": "sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.9.tgz", + "integrity": "sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ==", "dev": true, "requires": { - "@babel/types": "^7.16.7", + "@babel/types": "^7.17.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" } @@ -74,27 +83,27 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz", + "integrity": "sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==", "dev": true, "requires": { - "@babel/compat-data": "^7.16.4", + "@babel/compat-data": "^7.17.7", "@babel/helper-validator-option": "^7.16.7", "browserslist": "^4.17.5", "semver": "^6.3.0" } }, "@babel/helper-create-class-features-plugin": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz", - "integrity": "sha512-kIFozAvVfK05DM4EVQYKK+zteWvY85BFdGBRQBytRyY3y+6PX0DkDOn/CZ3lEuczCfrCxEzwt0YtP/87YPTWSw==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.9.tgz", + "integrity": "sha512-kUjip3gruz6AJKOq5i3nC6CoCEEF/oHH3cp6tOZhB+IyyyPyW0g1Gfsxn3mkk6S08pIA2y8GQh609v9G/5sHVQ==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.16.7", "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-member-expression-to-functions": "^7.17.7", "@babel/helper-optimise-call-expression": "^7.16.7", "@babel/helper-replace-supers": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7" @@ -110,23 +119,13 @@ } }, "@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.16.7", "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" } }, "@babel/helper-hoist-variables": { @@ -139,12 +138,12 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" } }, "@babel/helper-module-imports": { @@ -157,19 +156,19 @@ } }, "@babel/helper-module-transforms": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", - "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz", + "integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==", "dev": true, "requires": { "@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", "@babel/helper-split-export-declaration": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/traverse": "^7.17.3", + "@babel/types": "^7.17.0" } }, "@babel/helper-optimise-call-expression": { @@ -201,12 +200,12 @@ } }, "@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", + "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" } }, "@babel/helper-split-export-declaration": { @@ -231,20 +230,20 @@ "dev": true }, "@babel/helpers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz", - "integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz", + "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==", "dev": true, "requires": { "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/traverse": "^7.17.9", + "@babel/types": "^7.17.0" } }, "@babel/highlight": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", - "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz", + "integrity": "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.16.7", @@ -253,9 +252,9 @@ } }, "@babel/parser": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.7.tgz", - "integrity": "sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.9.tgz", + "integrity": "sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg==", "dev": true }, "@babel/plugin-proposal-class-properties": { @@ -319,9 +318,9 @@ } }, "@babel/plugin-syntax-decorators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.16.7.tgz", - "integrity": "sha512-vQ+PxL+srA7g6Rx6I1e15m55gftknl2X8GCUW1JTlkTaXZLJOS0UcaY0eK9jYT7IYf4awn6qwyghVHLDz1WyMw==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.0.tgz", + "integrity": "sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.16.7" @@ -427,14 +426,14 @@ } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.7.tgz", - "integrity": "sha512-h2RP2kE7He1ZWKyAlanMZrAbdv+Acw1pA8dQZhE025WJZE2z0xzFADAinXA9fxd5bn7JnM+SdOGcndGx1ARs9w==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.9.tgz", + "integrity": "sha512-2TBFd/r2I6VlYn0YRTz2JdazS+FoUuQ2rIFHoAxtyP/0G3D82SBLaRq9rnUkpqlLg03Byfl/+M32mpxjO6KaPw==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-module-transforms": "^7.17.7", "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, @@ -448,9 +447,9 @@ } }, "@babel/plugin-transform-typescript": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.7.tgz", - "integrity": "sha512-Hzx1lvBtOCWuCEwMmYOfpQpO7joFeXLgoPuzZZBtTxXqSqUGUubvFGZv2ygo1tB5Bp9q6PXV3H0E/kf7KM0RLA==", + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz", + "integrity": "sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==", "dev": true, "requires": { "@babel/helper-create-class-features-plugin": "^7.16.7", @@ -469,6 +468,25 @@ "@babel/plugin-transform-typescript": "^7.16.7" } }, + "@babel/runtime": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", + "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/runtime-corejs3": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.9.tgz", + "integrity": "sha512-WxYHHUWF2uZ7Hp1K+D1xQgbgkGUfA+5UPOegEXGt2Y5SMog/rYCVaifLZDbw8UkNXozEqqrZTy6bglL7xTaCOw==", + "dev": true, + "requires": { + "core-js-pure": "^3.20.2", + "regenerator-runtime": "^0.13.4" + } + }, "@babel/template": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", @@ -481,27 +499,27 @@ } }, "@babel/traverse": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.7.tgz", - "integrity": "sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.9.tgz", + "integrity": "sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw==", "dev": true, "requires": { "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.16.7", + "@babel/generator": "^7.17.9", "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7", + "@babel/parser": "^7.17.9", + "@babel/types": "^7.17.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.7.tgz", - "integrity": "sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", + "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.16.7", @@ -514,10 +532,17 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true + }, "@cparra/apexdocs": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@cparra/apexdocs/-/apexdocs-1.14.0.tgz", - "integrity": "sha512-2EruYNdNado6MkgGGxrjD9cve+c6GN/3g/+wNtEuMys6K6snOUIWym8hhkDiosmEGZUMizd9rWg49KfgzYIjXw==", + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/@cparra/apexdocs/-/apexdocs-1.13.7.tgz", + "integrity": "sha512-XqMQM6mEcJY7vRv50TrR1PRWGNMxNRCe7i1JKe8rN1B4itNuT0aspGbia9FlJQA4XgfLvOW6y4htErg3P1mGew==", "dev": true, "requires": { "html-entities": "^2.3.2", @@ -526,16 +551,16 @@ } }, "@eslint/eslintrc": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz", - "integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", + "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.2.0", + "espree": "^9.3.1", "globals": "^13.9.0", - "ignore": "^4.0.6", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.0.4", @@ -555,37 +580,31 @@ "dev": true }, "eslint-visitor-keys": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz", - "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true }, "espree": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.0.tgz", - "integrity": "sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", "dev": true, "requires": { "acorn": "^8.7.0", "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^3.1.0" + "eslint-visitor-keys": "^3.3.0" } }, "globals": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -618,10 +637,46 @@ "@hapi/hoek": "^9.0.0" } }, + "@heroku-cli/color": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@heroku-cli/color/-/color-1.1.14.tgz", + "integrity": "sha512-2JYy//YE2YINTe21hpdVMBNc7aYFkgDeY9JUz/BCjFZmYLn0UjGaCc4BpTcMGXNJwuqoUenw2WGOFGHsJqlIDw==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "strip-ansi": "^5.0.0", + "supports-color": "^5.5.0", + "tslib": "^1.9.3" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, "@humanwhocodes/config-array": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.3.tgz", - "integrity": "sha512-3xSMlXHh03hCcCmFc0rbKp3Ivt2PFEJnQUJDDMTJQ2wkECZWdq4GePs2ctc5H8zV+cHPaq8k2vU8mrQjA6iHdQ==", + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -693,17 +748,48 @@ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, + "@jayree/sfdx-plugin-prettier": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@jayree/sfdx-plugin-prettier/-/sfdx-plugin-prettier-1.1.4.tgz", + "integrity": "sha512-cJflGJEpuxPo1vrDBahKt2EFS1WGnmdYm7djVxG3rpT7X6FHdNoZt6X3ptCCfpPwUX9oyTqj+WDB4CleyhguBA==", + "dev": true, + "requires": { + "@oclif/config": "^1.18.3", + "@oclif/errors": "^1.3.5", + "@prettier/plugin-xml": "^1.2.0", + "@salesforce/core": "^2.35.3", + "@salesforce/kit": "^1.5.33", + "cli-progress": "^3.10.0", + "debug": "^4.3.3", + "fs-extra": "^10.0.1", + "prettier": "^2.5.1", + "prettier-plugin-apex": "^1.10.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "@prettier/plugin-xml": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@prettier/plugin-xml/-/plugin-xml-1.2.0.tgz", + "integrity": "sha512-bFvVAZKs59XNmntYjyefn3K4TBykS6E+d6ZW8IcylAs88ZO+TzLhp0dPpi0VKfPzq1Nb+kpDnPRTiwb4zY6NgA==", + "dev": true, + "requires": { + "@xml-tools/parser": "^1.0.11", + "prettier": ">=2.3" + } + } + } + }, "@jest/console": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.4.2.tgz", - "integrity": "sha512-xknHThRsPB/To1FUbi6pCe43y58qFC03zfb6R7fDb/FfC7k2R3i1l+izRBJf8DI46KhYGRaF14Eo9A3qbBoixg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.4.2", - "jest-util": "^27.4.2", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", "slash": "^3.0.0" }, "dependencies": { @@ -759,41 +845,50 @@ } }, "@jest/core": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.4.5.tgz", - "integrity": "sha512-3tm/Pevmi8bDsgvo73nX8p/WPng6KWlCyScW10FPEoN1HU4pwI83tJ3TsFvi1FfzsjwUlMNEPowgb/rPau/LTQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", "dev": true, "requires": { - "@jest/console": "^27.4.2", - "@jest/reporters": "^27.4.5", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.8.1", "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.4.2", - "jest-config": "^27.4.5", - "jest-haste-map": "^27.4.5", - "jest-message-util": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.5", - "jest-resolve-dependencies": "^27.4.5", - "jest-runner": "^27.4.5", - "jest-runtime": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "jest-watcher": "^27.4.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", "micromatch": "^4.0.4", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, "dependencies": { + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -834,6 +929,15 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -846,68 +950,68 @@ } }, "@jest/environment": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.4.4.tgz", - "integrity": "sha512-q+niMx7cJgt/t/b6dzLOh4W8Ef/8VyKG7hxASK39jakijJzbFBGpptx3RXz13FFV7OishQ9lTbv+dQ5K3EhfDQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", "dev": true, "requires": { - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", - "jest-mock": "^27.4.2" + "jest-mock": "^27.5.1" } }, "@jest/fake-timers": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.2.tgz", - "integrity": "sha512-f/Xpzn5YQk5adtqBgvw1V6bF8Nx3hY0OIRRpCvWcfPl0EAjdqWPdhH3t/3XpiWZqtjIEHDyMKP9ajpva1l4Zmg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.5.1", "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", - "jest-message-util": "^27.4.2", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2" + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" } }, "@jest/globals": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.4.4.tgz", - "integrity": "sha512-bqpqQhW30BOreXM8bA8t8JbOQzsq/WnPTnBl+It3UxAD9J8yxEAaBEylHx1dtBapAr/UBk8GidXbzmqnee8tYQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", "dev": true, "requires": { - "@jest/environment": "^27.4.4", - "@jest/types": "^27.4.2", - "expect": "^27.4.2" + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" } }, "@jest/reporters": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.4.5.tgz", - "integrity": "sha512-3orsG4vi8zXuBqEoy2LbnC1kuvkg1KQUgqNxmxpQgIOQEPeV0onvZu+qDQnEoX8qTQErtqn/xzcnbpeTuOLSiA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.4.2", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", "glob": "^7.1.2", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^27.4.5", - "jest-resolve": "^27.4.5", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.5", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", @@ -973,13 +1077,13 @@ } }, "@jest/source-map": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.4.0.tgz", - "integrity": "sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", "dev": true, "requires": { "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "source-map": "^0.6.0" }, "dependencies": { @@ -992,47 +1096,47 @@ } }, "@jest/test-result": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.4.2.tgz", - "integrity": "sha512-kr+bCrra9jfTgxHXHa2UwoQjxvQk3Am6QbpAiJ5x/50LW8llOYrxILkqY0lZRW/hu8FXesnudbql263+EW9iNA==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", "dev": true, "requires": { - "@jest/console": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.4.5.tgz", - "integrity": "sha512-n5woIn/1v+FT+9hniymHPARA9upYUmfi5Pw9ewVwXCDlK4F5/Gkees9v8vdjGdAIJ2MPHLHodiajLpZZanWzEQ==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", "dev": true, "requires": { - "@jest/test-result": "^27.4.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", - "jest-runtime": "^27.4.5" + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" } }, "@jest/transform": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.4.5.tgz", - "integrity": "sha512-PuMet2UlZtlGzwc6L+aZmR3I7CEBpqadO03pU40l2RNY2fFJ191b9/ITB44LNOhVtsyykx0OZvj0PCyuLm7Eew==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", "dev": true, "requires": { "@babel/core": "^7.1.0", - "@jest/types": "^27.4.2", - "babel-plugin-istanbul": "^6.0.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", - "jest-regex-util": "^27.4.0", - "jest-util": "^27.4.2", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", "micromatch": "^4.0.4", - "pirates": "^4.0.1", + "pirates": "^4.0.4", "slash": "^3.0.0", "source-map": "^0.6.1", "write-file-atomic": "^3.0.0" @@ -1096,9 +1200,9 @@ } }, "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", @@ -1160,9 +1264,9 @@ } }, "@jongpie/sfdx-bummer-plugin": { - "version": "0.0.17", - "resolved": "https://registry.npmjs.org/@jongpie/sfdx-bummer-plugin/-/sfdx-bummer-plugin-0.0.17.tgz", - "integrity": "sha512-payglGCjzRFyUbl8LmSwI2x+FoD6cxBWj3G8l575EOJDBi5CwzSpkjihO+WdL4nkkfVXemD2hFEKnsvwMDTLKA==", + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/@jongpie/sfdx-bummer-plugin/-/sfdx-bummer-plugin-0.0.18.tgz", + "integrity": "sha512-vJIwBb0adf/BfBvqxoC9YDXvQ/avRrzWnqf52Xu141V32gMB9zJg69/jCiSPT1To4d0amLtJ7u0zA/rPoI+/FA==", "dev": true, "requires": { "@oclif/command": "^1", @@ -1172,103 +1276,34 @@ "@salesforce/core": "^2.35.0", "fs-extra": "^10.0.0", "tslib": "^2.3" - }, - "dependencies": { - "@salesforce/command": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@salesforce/command/-/command-4.2.2.tgz", - "integrity": "sha512-2QEtPIMaeRyUEnLmPHJ1PhfKDJBupfQS5T4nG8rXpK2yOznBu48aPWaWCYErrxyC0bPa5eoFACeyPWz1k9QMog==", - "dev": true, - "requires": { - "@oclif/command": "^1.8.1", - "@oclif/errors": "^1.2.2", - "@oclif/parser": "3.8.6", - "@oclif/plugin-help": "^2.2.0", - "@oclif/test": "^1.2.4", - "@salesforce/core": "^2.35.0", - "@salesforce/kit": "^1.5.17", - "@salesforce/ts-types": "^1.5.20", - "chalk": "^2.4.2", - "cli-ux": "^4.9.3" - } - }, - "@salesforce/core": { - "version": "2.35.2", - "resolved": "https://registry.npmjs.org/@salesforce/core/-/core-2.35.2.tgz", - "integrity": "sha512-/f+nZFJf7wRVqZGxnCFGOICCLFJkx37oC/c1M8ICCPH0YRNa0GvlQQv7H/WYtej4OzA0HfnHkhxwCUuCQj5EHw==", - "dev": true, - "requires": { - "@salesforce/bunyan": "^2.0.0", - "@salesforce/kit": "^1.5.17", - "@salesforce/schemas": "^1.0.1", - "@salesforce/ts-types": "^1.5.20", - "@types/graceful-fs": "^4.1.5", - "@types/jsforce": "^1.9.38", - "@types/mkdirp": "^1.0.1", - "archiver": "^5.3.0", - "debug": "^3.1.0", - "faye": "^1.4.0", - "graceful-fs": "^4.2.4", - "js2xmlparser": "^4.0.1", - "jsen": "0.6.6", - "jsforce": "^1.11.0", - "jsonwebtoken": "8.5.0", - "mkdirp": "1.0.4", - "semver": "^7.3.5", - "ts-retry-promise": "^0.6.0" - } - }, - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - } + } + }, + "@jridgewell/resolve-uri": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", + "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", + "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", + "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, "@ljharb/eslint-config": { - "version": "20.2.3", - "resolved": "https://registry.npmjs.org/@ljharb/eslint-config/-/eslint-config-20.2.3.tgz", - "integrity": "sha512-Rk3IhGn8N7++t/1EQA2Op+0KvYZBBMmCyC8ICxA1gpDLnof64UVdoeUrn1h9YWNCnUMopm/xwH0GFirnWfD9lw==", + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@ljharb/eslint-config/-/eslint-config-21.0.0.tgz", + "integrity": "sha512-gk0AWYdJVA3UumN02ZjtGl1Q1+igH/EqhPgZMqJLFjhrSN54JzHu7ggVps7hdVnCKxwNc11myqrGrEYrN4Rq8A==", "dev": true, "requires": { "eslint-scope": "=7.1.0" @@ -1368,12 +1403,32 @@ "dev": true }, "@lwc/eslint-plugin-lwc": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@lwc/eslint-plugin-lwc/-/eslint-plugin-lwc-1.1.1.tgz", - "integrity": "sha512-e+66ZydcQ0HFs/hIsq2JXMWVDDG2BoYWCG2ZBs/Y23bLFAE+iPFOmli5cHS9QqVOYzx9HlOTkt0h/XweNoQ5xg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@lwc/eslint-plugin-lwc/-/eslint-plugin-lwc-1.2.1.tgz", + "integrity": "sha512-13a5XOultegAc4i4SyFk9367KOvvRy40zbRSKkApcNa9uMI6n9/C/yFMvwve6Mp6PaIsGXlKFWNkzwj+nADEzw==", "dev": true, "requires": { - "minimatch": "^3.0.4" + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "@lwc/jest-preset": { @@ -1472,11 +1527,21 @@ "dev": true }, "@mdn/browser-compat-data": { - "version": "3.3.14", - "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-3.3.14.tgz", - "integrity": "sha512-n2RC9d6XatVbWFdHLimzzUJxJ1KY8LdjqrW6YvGPiRmsHkhOUx74/Ct10x5Yo7bC/Jvqx7cDEW8IMPv/+vwEzA==", + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-4.1.16.tgz", + "integrity": "sha512-bqXpkAfQgSD1jUNnn+kKtaHDDMPFz2kij4C71euV4fBv+YCmzkB8TKIoSuUHEdjkE0s55WoQ2OZk/ullmbiUOA==", "dev": true }, + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "dev": true, + "requires": { + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1503,43 +1568,302 @@ "fastq": "^1.6.0" } }, - "@oclif/command": { - "version": "1.8.15", - "resolved": "https://registry.npmjs.org/@oclif/command/-/command-1.8.15.tgz", - "integrity": "sha512-lMRsr38sm4XBDBt2u88nvGyk3YxMjQenfX1HM140ZckTVqwuvFVZLP4HZ0rSAK9FdJzfryO/tH5hovdiC6bgsw==", + "@oclif/color": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@oclif/color/-/color-0.1.2.tgz", + "integrity": "sha512-M9o+DOrb8l603qvgz1FogJBUGLqcMFL1aFg2ZEL0FbXJofiNTLOWIeB4faeZTLwE6dt0xH9GpCVpzksMMzGbmA==", "dev": true, "requires": { - "@oclif/config": "^1.18.2", - "@oclif/errors": "^1.3.5", - "@oclif/help": "^1.0.1", - "@oclif/parser": "^3.8.6", - "debug": "^4.1.1", - "semver": "^7.3.2" + "ansi-styles": "^3.2.1", + "chalk": "^3.0.0", + "strip-ansi": "^5.2.0", + "supports-color": "^5.4.0", + "tslib": "^1" }, "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } - } - } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@oclif/command": { + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@oclif/command/-/command-1.8.16.tgz", + "integrity": "sha512-rmVKYEsKzurfRU0xJz+iHelbi1LGlihIWZ7Qvmb/CBz1EkhL7nOkW4SVXmG2dA5Ce0si2gr88i6q4eBOMRNJ1w==", + "dev": true, + "requires": { + "@oclif/config": "^1.18.2", + "@oclif/errors": "^1.3.5", + "@oclif/help": "^1.0.1", + "@oclif/parser": "^3.8.6", + "debug": "^4.1.1", + "semver": "^7.3.2" + }, + "dependencies": { + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } }, "@oclif/config": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.2.tgz", - "integrity": "sha512-cE3qfHWv8hGRCP31j7fIS7BfCflm/BNZ2HNqHexH+fDrdF2f1D5S8VmXWLC77ffv3oDvWyvE9AZeR0RfmHCCaA==", + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.3.tgz", + "integrity": "sha512-sBpko86IrTscc39EvHUhL+c++81BVTsIZ3ETu/vG+cCdi0N6vb2DoahR67A9FI2CGnxRRHjnTfa3m6LulwNATA==", "dev": true, "requires": { - "@oclif/errors": "^1.3.3", + "@oclif/errors": "^1.3.5", "@oclif/parser": "^3.8.0", "debug": "^4.1.1", "globby": "^11.0.1", "is-wsl": "^2.1.1", - "tslib": "^2.0.0" + "tslib": "^2.3.1" + } + }, + "@oclif/core": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-1.7.0.tgz", + "integrity": "sha512-I4q4qgtnNG7ef4sBDrJhwADdi7RExQV7LnflnXaWZZDiUoqF9AdOjC4jjx40MK0rRrCehCUtPNZBcr3WmxuS4Q==", + "dev": true, + "requires": { + "@oclif/linewrap": "^1.0.0", + "@oclif/screen": "^3.0.2", + "ansi-escapes": "^4.3.2", + "ansi-styles": "^4.3.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.2", + "clean-stack": "^3.0.1", + "cli-progress": "^3.10.0", + "debug": "^4.3.3", + "ejs": "^3.1.6", + "fs-extra": "^9.1.0", + "get-package-type": "^0.1.0", + "globby": "^11.1.0", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.14.1", + "lodash": "^4.17.21", + "natural-orderby": "^2.0.3", + "object-treeify": "^1.1.33", + "password-prompt": "^1.1.2", + "semver": "^7.3.5", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "supports-color": "^8.1.1", + "supports-hyperlinks": "^2.2.0", + "tslib": "^2.3.1", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "@oclif/screen": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@oclif/screen/-/screen-3.0.2.tgz", + "integrity": "sha512-S/SF/XYJeevwIgHFmVDAFRUvM3m+OjhvCAYMk78ZJQCYCQ5wS7j+LTt1ZEv2jpEEGg2tx/F6TYYWxddNAYHrFQ==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } } }, "@oclif/errors": { @@ -1553,6 +1877,31 @@ "indent-string": "^4.0.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } + } + }, + "@oclif/fixpack": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@oclif/fixpack/-/fixpack-2.3.1.tgz", + "integrity": "sha512-ynDtqYke7WBjyAK5KQiOoNm2XGm4wBfNDzjbpq3k4NEarA5wRW0PMjdP2FkTAJE2NI3tA6I7DXxxqBzwyt+fBg==", + "dev": true, + "requires": { + "alce": "1.2.0", + "colors": "1.4.0", + "extend-object": "^1.0.0", + "rc": "^1.2.8" } }, "@oclif/help": { @@ -1572,6 +1921,20 @@ "wrap-ansi": "^6.2.0" }, "dependencies": { + "@oclif/config": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.2.tgz", + "integrity": "sha512-cE3qfHWv8hGRCP31j7fIS7BfCflm/BNZ2HNqHexH+fDrdF2f1D5S8VmXWLC77ffv3oDvWyvE9AZeR0RfmHCCaA==", + "dev": true, + "requires": { + "@oclif/errors": "^1.3.3", + "@oclif/parser": "^3.8.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-wsl": "^2.1.1", + "tslib": "^2.0.0" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -1641,15 +2004,15 @@ "dev": true }, "@oclif/parser": { - "version": "3.8.6", - "resolved": "https://registry.npmjs.org/@oclif/parser/-/parser-3.8.6.tgz", - "integrity": "sha512-tXb0NKgSgNxmf6baN6naK+CCwOueaFk93FG9u202U7mTBHUKsioOUlw1SG/iPi9aJM3WE4pHLXmty59pci0OEw==", + "version": "3.8.7", + "resolved": "https://registry.npmjs.org/@oclif/parser/-/parser-3.8.7.tgz", + "integrity": "sha512-b11xBmIUK+LuuwVGJpFs4LwQN2xj2cBWj2c4z1FtiXGrJ85h9xV6q+k136Hw0tGg1jQoRXuvuBnqQ7es7vO9/Q==", "dev": true, "requires": { - "@oclif/errors": "^1.2.2", + "@oclif/errors": "^1.3.5", "@oclif/linewrap": "^1.0.0", "chalk": "^4.1.0", - "tslib": "^2.0.0" + "tslib": "^2.3.1" }, "dependencies": { "ansi-styles": { @@ -1703,313 +2066,213 @@ } } }, - "@oclif/plugin-help": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-2.2.3.tgz", - "integrity": "sha512-bGHUdo5e7DjPJ0vTeRBMIrfqTRDBfyR5w0MP41u0n3r7YG5p14lvMmiCXxi6WDaP2Hw5nqx3PnkAIntCKZZN7g==", + "@oclif/plugin-autocomplete": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@oclif/plugin-autocomplete/-/plugin-autocomplete-0.3.0.tgz", + "integrity": "sha512-gCuIUCswvoU1BxDDvHSUGxW8rFagiacle8jHqE49+WnuniXD/N8NmJvnzmlNyc8qLE192CnKK+qYyAF+vaFQBg==", "dev": true, "requires": { "@oclif/command": "^1.5.13", - "chalk": "^2.4.1", - "indent-string": "^4.0.0", - "lodash.template": "^4.4.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0", - "widest-line": "^2.0.1", - "wrap-ansi": "^4.0.0" + "@oclif/config": "^1.13.0", + "chalk": "^4.1.0", + "cli-ux": "^5.2.1", + "debug": "^4.0.0", + "fs-extra": "^9.0.1", + "moment": "^2.22.1" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "type-fest": "^0.21.3" } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "color-convert": "^2.0.1" } }, - "widest-line": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", - "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", - "dev": true, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "requires": { - "string-width": "^2.1.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cli-ux": { + "version": "5.6.7", + "resolved": "https://registry.npmjs.org/cli-ux/-/cli-ux-5.6.7.tgz", + "integrity": "sha512-dsKAurMNyFDnO6X1TiiRNiVbL90XReLKcvIq4H777NMqXGBxBws23ag8ubCJE97vVZEgWG2eSUhsyLf63Jv8+g==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.15", + "@oclif/errors": "^1.3.5", + "@oclif/linewrap": "^1.0.0", + "@oclif/screen": "^1.0.4", + "ansi-escapes": "^4.3.0", + "ansi-styles": "^4.2.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.0", + "clean-stack": "^3.0.0", + "cli-progress": "^3.4.0", + "extract-stack": "^2.0.0", + "fs-extra": "^8.1", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.13.1", + "lodash": "^4.17.21", + "natural-orderby": "^2.0.1", + "object-treeify": "^1.1.4", + "password-prompt": "^1.1.2", + "semver": "^7.3.2", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "supports-color": "^8.1.0", + "supports-hyperlinks": "^2.1.0", + "tslib": "^2.0.0" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "has-flag": "^4.0.0" } } } }, - "wrap-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-4.0.0.tgz", - "integrity": "sha512-uMTsj9rDb0/7kk1PbcbCcwvHUxp60fGDB/NNXpVa0Q+ic/e7y5+BwTxKfQ33VYgDppSwi/FBzpetYzo8s6tfbg==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0" + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "extract-stack": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extract-stack/-/extract-stack-2.0.0.tgz", + "integrity": "sha512-AEo4zm+TenK7zQorGK1f9mJ8L14hnTDi2ZQPR+Mub1NX8zimka1mXpV5LpH8x9HoUmFSHZCfLHqWvp0Y4FxxzQ==", + "dev": true + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" } }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true } } - } - } - }, - "@oclif/screen": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@oclif/screen/-/screen-1.0.4.tgz", - "integrity": "sha512-60CHpq+eqnTxLZQ4PGHYNwUX572hgpMHGPtTWMjdTMsAvlm69lZV/4ly6O3sAYkomo4NggGcomrDpBe34rxUqw==", - "dev": true - }, - "@oclif/test": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/@oclif/test/-/test-1.2.9.tgz", - "integrity": "sha512-op+ak0NTyeBKqjLVH1jfPCRGWK5befIoQpCL/xwekjucUEmMfCbUpV1Sa60f9rU8X58HEqrclwWbAH+DtQR6FQ==", - "dev": true, - "requires": { - "fancy-test": "^1.4.10" - } - }, - "@prettier/plugin-xml": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@prettier/plugin-xml/-/plugin-xml-1.2.0.tgz", - "integrity": "sha512-bFvVAZKs59XNmntYjyefn3K4TBykS6E+d6ZW8IcylAs88ZO+TzLhp0dPpi0VKfPzq1Nb+kpDnPRTiwb4zY6NgA==", - "dev": true, - "requires": { - "@xml-tools/parser": "^1.0.11", - "prettier": ">=2.3" - } - }, - "@salesforce/bunyan": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@salesforce/bunyan/-/bunyan-2.0.0.tgz", - "integrity": "sha512-5hq+HWQSeymuygl3i9ehlQo3XWrlBE+A+QzmpDaoK37op4u9M+SBUbXfOW0IABOQCg+JmfQPocSMV74hRoqU9w==", - "dev": true, - "requires": { - "dayjs": "^1.8.16", - "dayjs-plugin-utc": "^0.1.2", - "dtrace-provider": "~0.6", - "mv": "~2", - "safe-json-stringify": "~1" - } - }, - "@salesforce/command": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@salesforce/command/-/command-3.1.3.tgz", - "integrity": "sha512-Yg9lhl3ghwPN7WwqFmgfWIn6i7vz43WTpEsYsChz80bKORlVbDvhwPZQUj0XTv3DKDnPZVU8FFIDsrLSOa9G1A==", - "dev": true, - "requires": { - "@oclif/command": "^1.5.17", - "@oclif/errors": "^1.2.2", - "@oclif/parser": "^3.8.3", - "@oclif/plugin-help": "^2.2.0", - "@oclif/test": "^1.2.4", - "@salesforce/core": "^2.23.4", - "@salesforce/kit": "^1.2.2", - "@salesforce/ts-types": "^1.2.0", - "chalk": "^2.4.2", - "cli-ux": "^4.9.3" - } - }, - "@salesforce/core": { - "version": "2.33.1", - "resolved": "https://registry.npmjs.org/@salesforce/core/-/core-2.33.1.tgz", - "integrity": "sha512-jKVFYEvlV+loBoau5heBOVXmzsPO+RbYh6SPybJK6xF7khQmzu7+WAQbikY2eY8VaXcded2kka8L/FKuD/LKBg==", - "dev": true, - "requires": { - "@salesforce/bunyan": "^2.0.0", - "@salesforce/kit": "^1.5.0", - "@salesforce/schemas": "^1.0.1", - "@salesforce/ts-types": "^1.5.13", - "@types/graceful-fs": "^4.1.5", - "@types/jsforce": "^1.9.35", - "@types/mkdirp": "^1.0.1", - "debug": "^3.1.0", - "faye": "^1.4.0", - "graceful-fs": "^4.2.4", - "jsen": "0.6.6", - "jsforce": "^1.11.0", - "jsonwebtoken": "8.5.0", - "mkdirp": "1.0.4", - "semver": "^7.3.5", - "ts-retry-promise": "^0.6.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { - "ms": "^2.1.1" + "lru-cache": "^6.0.0" } }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "has-flag": "^4.0.0" } - } - } - }, - "@salesforce/eslint-config-lwc": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@salesforce/eslint-config-lwc/-/eslint-config-lwc-3.2.1.tgz", - "integrity": "sha512-tX+HKTkgEEYSI/cggkeUkRT+m0Hrv3FmxLclRMjUZWDZQYggyLzpWkGX9Nkj69xRssHJ0N/7pE4UNlbqCNpbrQ==", - "dev": true, - "requires": { - "@babel/core": "~7.16.0", - "@babel/eslint-parser": "~7.16.0", - "eslint-restricted-globals": "~0.2.0", - "semver": "^7.3.5" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" } } } }, - "@salesforce/eslint-plugin-aura": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@salesforce/eslint-plugin-aura/-/eslint-plugin-aura-2.0.0.tgz", - "integrity": "sha512-SLLnPk2fl1HIccPJgB5d0FCmWX9tgBKiK6sINUVixDgFcXLzogrnOmv5oCbXKbcJuOIoeG/JJDNjcb/WbsyvgQ==", - "dev": true, - "requires": { - "eslint-plugin-compat": "^3.9.0" - } - }, - "@salesforce/eslint-plugin-lightning": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@salesforce/eslint-plugin-lightning/-/eslint-plugin-lightning-1.0.0.tgz", - "integrity": "sha512-zk0PKXAcHKHepAG2EOSWlkOTxQM0Aw1CT6+MUxJcM42fCDwH/yPPpGkG3CWtRfmVViODGOwU9ywU2wlkAYcvUQ==", - "dev": true - }, - "@salesforce/kit": { - "version": "1.5.25", - "resolved": "https://registry.npmjs.org/@salesforce/kit/-/kit-1.5.25.tgz", - "integrity": "sha512-Tbb7AZwJ00oGW8uv4DWsb3tjYi/rI8XWICWhLDpi44lTjrd+b22hKZMJLZ6XWEmezwtbzLT7vZIcj3IMtDgkIg==", - "dev": true, - "requires": { - "@salesforce/ts-types": "^1.5.20", - "shx": "^0.3.3", - "tslib": "^2.2.0" - } - }, - "@salesforce/schemas": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@salesforce/schemas/-/schemas-1.1.0.tgz", - "integrity": "sha512-6D7DvE6nFxpLyyTnrOIbbAeCJw2r/EpinFAcMh6gU0gA/CGfSbwV/8uR3uHLYL2zCyCZLH8jJ4dZ3BzCMqc+Eg==", - "dev": true - }, - "@salesforce/sfdx-lwc-jest": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@salesforce/sfdx-lwc-jest/-/sfdx-lwc-jest-1.1.0.tgz", - "integrity": "sha512-bYhvs9Th4qMjk4Vs66GDwloVh2LAcV8cg/j0WWbIug8MiI+KOSZL0IWZA7fqr8vXkSdArt5WjoTv4ckzfklzQA==", + "@oclif/plugin-commands": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@oclif/plugin-commands/-/plugin-commands-1.3.0.tgz", + "integrity": "sha512-Qx9gJ7/aPBgo+Q/DHmGcWyxn2/0bjqmCwt/nO0lWuTZQIH3ZTqclTm68TMZLS4QnQyDGeeYK0GqZ5qJlrXD+SQ==", "dev": true, "requires": { - "@lwc/compiler": "2.2.11", - "@lwc/engine-dom": "2.2.11", - "@lwc/jest-preset": "11.2.0", - "@lwc/jest-resolver": "11.2.0", - "@lwc/jest-serializer": "11.2.0", - "@lwc/jest-transformer": "11.2.0", - "@lwc/module-resolver": "2.2.11", - "@lwc/synthetic-shadow": "2.2.11", - "@lwc/wire-service": "2.2.11", - "@salesforce/wire-service-jest-util": "4.0.0", - "chalk": "~4.1.1", - "fast-glob": "^3.2.7", - "jest": "27.0.6", - "yargs": "~17.0.1" + "@oclif/command": "^1.5.4", + "@oclif/config": "^1.8.7", + "cli-ux": "^5.4.5", + "lodash": "^4.17.11" }, "dependencies": { + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2027,6 +2290,51 @@ "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "cli-ux": { + "version": "5.6.7", + "resolved": "https://registry.npmjs.org/cli-ux/-/cli-ux-5.6.7.tgz", + "integrity": "sha512-dsKAurMNyFDnO6X1TiiRNiVbL90XReLKcvIq4H777NMqXGBxBws23ag8ubCJE97vVZEgWG2eSUhsyLf63Jv8+g==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.15", + "@oclif/errors": "^1.3.5", + "@oclif/linewrap": "^1.0.0", + "@oclif/screen": "^1.0.4", + "ansi-escapes": "^4.3.0", + "ansi-styles": "^4.2.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.0", + "clean-stack": "^3.0.0", + "cli-progress": "^3.4.0", + "extract-stack": "^2.0.0", + "fs-extra": "^8.1", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.13.1", + "lodash": "^4.17.21", + "natural-orderby": "^2.0.1", + "object-treeify": "^1.1.4", + "password-prompt": "^1.1.2", + "semver": "^7.3.2", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "supports-color": "^8.1.0", + "supports-hyperlinks": "^2.1.0", + "tslib": "^2.0.0" } }, "color-convert": { @@ -2044,1011 +2352,904 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "extract-stack": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extract-stack/-/extract-stack-2.0.0.tgz", + "integrity": "sha512-AEo4zm+TenK7zQorGK1f9mJ8L14hnTDi2ZQPR+Mub1NX8zimka1mXpV5LpH8x9HoUmFSHZCfLHqWvp0Y4FxxzQ==", "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { "has-flag": "^4.0.0" } }, - "yargs": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.0.1.tgz", - "integrity": "sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ==", + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", "dev": true, "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } } } }, - "@salesforce/sfdx-scanner": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@salesforce/sfdx-scanner/-/sfdx-scanner-2.12.0.tgz", - "integrity": "sha512-0v7hA9c1y7DUUbbAAGA2ngr9cqQVUbiUgoaXCKoQYMFfEV2aSLft5MjAJ377lUNV8pjwPzeId2ndvIscNoZX/g==", + "@oclif/plugin-help": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-2.2.3.tgz", + "integrity": "sha512-bGHUdo5e7DjPJ0vTeRBMIrfqTRDBfyR5w0MP41u0n3r7YG5p14lvMmiCXxi6WDaP2Hw5nqx3PnkAIntCKZZN7g==", "dev": true, "requires": { - "@lwc/eslint-plugin-lwc": "^0.10.0", - "@oclif/command": "^1", - "@oclif/config": "^1", - "@oclif/errors": "^1", - "@salesforce/command": "^3", - "@salesforce/core": "^2.1.6", - "@salesforce/eslint-config-lwc": "^0.7.0", - "@typescript-eslint/eslint-plugin": "^2.21.0", - "@typescript-eslint/parser": "^2.21.0", - "babel-eslint": "^10.1.0", - "cross-spawn": "^7.0.3", - "eslint": "^6.8.0", - "find-java-home": "1.1.0", - "globby": "^11.0.0", - "html-escaper": "^3.0.0", - "is-zip": "^1.0.0", - "isbinaryfile": "^4.0.8", - "mustache": "^4.0.1", - "node-stream-zip": "1.13.2", - "normalize-path": "^3.0.0", - "picomatch": "^2.2.2", - "reflect-metadata": "^0.1.13", - "retire": "^2.2.5", - "semver": "^7.3.4", - "ts-node": "^8", - "tslib": "^2", - "tsyringe": "^4.1.0", - "typescript": "^3.8.2", - "untildify": "^4.0.0", - "word-wrap": "^1.2.3", - "xml-js": "^1.6.11" + "@oclif/command": "^1.5.13", + "chalk": "^2.4.1", + "indent-string": "^4.0.0", + "lodash.template": "^4.4.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0", + "widest-line": "^2.0.1", + "wrap-ansi": "^4.0.0" }, "dependencies": { - "@lwc/eslint-plugin-lwc": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@lwc/eslint-plugin-lwc/-/eslint-plugin-lwc-0.10.0.tgz", - "integrity": "sha512-UsosUow0xWrzzcSK1fWDWHKBT81/pJz1/icfv7w8T+BCE9G4Kb4TwJexHLOIZvY7e/dv4Fjme4lTOWehuNE5Sg==", - "dev": true, - "requires": { - "minimatch": "^3.0.4" - } + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true }, - "@salesforce/eslint-config-lwc": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@salesforce/eslint-config-lwc/-/eslint-config-lwc-0.7.0.tgz", - "integrity": "sha512-x87H9+amXcPDmOnOZoLdajp5yNZqv8ieyzfE4R8QDOJeZfj1X5I2AOSZYG0pUV51eUV/kOdGjAj28zU296t2yQ==", + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { - "@lwc/eslint-plugin-lwc": "~0.10.0", - "babel-eslint": "~10.1.0", - "eslint-plugin-import": "~2.20.2", - "eslint-plugin-jest": "~23.8.2", - "eslint-restricted-globals": "~0.2.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" } }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ms": "2.0.0" + "ansi-regex": "^4.1.0" } }, - "eslint": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", - "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "widest-line": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", + "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.3", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.2", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^7.0.0", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.3", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "string-width": "^2.1.1" }, "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "ms": "2.1.2" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "esutils": "^2.0.2" + "ansi-regex": "^3.0.0" } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true } } }, - "eslint-plugin-import": { - "version": "2.20.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.2.tgz", - "integrity": "sha512-FObidqpXrR8OnCh4iNsxy+WACztJLXAHBO5hK79T1Hc77PgQZkyDGA5Ag9xAvRpglvLNxhH/zSmZ70/pZ31dHg==", + "wrap-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-4.0.0.tgz", + "integrity": "sha512-uMTsj9rDb0/7kk1PbcbCcwvHUxp60fGDB/NNXpVa0Q+ic/e7y5+BwTxKfQ33VYgDppSwi/FBzpetYzo8s6tfbg==", "dev": true, "requires": { - "array-includes": "^3.0.3", - "array.prototype.flat": "^1.2.1", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.4.1", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.0", - "read-pkg-up": "^2.0.0", - "resolve": "^1.12.0" + "ansi-styles": "^3.2.0", + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + } + } + }, + "@oclif/plugin-not-found": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@oclif/plugin-not-found/-/plugin-not-found-1.2.6.tgz", + "integrity": "sha512-cfkDub79I9EpselfU/W8FTXhslrkOgfqjaa25tyGo99dAX5UVr6BWL2wbUobsU+rUcm4HN3byzdHDcqfu6hoAw==", + "dev": true, + "requires": { + "@oclif/color": "^0.1.2", + "@oclif/command": "1.8.11", + "cli-ux": "5.6.6", + "fast-levenshtein": "^3.0.0", + "lodash": "^4.17.21" + }, + "dependencies": { + "@oclif/command": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/@oclif/command/-/command-1.8.11.tgz", + "integrity": "sha512-2fGLMvi6J5+oNxTaZfdWPMWY8oW15rYj0V8yLzmZBAEjfzjLqLIzJE9IlNccN1zwRqRHc1bcISSRDdxJ56IS/Q==", + "dev": true, + "requires": { + "@oclif/config": "^1.18.2", + "@oclif/errors": "^1.3.5", + "@oclif/parser": "^3.8.6", + "@oclif/plugin-help": "3.2.14", + "debug": "^4.1.1", + "semver": "^7.3.2" } }, - "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "@oclif/plugin-help": { + "version": "3.2.14", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-3.2.14.tgz", + "integrity": "sha512-NP5qmE2YfcW3MmXjcrxiqKe9Hf3G0uK/qNc0zAMYKU4crFyIsWj7dBfQVFZSb28YXGioOOpjMzG1I7VMxKF38Q==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "@oclif/command": "^1.8.9", + "@oclif/config": "^1.18.2", + "@oclif/errors": "^1.3.5", + "chalk": "^4.1.2", + "indent-string": "^4.0.0", + "lodash": "^4.17.21", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "widest-line": "^3.1.0", + "wrap-ansi": "^6.2.0" } }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "type-fest": "^0.8.1" + "color-convert": "^2.0.1" } }, - "html-escaper": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", - "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", - "dev": true + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true + "cli-ux": { + "version": "5.6.6", + "resolved": "https://registry.npmjs.org/cli-ux/-/cli-ux-5.6.6.tgz", + "integrity": "sha512-4wUB34zoFklcZV0z5YiOM5IqVMMt9c3TK3QYRK3dqyk3XoRC0ybiWDWHfsMDjkKrzsVTw95rXn9NrzSHbae4pg==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.9", + "@oclif/errors": "^1.3.5", + "@oclif/linewrap": "^1.0.0", + "@oclif/screen": "^1.0.4", + "ansi-escapes": "^4.3.0", + "ansi-styles": "^4.2.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.0", + "clean-stack": "^3.0.0", + "cli-progress": "^3.4.0", + "extract-stack": "^2.0.0", + "fs-extra": "^8.1", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.13.1", + "lodash": "^4.17.21", + "natural-orderby": "^2.0.1", + "object-treeify": "^1.1.4", + "password-prompt": "^1.1.2", + "semver": "^7.3.2", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "supports-color": "^8.1.0", + "supports-hyperlinks": "^2.1.0", + "tslib": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "minimist": "^1.2.5" + "color-name": "~1.1.4" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "extract-stack": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extract-stack/-/extract-stack-2.0.0.tgz", + "integrity": "sha512-AEo4zm+TenK7zQorGK1f9mJ8L14hnTDi2ZQPR+Mub1NX8zimka1mXpV5LpH8x9HoUmFSHZCfLHqWvp0Y4FxxzQ==", "dev": true }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "fast-levenshtein": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz", + "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==", + "dev": true, + "requires": { + "fastest-levenshtein": "^1.0.7" + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" } }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "has-flag": "^4.0.0" } }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" } }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "requires": { - "isexe": "^2.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } } } }, - "@salesforce/ts-types": { - "version": "1.5.20", - "resolved": "https://registry.npmjs.org/@salesforce/ts-types/-/ts-types-1.5.20.tgz", - "integrity": "sha512-Ov6um4CWd63EvkRavkHG0J/P9XYL55sdkDWPMr7+AIgqh5flHxDRz09/C4e9M94aX30rzJxW4TVX6EBf4Cu2BQ==", - "dev": true, - "requires": { - "tslib": "^2.2.0" - } - }, - "@salesforce/wire-service-jest-util": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@salesforce/wire-service-jest-util/-/wire-service-jest-util-4.0.0.tgz", - "integrity": "sha512-YJO/bMq5l6IYIZG6bAqYzzbmZMPCzB2GE2TKGLA1U7B9HpmNHZS7DdDcy154P03dfLSgF+tgVYeklh2HRYGk9g==", - "dev": true - }, - "@sideway/address": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.3.tgz", - "integrity": "sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ==", - "dev": true, - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@sideway/formula": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", - "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==", - "dev": true - }, - "@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", - "dev": true - }, - "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, - "@types/babel__core": { - "version": "7.1.18", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", - "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "@oclif/plugin-plugins": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@oclif/plugin-plugins/-/plugin-plugins-1.10.11.tgz", + "integrity": "sha512-C9eHF10UkxwoAqRYrPW51YDuDOpDXASX4BEA++kTVcqhMQTKBQalmEJKw+gVnLl1YNmapse1ZSAcU1TrXjqykg==", "dev": true, "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/chai": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz", - "integrity": "sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==", - "dev": true - }, - "@types/eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", - "dev": true - }, - "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/jsforce": { - "version": "1.9.38", - "resolved": "https://registry.npmjs.org/@types/jsforce/-/jsforce-1.9.38.tgz", - "integrity": "sha512-+Iwf5jlDiK8z+zI2LAi4mzln8++5lETv2YofFEATu+dNkrP8LACB76lz2tPsXDx/a+5uW8HQhbwL/SyqIic0cg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", - "dev": true - }, - "@types/lodash": { - "version": "4.14.178", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", - "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==", - "dev": true - }, - "@types/mkdirp": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.2.tgz", - "integrity": "sha512-o0K1tSO0Dx5X6xlU5F1D6625FawhC3dU3iqr25lluNv/+/QIVH8RLNEiVokgIZo+mz+87w/3Mkg/VvQS+J51fQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/node": { - "version": "6.14.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-6.14.13.tgz", - "integrity": "sha512-J1F0XJ/9zxlZel5ZlbeSuHW2OpabrUAqpFuC2sm2I3by8sERQ8+KCjNKUcq8QHuzpGMWiJpo9ZxeHrqrP2KzQw==", - "dev": true - }, - "@types/prettier": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.2.tgz", - "integrity": "sha512-ekoj4qOQYp7CvjX8ZDBgN86w3MqQhLE1hczEJbEIjgFEumDy+na/4AJAbLXfgEWFNB2pKadM5rPFtuSGMWK7xA==", - "dev": true - }, - "@types/sinon": { - "version": "10.0.6", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.6.tgz", - "integrity": "sha512-6EF+wzMWvBNeGrfP3Nx60hhx+FfwSg1JJBLAAP/IdIUq0EYkqCYf70VT3PhuhPX9eLD+Dp+lNdpb/ZeHG8Yezg==", - "dev": true, - "requires": { - "@sinonjs/fake-timers": "^7.1.0" + "@oclif/color": "^0.1.2", + "@oclif/command": "^1.8.15", + "@oclif/errors": "^1.3.5", + "chalk": "^4.1.2", + "cli-ux": "^5.6.7", + "debug": "^4.3.3", + "fs-extra": "^9.0", + "http-call": "^5.3.0", + "load-json-file": "^5.3.0", + "npm-run-path": "^4.0.1", + "semver": "^7.3.2", + "tslib": "^2.0.0", + "yarn": "^1.21.1" }, "dependencies": { - "@sinonjs/fake-timers": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", - "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "requires": { - "@sinonjs/commons": "^1.7.0" + "type-fest": "^0.21.3" } - } - } - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz", - "integrity": "sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "2.34.0", - "functional-red-black-tree": "^1.0.1", - "regexpp": "^3.0.0", - "tsutils": "^3.17.1" - } - }, - "@typescript-eslint/experimental-utils": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz", - "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.34.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" - } - }, - "@typescript-eslint/parser": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.34.0.tgz", - "integrity": "sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==", - "dev": true, - "requires": { - "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.34.0", - "@typescript-eslint/typescript-estree": "2.34.0", - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cli-ux": { + "version": "5.6.7", + "resolved": "https://registry.npmjs.org/cli-ux/-/cli-ux-5.6.7.tgz", + "integrity": "sha512-dsKAurMNyFDnO6X1TiiRNiVbL90XReLKcvIq4H777NMqXGBxBws23ag8ubCJE97vVZEgWG2eSUhsyLf63Jv8+g==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.15", + "@oclif/errors": "^1.3.5", + "@oclif/linewrap": "^1.0.0", + "@oclif/screen": "^1.0.4", + "ansi-escapes": "^4.3.0", + "ansi-styles": "^4.2.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.0", + "clean-stack": "^3.0.0", + "cli-progress": "^3.4.0", + "extract-stack": "^2.0.0", + "fs-extra": "^8.1", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.13.1", + "lodash": "^4.17.21", + "natural-orderby": "^2.0.1", + "object-treeify": "^1.1.4", + "password-prompt": "^1.1.2", + "semver": "^7.3.2", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "supports-color": "^8.1.0", + "supports-hyperlinks": "^2.1.0", + "tslib": "^2.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true - } - } - }, - "@typescript-eslint/typescript-estree": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", - "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "eslint-visitor-keys": "^1.1.0", - "glob": "^7.1.6", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + }, + "extract-stack": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extract-stack/-/extract-stack-2.0.0.tgz", + "integrity": "sha512-AEo4zm+TenK7zQorGK1f9mJ8L14hnTDi2ZQPR+Mub1NX8zimka1mXpV5LpH8x9HoUmFSHZCfLHqWvp0Y4FxxzQ==", "dev": true }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "dependencies": { + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } } - } - } - }, - "@xml-tools/parser": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@xml-tools/parser/-/parser-1.0.11.tgz", - "integrity": "sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==", - "dev": true, - "requires": { - "chevrotain": "7.1.1" - } - }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "acorn": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", - "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", - "dev": true - }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - }, - "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "load-json-file": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", + "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "parse-json": "^4.0.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0", + "type-fest": "^0.3.0" + }, + "dependencies": { + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + } + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } } } }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "@oclif/plugin-update": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@oclif/plugin-update/-/plugin-update-1.5.0.tgz", + "integrity": "sha512-GsWK1CMeBBO8YknThoOZulj3xE+ZgZAXW1ouNJALXcs3mbROzszLDGjXV3RM6ffbJpnWLiMIqSFNOE8d+vGcgQ==", "dev": true, "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" + "@oclif/color": "^0.1.0", + "@oclif/command": "^1.7.0", + "@oclif/config": "^1.16.0", + "@oclif/errors": "^1.3.4", + "@types/semver": "^7.3.4", + "cli-ux": "^5.5.1", + "cross-spawn": "^7.0.3", + "debug": "^4.3.1", + "filesize": "^6.1.0", + "fs-extra": "^9.0.1", + "http-call": "^5.3.0", + "lodash": "^4.17.21", + "log-chopper": "^1.0.2", + "semver": "^7.3.5", + "tar-fs": "^2.1.1" }, "dependencies": { - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "cli-ux": { + "version": "5.6.7", + "resolved": "https://registry.npmjs.org/cli-ux/-/cli-ux-5.6.7.tgz", + "integrity": "sha512-dsKAurMNyFDnO6X1TiiRNiVbL90XReLKcvIq4H777NMqXGBxBws23ag8ubCJE97vVZEgWG2eSUhsyLf63Jv8+g==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.15", + "@oclif/errors": "^1.3.5", + "@oclif/linewrap": "^1.0.0", + "@oclif/screen": "^1.0.4", + "ansi-escapes": "^4.3.0", + "ansi-styles": "^4.2.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.0", + "clean-stack": "^3.0.0", + "cli-progress": "^3.4.0", + "extract-stack": "^2.0.0", + "fs-extra": "^8.1", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.13.1", + "lodash": "^4.17.21", + "natural-orderby": "^2.0.1", + "object-treeify": "^1.1.4", + "password-prompt": "^1.1.2", + "semver": "^7.3.2", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "supports-color": "^8.1.0", + "supports-hyperlinks": "^2.1.0", + "tslib": "^2.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "extract-stack": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extract-stack/-/extract-stack-2.0.0.tgz", + "integrity": "sha512-AEo4zm+TenK7zQorGK1f9mJ8L14hnTDi2ZQPR+Mub1NX8zimka1mXpV5LpH8x9HoUmFSHZCfLHqWvp0Y4FxxzQ==", + "dev": true + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "dependencies": { + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } } } }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "@oclif/plugin-warn-if-update-available": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-1.7.3.tgz", + "integrity": "sha512-q8q0NIneVCwIAJzglUMsl3EbXR/H5aPDk6g+qs7uF0tToxe07SWSONoNaKPzViwRWvYChMPjL77/rXyW1HVn4A==", "dev": true, "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-escape-sequences": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-escape-sequences/-/ansi-escape-sequences-4.1.0.tgz", - "integrity": "sha512-dzW9kHxH011uBsidTXd14JXgzye/YLb2LzeKZ4bsgl/Knwx8AtbSFkkGxagdNOoh0DlqHCmfiEjWKBaqjOanVw==", - "dev": true, - "requires": { - "array-back": "^3.0.1" - }, - "dependencies": { - "array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", - "dev": true - } - } - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "ansicolors": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", - "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", - "dev": true - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "archiver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.0.tgz", - "integrity": "sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg==", - "dev": true, - "requires": { - "archiver-utils": "^2.1.0", - "async": "^3.2.0", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", - "readdir-glob": "^1.0.0", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", - "dev": true, - "requires": { - "glob": "^7.1.4", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-back": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.0.tgz", - "integrity": "sha512-mixVv03GOOn/ubHE4STQ+uevX42ETdk0JoMVEjNkSOCT7WgERh7C8/+NyhWYNpE3BN69pxFyJIBcF7CxWz/+4A==", - "dev": true - }, - "array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" - } - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true - }, - "asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "ast-metadata-inferer": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/ast-metadata-inferer/-/ast-metadata-inferer-0.7.0.tgz", - "integrity": "sha512-OkMLzd8xelb3gmnp6ToFvvsHLtS6CbagTkFQvQ+ZYFe3/AIl9iKikNR9G7pY3GfOR/2Xc222hwBjzI7HLkE76Q==", - "dev": true, - "requires": { - "@mdn/browser-compat-data": "^3.3.14" - } - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, - "astring": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/astring/-/astring-1.7.6.tgz", - "integrity": "sha512-7ofuRb7zx2u7T4OGZTtfkGKAfPKq72XQ7zgpI2b3pR3wdROrDIDmKPtrel7D8S4t+97SGpYTpDR6lq5cNX/DJw==", - "dev": true - }, - "async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, - "axios": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", - "dev": true, - "requires": { - "follow-redirects": "^1.14.0" - } - }, - "babel-eslint": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", - "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.7.0", - "@babel/traverse": "^7.7.0", - "@babel/types": "^7.7.0", - "eslint-visitor-keys": "^1.0.0", - "resolve": "^1.12.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "babel-jest": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.5.tgz", - "integrity": "sha512-3uuUTjXbgtODmSv/DXO9nZfD52IyC2OYTFaXGRzL0kpykzroaquCrD5+lZNafTvZlnNqZHt5pb0M08qVBZnsnA==", - "dev": true, - "requires": { - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^27.4.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" + "@oclif/command": "^1.8.6", + "@oclif/config": "^1.17.1", + "@oclif/errors": "^1.3.5", + "chalk": "^4.1.0", + "debug": "^4.1.0", + "fs-extra": "^9.0.1", + "http-call": "^5.2.2", + "lodash": "^4.17.21", + "semver": "^7.3.2" }, "dependencies": { "ansi-styles": { @@ -3085,11 +3286,42 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, "supports-color": { "version": "7.2.0", @@ -3099,2552 +3331,11346 @@ "requires": { "has-flag": "^4.0.0" } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true } } }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "@oclif/plugin-which": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@oclif/plugin-which/-/plugin-which-1.0.4.tgz", + "integrity": "sha512-xuJVhnUDiKIPIw5i6GiQnB3QZ55ie7ucrI6/P0TQWx+1BEt3xl6tEs/vFqnyFuDOh8fc0ZwYTBWFUWkQfYsv4w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" + "@oclif/command": "1.8.11", + "@oclif/config": "1.18.2", + "cli-ux": "5.6.6", + "tslib": "^2.0.0" }, "dependencies": { - "istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", + "@oclif/command": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/@oclif/command/-/command-1.8.11.tgz", + "integrity": "sha512-2fGLMvi6J5+oNxTaZfdWPMWY8oW15rYj0V8yLzmZBAEjfzjLqLIzJE9IlNccN1zwRqRHc1bcISSRDdxJ56IS/Q==", + "dev": true, + "requires": { + "@oclif/config": "^1.18.2", + "@oclif/errors": "^1.3.5", + "@oclif/parser": "^3.8.6", + "@oclif/plugin-help": "3.2.14", + "debug": "^4.1.1", + "semver": "^7.3.2" + } + }, + "@oclif/config": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.2.tgz", + "integrity": "sha512-cE3qfHWv8hGRCP31j7fIS7BfCflm/BNZ2HNqHexH+fDrdF2f1D5S8VmXWLC77ffv3oDvWyvE9AZeR0RfmHCCaA==", + "dev": true, + "requires": { + "@oclif/errors": "^1.3.3", + "@oclif/parser": "^3.8.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-wsl": "^2.1.1", + "tslib": "^2.0.0" + } + }, + "@oclif/plugin-help": { + "version": "3.2.14", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-3.2.14.tgz", + "integrity": "sha512-NP5qmE2YfcW3MmXjcrxiqKe9Hf3G0uK/qNc0zAMYKU4crFyIsWj7dBfQVFZSb28YXGioOOpjMzG1I7VMxKF38Q==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.9", + "@oclif/config": "^1.18.2", + "@oclif/errors": "^1.3.5", + "chalk": "^4.1.2", + "indent-string": "^4.0.0", + "lodash": "^4.17.21", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "widest-line": "^3.1.0", + "wrap-ansi": "^6.2.0" + } + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cli-ux": { + "version": "5.6.6", + "resolved": "https://registry.npmjs.org/cli-ux/-/cli-ux-5.6.6.tgz", + "integrity": "sha512-4wUB34zoFklcZV0z5YiOM5IqVMMt9c3TK3QYRK3dqyk3XoRC0ybiWDWHfsMDjkKrzsVTw95rXn9NrzSHbae4pg==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.9", + "@oclif/errors": "^1.3.5", + "@oclif/linewrap": "^1.0.0", + "@oclif/screen": "^1.0.4", + "ansi-escapes": "^4.3.0", + "ansi-styles": "^4.2.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.0", + "clean-stack": "^3.0.0", + "cli-progress": "^3.4.0", + "extract-stack": "^2.0.0", + "fs-extra": "^8.1", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.13.1", + "lodash": "^4.17.21", + "natural-orderby": "^2.0.1", + "object-treeify": "^1.1.4", + "password-prompt": "^1.1.2", + "semver": "^7.3.2", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "supports-color": "^8.1.0", + "supports-hyperlinks": "^2.1.0", + "tslib": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "extract-stack": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extract-stack/-/extract-stack-2.0.0.tgz", + "integrity": "sha512-AEo4zm+TenK7zQorGK1f9mJ8L14hnTDi2ZQPR+Mub1NX8zimka1mXpV5LpH8x9HoUmFSHZCfLHqWvp0Y4FxxzQ==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } } } }, - "babel-plugin-jest-hoist": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz", - "integrity": "sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw==", + "@oclif/screen": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@oclif/screen/-/screen-1.0.4.tgz", + "integrity": "sha512-60CHpq+eqnTxLZQ4PGHYNwUX572hgpMHGPtTWMjdTMsAvlm69lZV/4ly6O3sAYkomo4NggGcomrDpBe34rxUqw==", + "dev": true + }, + "@oclif/test": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@oclif/test/-/test-1.2.9.tgz", + "integrity": "sha512-op+ak0NTyeBKqjLVH1jfPCRGWK5befIoQpCL/xwekjucUEmMfCbUpV1Sa60f9rU8X58HEqrclwWbAH+DtQR6FQ==", "dev": true, "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" + "fancy-test": "^1.4.10" } }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "@prettier/plugin-xml": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@prettier/plugin-xml/-/plugin-xml-2.0.1.tgz", + "integrity": "sha512-zJ2+/J5ujo23oHwaiuo3DEnxnRWSw/52IP7to+XmHiTC/qG17w2ld6FbDfVrsnO2PTPp0HFotPtZFlbrPJnaqA==", "dev": true, "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" + "@xml-tools/parser": "^1.0.11", + "prettier": ">=2.4.0" } }, - "babel-preset-jest": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz", - "integrity": "sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg==", + "@salesforce/apex-node": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@salesforce/apex-node/-/apex-node-0.11.0.tgz", + "integrity": "sha512-7x3QoTcl+5zKQ/PHglBz/IdJuMO65hbzboS2uTMISrFVzeeB06sDeGcv41IfrXn1dxR7NHJm+J3FE70zCgW/7w==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^27.4.0", - "babel-preset-current-node-syntax": "^1.0.0" + "@salesforce/core": "^2.35.0", + "faye": "1.4.0" } }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "base64-url": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-2.3.3.tgz", - "integrity": "sha512-dLMhIsK7OplcDauDH/tZLvK7JmUZK3A7KiQpjNzsBrM6Etw7hzNI1tLEywqJk9NnwkgWuFKSlx/IUO7vF6Mo8Q==", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "@salesforce/bunyan": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@salesforce/bunyan/-/bunyan-2.0.0.tgz", + "integrity": "sha512-5hq+HWQSeymuygl3i9ehlQo3XWrlBE+A+QzmpDaoK37op4u9M+SBUbXfOW0IABOQCg+JmfQPocSMV74hRoqU9w==", "dev": true, "requires": { - "tweetnacl": "^0.14.3" + "dayjs": "^1.8.16", + "dayjs-plugin-utc": "^0.1.2", + "dtrace-provider": "~0.6", + "mv": "~2", + "safe-json-stringify": "~1" } }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "@salesforce/command": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@salesforce/command/-/command-4.2.2.tgz", + "integrity": "sha512-2QEtPIMaeRyUEnLmPHJ1PhfKDJBupfQS5T4nG8rXpK2yOznBu48aPWaWCYErrxyC0bPa5eoFACeyPWz1k9QMog==", "dev": true, "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "@oclif/command": "^1.8.1", + "@oclif/errors": "^1.2.2", + "@oclif/parser": "3.8.6", + "@oclif/plugin-help": "^2.2.0", + "@oclif/test": "^1.2.4", + "@salesforce/core": "^2.35.0", + "@salesforce/kit": "^1.5.17", + "@salesforce/ts-types": "^1.5.20", + "chalk": "^2.4.2", + "cli-ux": "^4.9.3" }, "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "@oclif/parser": { + "version": "3.8.6", + "resolved": "https://registry.npmjs.org/@oclif/parser/-/parser-3.8.6.tgz", + "integrity": "sha512-tXb0NKgSgNxmf6baN6naK+CCwOueaFk93FG9u202U7mTBHUKsioOUlw1SG/iPi9aJM3WE4pHLXmty59pci0OEw==", "dev": true, "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "@oclif/errors": "^1.2.2", + "@oclif/linewrap": "^1.0.0", + "chalk": "^4.1.0", + "tslib": "^2.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" } } } }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", - "escalade": "^3.1.1", - "node-releases": "^2.0.1", - "picocolors": "^1.0.0" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=", - "dev": true - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "cache-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-2.0.0.tgz", - "integrity": "sha512-4gkeHlFpSKgm3vm2gJN5sPqfmijYRFYCQ6tv5cLw0xVmT6r1z1vd4FNnpuOREco3cBs1G709sZ72LdgddKvL5w==", + "@salesforce/core": { + "version": "2.36.0", + "resolved": "https://registry.npmjs.org/@salesforce/core/-/core-2.36.0.tgz", + "integrity": "sha512-VsKt7SXArxrOelaJl5Ez21Pmtdp2eU6qimqZ5clxnNaZDZKOySDPYnKHu7AYCt1LUNFN9cfsX8K5yOHxS+wT+w==", "dev": true, "requires": { - "array-back": "^4.0.1", - "fs-then-native": "^2.0.0", - "mkdirp2": "^1.0.4" + "@salesforce/bunyan": "^2.0.0", + "@salesforce/kit": "^1.5.17", + "@salesforce/schemas": "^1.0.1", + "@salesforce/ts-types": "^1.5.20", + "@types/graceful-fs": "^4.1.5", + "@types/jsforce": "^1.9.41", + "@types/mkdirp": "^1.0.1", + "archiver": "^5.3.0", + "debug": "^3.1.0", + "faye": "^1.4.0", + "graceful-fs": "^4.2.4", + "js2xmlparser": "^4.0.1", + "jsen": "0.6.6", + "jsforce": "^1.11.0", + "jsonwebtoken": "8.5.0", + "mkdirp": "1.0.4", + "semver": "^7.3.5", + "ts-retry-promise": "^0.6.0" }, "dependencies": { - "array-back": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", - "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } } } }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "@salesforce/eslint-config-lwc": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@salesforce/eslint-config-lwc/-/eslint-config-lwc-3.3.0.tgz", + "integrity": "sha512-eisGB/HsAlkzrClrHdcixmIP4b/0sfD+U6WMwIvMjsQ10WkIemuPMEr15Jr3nDQI61iQujlpkmEl5Iqp7ZbZRA==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "@babel/core": "~7.17.8", + "@babel/eslint-parser": "~7.17.0", + "eslint-restricted-globals": "~0.2.0", + "semver": "^7.3.5" + }, + "dependencies": { + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001295", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001295.tgz", - "integrity": "sha512-lSP16vcyC0FEy0R4ECc9duSPoKoZy+YkpGkue9G4D81OfPnliopaZrU10+qtPdT8PbGXad/PNx43TIQrOmJZSQ==", - "dev": true - }, - "cardinal": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", - "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", + "@salesforce/eslint-plugin-aura": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@salesforce/eslint-plugin-aura/-/eslint-plugin-aura-2.1.0.tgz", + "integrity": "sha512-7HfwSBKTHQZQboLoEhkBY7bYR9wTaT+G5jHXGlq8y31hEnNhJXRZ+RERDEwDm1jYa2SV9lE8nMNr0/8EKIGjlQ==", "dev": true, "requires": { - "ansicolors": "~0.3.2", - "redeyed": "~2.1.0" + "eslint-plugin-compat": "^4.0.2" } }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "@salesforce/eslint-plugin-lightning": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@salesforce/eslint-plugin-lightning/-/eslint-plugin-lightning-1.0.0.tgz", + "integrity": "sha512-zk0PKXAcHKHepAG2EOSWlkOTxQM0Aw1CT6+MUxJcM42fCDwH/yPPpGkG3CWtRfmVViODGOwU9ywU2wlkAYcvUQ==", "dev": true }, - "catharsis": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", - "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "@salesforce/kit": { + "version": "1.5.38", + "resolved": "https://registry.npmjs.org/@salesforce/kit/-/kit-1.5.38.tgz", + "integrity": "sha512-tAz5oWTlHW4VkQqWilaHihuiFf/opzbhfL6JK1TPtY8CyKCwCMPchoWafe+pCKWOSFTu+WzT/er06zVYC4ITrw==", "dev": true, "requires": { - "lodash": "^4.17.15" + "@salesforce/ts-types": "^1.5.20", + "shx": "^0.3.3", + "tslib": "^2.2.0" } }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "@salesforce/lazy-require": { + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/@salesforce/lazy-require/-/lazy-require-0.4.21.tgz", + "integrity": "sha512-JOfqvHXXhTRjJre84N8vB7u8s3g+8DzhDSHimCuMIn2uv7SQil5TXmvAu8eld7D5L9yzs1w25kGVeCHdUK/lAw==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "debug": "^4.3.1", + "tslib": "^2.2.0" } }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "chevrotain": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-7.1.1.tgz", - "integrity": "sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw==", + "@salesforce/plugin-alias": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-alias/-/plugin-alias-2.0.0.tgz", + "integrity": "sha512-v4nS3dw7qxbWqYja7XL6xPZuJPj7hiy9kuam4bxOyMgqGQBGjeeMbdjJpNmv2MaeAC/+QoZWSB6MUjnP6GTAEw==", "dev": true, "requires": { - "regexp-to-ast": "0.5.0" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "clean-stack": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", - "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", - "dev": true, - "requires": { - "escape-string-regexp": "4.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - } - } - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-truncate": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", - "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", - "dev": true, - "requires": { - "slice-ansi": "^5.0.0", - "string-width": "^5.0.0" + "@oclif/core": "^1.5.1", + "@salesforce/command": "^5.0.0", + "@salesforce/core": "^3.7.8", + "chalk": "^4.1.2", + "tslib": "^2" }, "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true - }, - "ansi-styles": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz", - "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==", - "dev": true + "@oclif/plugin-help": { + "version": "5.1.12", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-5.1.12.tgz", + "integrity": "sha512-HvH/RubJxqCinP0vUWQLTOboT+SfjfL8h40s+PymkWaldIcXlpoRaJX50vz+SjZIs7uewZwEk8fzLqpF/BWXlg==", + "dev": true, + "requires": { + "@oclif/core": "^1.3.6" + } }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "@oclif/test": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@oclif/test/-/test-2.1.0.tgz", + "integrity": "sha512-o+JTv3k28aMUxywJUlJY1/DORLqumoZFRII492phOmtXM16rD6Luy3z1qinT4BvEtPj2BzOPd2whr/VdYszaYw==", + "dev": true, + "requires": { + "@oclif/core": "^1.3.1", + "fancy-test": "^2.0.0" + } }, - "is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true + "@salesforce/command": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@salesforce/command/-/command-5.0.5.tgz", + "integrity": "sha512-zutR54SbdBZNzb2UVKdfe7/3sPMi5v8gPaSWvTSRjaOmRI476EE5xosKc0X1Svm39QKobho04Rkqn8r+r78lgA==", + "dev": true, + "requires": { + "@oclif/core": "^1.5.2", + "@oclif/plugin-help": "^5.1.11", + "@oclif/test": "^2.1.0", + "@salesforce/core": "^3.7.9", + "@salesforce/kit": "^1.5.34", + "@salesforce/ts-types": "^1.5.20", + "chalk": "^2.4.2" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } }, - "slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "@salesforce/core": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@salesforce/core/-/core-3.12.1.tgz", + "integrity": "sha512-j7WvlPwhTLBMBdnF/6Og3oqcM72tGqK99UHK/UqJpGaX0HcadnxMyL3uOMi8aAautvg4BnpfGjesn0pinqKVXw==", "dev": true, "requires": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" + "@salesforce/bunyan": "^2.0.0", + "@salesforce/kit": "^1.5.34", + "@salesforce/schemas": "^1.1.0", + "@salesforce/ts-types": "^1.5.20", + "@types/graceful-fs": "^4.1.5", + "@types/mkdirp": "^1.0.2", + "@types/semver": "^7.3.9", + "archiver": "^5.3.0", + "change-case": "^4.1.2", + "debug": "^3.2.7", + "faye": "^1.4.0", + "form-data": "^4.0.0", + "graceful-fs": "^4.2.9", + "js2xmlparser": "^4.0.1", + "jsen": "0.6.6", + "jsforce": "2.0.0-beta.7", + "jsonwebtoken": "8.5.1", + "mkdirp": "1.0.4", + "ts-retry-promise": "^0.6.0" } }, - "string-width": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.0.tgz", - "integrity": "sha512-7x54QnN21P+XL/v8SuNKvfgsUre6PXpN7mc77N3HlZv+f1SBRGmjxtOud2Z6FZ8DmdkD/IdjCaf9XXbnqmTZGQ==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "ansi-regex": "^6.0.1" + "color-name": "~1.1.4" } - } - } - }, - "cli-ux": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/cli-ux/-/cli-ux-4.9.3.tgz", - "integrity": "sha512-/1owvF0SZ5Gn54cgrikJ0QskgTzeg30HGjkmjFoaHDJzAqFpuX1DBpFR8aLvsE1J5s9MgeYRENQK4BFwOag5VA==", - "dev": true, - "requires": { - "@oclif/errors": "^1.2.2", - "@oclif/linewrap": "^1.0.0", - "@oclif/screen": "^1.0.3", - "ansi-escapes": "^3.1.0", - "ansi-styles": "^3.2.1", - "cardinal": "^2.1.1", - "chalk": "^2.4.1", - "clean-stack": "^2.0.0", - "extract-stack": "^1.0.0", - "fs-extra": "^7.0.0", - "hyperlinker": "^1.0.0", - "indent-string": "^3.2.0", - "is-wsl": "^1.1.0", - "lodash": "^4.17.11", - "password-prompt": "^1.0.7", - "semver": "^5.6.0", - "strip-ansi": "^5.0.0", - "supports-color": "^5.5.0", - "supports-hyperlinks": "^1.0.1", - "treeify": "^1.1.0", - "tslib": "^1.9.3" - }, - "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "csv-stringify": { + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz", + "integrity": "sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==", "dev": true }, - "fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "ms": "^2.1.1" } }, - "has-flag": { + "fancy-test": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", - "dev": true + "resolved": "https://registry.npmjs.org/fancy-test/-/fancy-test-2.0.0.tgz", + "integrity": "sha512-SFb2D/VX9SV+wNYXO1IIh1wyxUC1GS0mYCFJOWD1ia7MPj9yE2G8jaPkw4t/pg0Sj7/YJP56OzMY4nAuJSOugQ==", + "dev": true, + "requires": { + "@types/chai": "*", + "@types/lodash": "*", + "@types/node": "*", + "@types/sinon": "*", + "lodash": "^4.17.13", + "mock-stdin": "^1.0.0", + "nock": "^13.0.0", + "stdout-stderr": "^0.1.9" + } }, - "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "dev": true + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "jsforce": { + "version": "2.0.0-beta.7", + "resolved": "https://registry.npmjs.org/jsforce/-/jsforce-2.0.0-beta.7.tgz", + "integrity": "sha512-aiJRbf6v0eQSJLpAg4aEB/yXsQwV9WM3ewT2v/WTLmeeZQ4ZtwlcJhQCTwW4tKX/S8U+t5nL+Iluz8jFSZFqnA==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "@babel/runtime": "^7.12.5", + "@babel/runtime-corejs3": "^7.12.5", + "@types/node": "^12.19.9", + "abort-controller": "^3.0.0", + "base64url": "^3.0.1", + "commander": "^4.0.1", + "core-js": "^3.6.4", + "csv-parse": "^4.8.2", + "csv-stringify": "^5.3.4", + "faye": "^1.4.0", + "fs-extra": "^8.1.0", + "https-proxy-agent": "^5.0.0", + "inquirer": "^7.0.0", + "multistream": "^3.1.0", + "node-fetch": "^2.6.1", + "open": "^7.0.0", + "regenerator-runtime": "^0.13.3", + "strip-ansi": "^6.0.0", + "xml2js": "^0.4.22" + }, + "dependencies": { + "@types/node": { + "version": "12.20.47", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.47.tgz", + "integrity": "sha512-BzcaRsnFuznzOItW1WpQrDHM7plAa7GIDMZ6b5pnMbkqEtM/6WCOhvZar39oeMQP79gwvFUWjjptE7/KGcNqFg==", + "dev": true + } } }, - "supports-hyperlinks": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz", - "integrity": "sha512-HHi5kVSefKaJkGYXbDuKbUGRVxqnWGn3J2e39CYcNJEfWciGq2zYtOhXLTlvrOZW1QU7VX67w7fMmWafHX9Pfw==", + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", "dev": true, "requires": { - "has-flag": "^2.0.0", - "supports-color": "^5.0.0" + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" } }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true - } - } - }, - "cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "co-prompt": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/co-prompt/-/co-prompt-1.0.0.tgz", - "integrity": "sha1-+zcOntrEhXayenMv5dfyHZ/G5vY=", - "dev": true, - "requires": { - "keypress": "~0.2.1" - } - }, - "coffeescript": { - "version": "1.12.7", - "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.12.7.tgz", - "integrity": "sha512-pLXHFxQMPklVoEekowk8b3erNynC+DVJzChxS/LCBBgR6/8AJkHivkm//zbowcfc7BTCAjryuhx6gPqPRfsFoA==", - "dev": true - }, - "collect-all": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/collect-all/-/collect-all-1.0.4.tgz", - "integrity": "sha512-RKZhRwJtJEP5FWul+gkSMEnaK6H3AGPTTWOiRimCcs+rc/OmQE3Yhy1Q7A7KsdkG3ZXVdZq68Y6ONSdvkeEcKA==", - "dev": true, - "requires": { - "stream-connect": "^1.0.2", - "stream-via": "^1.0.4" - } - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", - "dev": true - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "command-line-args": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.0.tgz", - "integrity": "sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==", - "dev": true, - "requires": { - "array-back": "^3.1.0", - "find-replace": "^3.0.0", - "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" - }, - "dependencies": { - "array-back": { + }, + "multistream": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", - "dev": true + "resolved": "https://registry.npmjs.org/multistream/-/multistream-3.1.0.tgz", + "integrity": "sha512-zBgD3kn8izQAN/TaL1PCMv15vYpf+Vcrsfub06njuYVYlzUldzpopTlrEZ53pZVEbfn3Shtv7vRFoOv6LOV87Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^3.4.0" + } }, - "typical": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", - "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } }, - "command-line-tool": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/command-line-tool/-/command-line-tool-0.8.0.tgz", - "integrity": "sha512-Xw18HVx/QzQV3Sc5k1vy3kgtOeGmsKIqwtFFoyjI4bbcpSgnw2CWVULvtakyw4s6fhyAdI6soQQhXc2OzJy62g==", + "@salesforce/plugin-apex": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-apex/-/plugin-apex-0.11.0.tgz", + "integrity": "sha512-8GDbrT1jIhDXgQhbS26vihSKWxng5OMjjzzEoY6WKEwXtBwnsR4WRm232Z7LbtTy6p7aw7K1wTPZYj6vDMiduQ==", "dev": true, "requires": { - "ansi-escape-sequences": "^4.0.0", - "array-back": "^2.0.0", - "command-line-args": "^5.0.0", - "command-line-usage": "^4.1.0", - "typical": "^2.6.1" + "@oclif/command": "^1", + "@oclif/config": "^1", + "@oclif/errors": "^1", + "@salesforce/apex-node": "0.11.0", + "@salesforce/command": "4.2.0", + "@salesforce/core": "^2.35.0", + "chalk": "^4.1.0", + "tslib": "^1" }, "dependencies": { - "array-back": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", - "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "@oclif/parser": { + "version": "3.8.6", + "resolved": "https://registry.npmjs.org/@oclif/parser/-/parser-3.8.6.tgz", + "integrity": "sha512-tXb0NKgSgNxmf6baN6naK+CCwOueaFk93FG9u202U7mTBHUKsioOUlw1SG/iPi9aJM3WE4pHLXmty59pci0OEw==", "dev": true, "requires": { - "typical": "^2.6.1" + "@oclif/errors": "^1.2.2", + "@oclif/linewrap": "^1.0.0", + "chalk": "^4.1.0", + "tslib": "^2.0.0" + }, + "dependencies": { + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + } + } + }, + "@salesforce/command": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@salesforce/command/-/command-4.2.0.tgz", + "integrity": "sha512-KxvzBHqJHLR5WMP/Gh4TpSjCSfIveZEVRA8+zS+ZFXXLILuZzCPi/kHwZnKwOedO3EyjC8HFnFDgKt62vqgw8w==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.1", + "@oclif/errors": "^1.2.2", + "@oclif/parser": "3.8.6", + "@oclif/plugin-help": "^2.2.0", + "@oclif/test": "^1.2.4", + "@salesforce/core": "^2.31.0", + "@salesforce/kit": "^1.5.17", + "@salesforce/ts-types": "^1.5.20", + "chalk": "^2.4.2", + "cli-ux": "^4.9.3" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true } } }, - "command-line-usage": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-4.1.0.tgz", - "integrity": "sha512-MxS8Ad995KpdAC0Jopo/ovGIroV/m0KHwzKfXxKag6FHOkGsH8/lv5yjgablcRxCJJC0oJeUMuO/gmaq+Wq46g==", + "@salesforce/plugin-auth": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-auth/-/plugin-auth-1.8.2.tgz", + "integrity": "sha512-ROHxuEHsMv5uh1LA6BWqvYEx2ajqYHzcX6FDHP0TisEARO5yIq+2Mvhl2ob2jENsDjHyXurA2U1m/MVimu7qbw==", "dev": true, "requires": { - "ansi-escape-sequences": "^4.0.0", - "array-back": "^2.0.0", - "table-layout": "^0.4.2", - "typical": "^2.6.1" + "@oclif/config": "^1.18.1", + "@salesforce/command": "^4.2.0", + "@salesforce/core": "^2.31.0", + "@salesforce/kit": "^1.5.17", + "chalk": "^4.1.2", + "open": "^8.2.1", + "tslib": "^2" }, "dependencies": { - "array-back": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", - "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "typical": "^2.6.1" + "color-convert": "^2.0.1" } - } - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "common-sequence": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-2.0.2.tgz", - "integrity": "sha512-jAg09gkdkrDO9EWTdXfv80WWH3yeZl5oT69fGfedBNS9pXUKYInVJ1bJ+/ht2+Moeei48TmSbQDYMc8EOx9G0g==", - "dev": true - }, - "compress-commons": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz", - "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", - "dev": true, - "requires": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "config-master": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/config-master/-/config-master-3.1.0.tgz", - "integrity": "sha1-ZnZjWQUFooO/JqSE1oSJ10xUhdo=", - "dev": true, - "requires": { - "walk-back": "^2.0.1" - }, - "dependencies": { - "walk-back": { + }, + "color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-2.0.1.tgz", - "integrity": "sha1-VU4qnYdPrEeoywBr9EwvDEmYoKQ=", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true + }, + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "@salesforce/plugin-community": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-community/-/plugin-community-1.1.4.tgz", + "integrity": "sha512-pmbnfOMe2G/vfZuoNWaoH3hZMQqcW2ge3CBYbmUe4wZRT+vjP8ZcTtJLZOMSYvLnFUycY5KRx3gnZlQLo3dsYQ==", "dev": true, "requires": { - "safe-buffer": "~5.1.1" + "@oclif/config": "^1", + "@salesforce/command": "^4.2.2", + "@salesforce/core": "^2.35.1", + "tslib": "^2" } }, - "core-js": { - "version": "3.20.2", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.2.tgz", - "integrity": "sha512-nuqhq11DcOAbFBV4zCbKeGbKQsUDRqTX0oqx7AttUBuqe3h20ixsE039QHelbL6P4h+9kytVqyEtyZ6gsiwEYw==", - "dev": true - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "crc-32": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.1.tgz", - "integrity": "sha512-Dn/xm/1vFFgs3nfrpEVScHoIslO9NZRITWGz/1E/St6u4xw99vfZzVkW0OSnzx2h9egej9xwMCEut6sqwokM/w==", + "@salesforce/plugin-config": { + "version": "1.3.24", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-config/-/plugin-config-1.3.24.tgz", + "integrity": "sha512-zOxQL8ZYIrNhVLIPXLl934YUFHzyyCkMuBxY3nWkOZ6m1otxUEyXAAWyqIVR1xVMIXymAlq/Xs2ZSjLVfTjZIA==", "dev": true, "requires": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.3.1" + "@oclif/config": "^1.18.1", + "@salesforce/command": "^4.2.0", + "@salesforce/core": "^2.31.0", + "tslib": "^2" } }, - "crc32-stream": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz", - "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", + "@salesforce/plugin-custom-metadata": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-custom-metadata/-/plugin-custom-metadata-1.0.12.tgz", + "integrity": "sha512-f/I8rxmIuOMQtJ4SbWIvf+ui4Nak/of0jwxS90mNcG1Fvtu8vikYvaXzGA6sdiOVkMFrDhHHJkf0D416Bu/zBQ==", "dev": true, "requires": { - "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" + "@oclif/command": "^1.6.1", + "@oclif/config": "^1.15.1", + "@oclif/errors": "^1.2.2", + "@salesforce/command": "^3.0.0", + "@salesforce/ts-types": "^1.2.2", + "tslib": "^2.0.0" }, "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "@salesforce/command": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@salesforce/command/-/command-3.1.3.tgz", + "integrity": "sha512-Yg9lhl3ghwPN7WwqFmgfWIn6i7vz43WTpEsYsChz80bKORlVbDvhwPZQUj0XTv3DKDnPZVU8FFIDsrLSOa9G1A==", "dev": true, "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "@oclif/command": "^1.5.17", + "@oclif/errors": "^1.2.2", + "@oclif/parser": "^3.8.3", + "@oclif/plugin-help": "^2.2.0", + "@oclif/test": "^1.2.4", + "@salesforce/core": "^2.23.4", + "@salesforce/kit": "^1.2.2", + "@salesforce/ts-types": "^1.2.0", + "chalk": "^2.4.2", + "cli-ux": "^4.9.3" } } } }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "csprng": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/csprng/-/csprng-0.1.2.tgz", - "integrity": "sha1-S8aPEvo2jSUqWYQcusqXSxirReI=", - "dev": true, - "requires": { - "sequin": "*" - } - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true - }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "@salesforce/plugin-data": { + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-data/-/plugin-data-0.6.12.tgz", + "integrity": "sha512-gyGaN7p6SlZwBEatGrC/CobUqqRtnA+ZR/W14unWwoKNi1asoKoM4I/ddOlktE4sBvBJzR0AwBtYp83iL1MTMA==", "dev": true, "requires": { - "cssom": "~0.3.6" + "@oclif/config": "^1", + "@salesforce/command": "^4.2.0", + "@salesforce/core": "^2.35.3", + "@salesforce/ts-types": "^1.5.20", + "chalk": "^4.1.0", + "csv-parse": "^4.16.3", + "tslib": "^2" }, "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, - "csv-parse": { - "version": "4.16.3", - "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", - "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", - "dev": true - }, - "csv-stringify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-1.1.2.tgz", - "integrity": "sha1-d6QVJlgbzjOA8SsA18W7rHDIK1g=", - "dev": true, - "requires": { - "lodash.get": "~4.4.2" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - } - }, - "dayjs": { - "version": "1.10.7", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", - "integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==", - "dev": true - }, - "dayjs-plugin-utc": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dayjs-plugin-utc/-/dayjs-plugin-utc-0.1.2.tgz", - "integrity": "sha512-ExERH5o3oo6jFOdkvMP3gytTCQ9Ksi5PtylclJWghr7k7m3o2U5QrwtdiJkOxLOH4ghr0EKhpqGefzGz1VvVJg==", - "dev": true - }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "@salesforce/plugin-generator": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-generator/-/plugin-generator-1.2.2.tgz", + "integrity": "sha512-ua6Brn/vzO4SqspF44dGOcmHP6ezgblL2BqV9Vul/Ze8ZOeaJvfgBA0BUrZSB3TVd9BrugwxoXa12T6F2qJRaw==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.0", + "@oclif/config": "^1.17.0", + "@oclif/errors": "^1.3.4", + "@oclif/fixpack": "^2.3.0", + "@oclif/plugin-help": "^3.2.2", + "@oclif/plugin-not-found": "^1.2.2", + "@oclif/plugin-warn-if-update-available": "^1.5.4", + "concurrently": "^7.0.0", + "debug": "^4.3.1", + "eslint-config-xo": "^0.36.0", + "eslint-config-xo-space": "^0.27.0", + "lodash": "^4.17.21", + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2", + "sort-pjson": "^1.0.3", + "tslib": "^2.2.0", + "yeoman-environment": "^2.4.0", + "yeoman-generator": "^4.0.1", + "yosay": "^2.0.2" + }, + "dependencies": { + "@oclif/plugin-help": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-3.3.1.tgz", + "integrity": "sha512-QuSiseNRJygaqAdABYFWn/H1CwIZCp9zp/PLid6yXvy6VcQV7OenEFF5XuYaCvSARe2Tg9r8Jqls5+fw1A9CbQ==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.15", + "@oclif/config": "1.18.2", + "@oclif/errors": "1.3.5", + "@oclif/help": "^1.0.1", + "chalk": "^4.1.2", + "indent-string": "^4.0.0", + "lodash": "^4.17.21", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "widest-line": "^3.1.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "@oclif/config": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.2.tgz", + "integrity": "sha512-cE3qfHWv8hGRCP31j7fIS7BfCflm/BNZ2HNqHexH+fDrdF2f1D5S8VmXWLC77ffv3oDvWyvE9AZeR0RfmHCCaA==", + "dev": true, + "requires": { + "@oclif/errors": "^1.3.3", + "@oclif/parser": "^3.8.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-wsl": "^2.1.1", + "tslib": "^2.0.0" + } + } + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "@salesforce/plugin-info": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-info/-/plugin-info-1.3.1.tgz", + "integrity": "sha512-fL0Kq4o65IjXAs+O8yFYyc0fHQycOUEcRIm96w9ckcAv6hcDu3lnIv+63KuMSR7q/S6sG/W/TE7O/wOLCMwzCw==", "dev": true, "requires": { - "ms": "2.1.2" + "@oclif/config": "^1", + "@oclif/plugin-help": "^3.3.1", + "@salesforce/command": "^4.1.5", + "@salesforce/core": "^2.29.0", + "@salesforce/kit": "^1.5.17", + "got": "^11.8.2", + "marked": "^4.0.1", + "marked-terminal": "^4.2.0", + "proxy-agent": "^5.0.0", + "proxy-from-env": "^1.1.0", + "semver": "^7.3.5", + "tslib": "^2" + }, + "dependencies": { + "@oclif/plugin-help": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-3.3.1.tgz", + "integrity": "sha512-QuSiseNRJygaqAdABYFWn/H1CwIZCp9zp/PLid6yXvy6VcQV7OenEFF5XuYaCvSARe2Tg9r8Jqls5+fw1A9CbQ==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.15", + "@oclif/config": "1.18.2", + "@oclif/errors": "1.3.5", + "@oclif/help": "^1.0.1", + "chalk": "^4.1.2", + "indent-string": "^4.0.0", + "lodash": "^4.17.21", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "widest-line": "^3.1.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "@oclif/config": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.2.tgz", + "integrity": "sha512-cE3qfHWv8hGRCP31j7fIS7BfCflm/BNZ2HNqHexH+fDrdF2f1D5S8VmXWLC77ffv3oDvWyvE9AZeR0RfmHCCaA==", + "dev": true, + "requires": { + "@oclif/errors": "^1.3.3", + "@oclif/parser": "^3.8.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-wsl": "^2.1.1", + "tslib": "^2.0.0" + } + } + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "got": { + "version": "11.8.3", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", + "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", + "dev": true, + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } } }, - "debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", - "dev": true - }, - "decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true + "@salesforce/plugin-limits": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-limits/-/plugin-limits-1.3.0.tgz", + "integrity": "sha512-W3XN42SZzwSL+xattZdGA23Oy7Bg523n1FKEZg4vL6V8kSrP/C8AIm3U4UL5L9vBM89pCjCoDNgQ2ANy3r4BDg==", + "dev": true, + "requires": { + "@oclif/config": "^1", + "@salesforce/command": "^4.2.0", + "@salesforce/core": "^2.31.0", + "tslib": "^2" + } }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "@salesforce/plugin-org": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-org/-/plugin-org-1.11.2.tgz", + "integrity": "sha512-vHex65zx7Jd7FNCcBcFo12QymVHxJUF1XZ4O+MLMP6DEHnhiiQYo75bXcBBuumj+SAIfJi/RifYLpPRbyU/1Lw==", + "dev": true, "requires": { - "mimic-response": "^3.1.0" + "@oclif/config": "^1.18.1", + "@salesforce/command": "^4.2.2", + "@salesforce/core": "^2.35.0", + "@salesforce/kit": "^1.5.17", + "open": "8.4.0", + "tslib": "^2" }, "dependencies": { - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } } } }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "@salesforce/plugin-schema": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-schema/-/plugin-schema-1.1.0.tgz", + "integrity": "sha512-fAYVrPnlZvWalqS3PrtrxID2KeXi2W9M7OhysctVWJUpBkoi3r1vCAK8RXCCP31H/KHt3PiuOyoyn4+8vfCgDA==", "dev": true, "requires": { - "object-keys": "^1.0.12" + "@oclif/config": "^1", + "@salesforce/command": "^4.2.0", + "@salesforce/core": "^2.31.0", + "tslib": "^2" } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "@salesforce/plugin-source": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-source/-/plugin-source-1.9.2.tgz", + "integrity": "sha512-vNwMvlCtyoMWOu1q3zdsOQ4T58LEfLcrNdGWnhrDYKHuaEmQfezewNiE2R68hyDT9jJhDVK1OyM/0zpY832yXg==", "dev": true, "requires": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "diff-sequences": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz", - "integrity": "sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "dmd": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/dmd/-/dmd-6.0.0.tgz", - "integrity": "sha512-PwWZlqZnJPETwqZZ70haRa+UDZcD5jeBD3ywW1Kf+jYYv0MHu/S7Ri9jsSoeTMwkcMVW9hXOMA1IZUMEufBhOg==", - "dev": true, - "requires": { - "array-back": "^5.0.0", - "cache-point": "^2.0.0", - "common-sequence": "^2.0.0", - "file-set": "^4.0.1", - "handlebars": "^4.7.7", - "marked": "^2.0.0", - "object-get": "^2.1.1", - "reduce-flatten": "^3.0.0", - "reduce-unique": "^2.0.1", - "reduce-without": "^1.0.1", - "test-value": "^3.0.0", - "walk-back": "^5.0.0" + "@oclif/config": "^1.18.3", + "@oclif/plugin-help": "^3.3.1", + "@salesforce/command": "^4.2.2", + "@salesforce/core": "^2.35.0", + "@salesforce/source-deploy-retrieve": "^5.12.5", + "@salesforce/source-tracking": "^1.3.1", + "chalk": "^4.1.2", + "cli-ux": "^5.6.3", + "got": "^11.8.3", + "open": "^8.4.0", + "proxy-agent": "^5.0.0", + "proxy-from-env": "^1.1.0", + "tslib": "^2" }, "dependencies": { - "array-back": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-5.0.0.tgz", - "integrity": "sha512-kgVWwJReZWmVuWOQKEOohXKJX+nD02JAZ54D1RRWlv8L0NebauKAaFxACKzB74RTclt1+WNz5KHaLRDAPZbDEw==", + "@oclif/plugin-help": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-3.3.1.tgz", + "integrity": "sha512-QuSiseNRJygaqAdABYFWn/H1CwIZCp9zp/PLid6yXvy6VcQV7OenEFF5XuYaCvSARe2Tg9r8Jqls5+fw1A9CbQ==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.15", + "@oclif/config": "1.18.2", + "@oclif/errors": "1.3.5", + "@oclif/help": "^1.0.1", + "chalk": "^4.1.2", + "indent-string": "^4.0.0", + "lodash": "^4.17.21", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "widest-line": "^3.1.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "@oclif/config": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.2.tgz", + "integrity": "sha512-cE3qfHWv8hGRCP31j7fIS7BfCflm/BNZ2HNqHexH+fDrdF2f1D5S8VmXWLC77ffv3oDvWyvE9AZeR0RfmHCCaA==", + "dev": true, + "requires": { + "@oclif/errors": "^1.3.3", + "@oclif/parser": "^3.8.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-wsl": "^2.1.1", + "tslib": "^2.0.0" + } + } + } + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cli-ux": { + "version": "5.6.7", + "resolved": "https://registry.npmjs.org/cli-ux/-/cli-ux-5.6.7.tgz", + "integrity": "sha512-dsKAurMNyFDnO6X1TiiRNiVbL90XReLKcvIq4H777NMqXGBxBws23ag8ubCJE97vVZEgWG2eSUhsyLf63Jv8+g==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.15", + "@oclif/errors": "^1.3.5", + "@oclif/linewrap": "^1.0.0", + "@oclif/screen": "^1.0.4", + "ansi-escapes": "^4.3.0", + "ansi-styles": "^4.2.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.0", + "clean-stack": "^3.0.0", + "cli-progress": "^3.4.0", + "extract-stack": "^2.0.0", + "fs-extra": "^8.1", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.13.1", + "lodash": "^4.17.21", + "natural-orderby": "^2.0.1", + "object-treeify": "^1.1.4", + "password-prompt": "^1.1.2", + "semver": "^7.3.2", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "supports-color": "^8.1.0", + "supports-hyperlinks": "^2.1.0", + "tslib": "^2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "marked": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz", - "integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==", + "extract-stack": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extract-stack/-/extract-stack-2.0.0.tgz", + "integrity": "sha512-AEo4zm+TenK7zQorGK1f9mJ8L14hnTDi2ZQPR+Mub1NX8zimka1mXpV5LpH8x9HoUmFSHZCfLHqWvp0Y4FxxzQ==", "dev": true }, - "reduce-flatten": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-3.0.1.tgz", - "integrity": "sha512-bYo+97BmUUOzg09XwfkwALt4PQH1M5L0wzKerBt6WLm3Fhdd43mMS89HiT1B9pJIqko/6lWx3OnV4J9f2Kqp5Q==", + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "got": { + "version": "11.8.3", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", + "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", + "dev": true, + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", "dev": true + }, + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } } } }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "@salesforce/plugin-telemetry": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-telemetry/-/plugin-telemetry-1.4.0.tgz", + "integrity": "sha512-vroDey9dTomc6mMWWufzN2mKXsWzLR067z2263TPEFr3Hgt0qQjE0K4eXa5rjbs0OOpm6dGGwisa9sT6wkoseA==", "dev": true, "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" + "@oclif/config": "^1", + "@salesforce/command": "^4.2.0", + "@salesforce/core": "^2.31.0", + "@salesforce/telemetry": "^3.1.0", + "tslib": "^2" } }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "@salesforce/plugin-templates": { + "version": "54.3.0", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-templates/-/plugin-templates-54.3.0.tgz", + "integrity": "sha512-gSsFsaO7peDcI+2gp1i2QvJ6RGbHCZKBIEHlpviwtMGJzPAV0eA3alvvBLTg7A/feZK+Kv41pZM2x5Qo1DUg4A==", "dev": true, "requires": { - "webidl-conversions": "^5.0.0" + "@oclif/command": "^1", + "@oclif/config": "^1", + "@oclif/errors": "^1", + "@salesforce/command": "^4.2.1", + "@salesforce/core": "^2.33.1", + "@salesforce/templates": "54.3.0", + "tslib": "^1", + "yeoman-environment": "2.4.0", + "yeoman-generator": "^4.8.2" }, "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } - } - }, - "dtrace-provider": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.6.0.tgz", - "integrity": "sha1-CweNVReTfYcxAUUtkUZzdVe3XlE=", - "dev": true, - "optional": true, - "requires": { - "nan": "^2.0.8" - } - }, - "eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "electron-to-chromium": { - "version": "1.4.31", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.31.tgz", - "integrity": "sha512-t3XVQtk+Frkv6aTD4RRk0OqosU+VLe1dQFW83MDer78ZD6a52frgXuYOIsLYTQiH2Lm+JB2OKYcn7zrX+YGAiQ==", - "dev": true - }, - "emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", "dev": true }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - } - } - }, - "eslint": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.8.0.tgz", - "integrity": "sha512-H3KXAzQGBH1plhYS3okDix2ZthuYJlQQEGE5k0IKuEqUSiyu4AmxxlJ2MtTYeJ3xB4jDhcYCwGOg2TXYdnDXlQ==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.0.5", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.0", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.2.0", - "espree": "^9.3.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.6.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", "dev": true }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "color-convert": "^2.0.1" + "array-uniq": "^1.0.1" } }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true, "requires": { - "color-name": "~1.1.4" + "restore-cursor": "^2.0.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", "dev": true }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { - "esutils": "^2.0.2" + "ms": "^2.1.1" } }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, - "eslint-scope": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz", - "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==", + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", "dev": true, "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "arrify": "^1.0.1", + "path-type": "^3.0.0" } }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", "dev": true, "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" } }, - "eslint-visitor-keys": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.2.0.tgz", - "integrity": "sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==", - "dev": true - }, - "espree": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.0.tgz", - "integrity": "sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ==", + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, "requires": { - "acorn": "^8.7.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^3.1.0" + "escape-string-regexp": "^1.0.5" } }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "dev": true, "requires": { - "flat-cache": "^3.0.4" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } } }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "dev": true, "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } } }, - "flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", "dev": true, "requires": { - "is-glob": "^4.0.3" + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" } }, - "globals": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "grouped-queue": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/grouped-queue/-/grouped-queue-0.3.3.tgz", + "integrity": "sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw=", "dev": true, "requires": { - "type-fest": "^0.20.2" + "lodash": "^4.17.2" } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", "dev": true }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", "dev": true, "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } } }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" } }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true - } - } - }, - "eslint-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", - "dev": true - }, - "eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true, "requires": { - "ms": "^2.1.1" + "mimic-fn": "^1.0.0" } - } - } - }, - "eslint-module-utils": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.2.tgz", - "integrity": "sha512-zquepFnWCY2ISMFwD/DqzaM++H+7PDzOpUvotJWm/y1BAFt5R4oeULgdrTejKqLkz7MA/tgstsUMNYc7wNdTrg==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "find-up": "^2.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { - "ms": "^2.1.1" + "pify": "^3.0.0" } }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, "requires": { - "locate-path": "^2.0.0" + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" } }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" } }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { - "p-try": "^1.0.0" + "ansi-regex": "^3.0.0" } }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "p-limit": "^1.1.0" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "untildify": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", + "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", "dev": true - } - } - }, - "eslint-plugin-compat": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-3.13.0.tgz", - "integrity": "sha512-cv8IYMuTXm7PIjMVDN2y4k/KVnKZmoNGHNq27/9dLstOLydKblieIv+oe2BN2WthuXnFNhaNvv3N1Bvl4dbIGA==", - "dev": true, - "requires": { - "@mdn/browser-compat-data": "^3.3.14", - "ast-metadata-inferer": "^0.7.0", - "browserslist": "^4.16.8", - "caniuse-lite": "^1.0.30001251", - "core-js": "^3.16.2", - "find-up": "^5.0.0", - "lodash.memoize": "4.1.2", - "semver": "7.3.5" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + }, + "yeoman-environment": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-2.4.0.tgz", + "integrity": "sha512-SsvoL0RNAFIX69eFxkUhwKUN2hG1UwUjxrcP+T2ytwdhqC/kHdnFOH2SXdtSN1Ju4aO4xuimmzfRoheYY88RuA==", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "debug": "^3.1.0", + "diff": "^3.5.0", + "escape-string-regexp": "^1.0.2", + "globby": "^8.0.1", + "grouped-queue": "^0.3.3", + "inquirer": "^6.0.0", + "is-scoped": "^1.0.0", + "lodash": "^4.17.10", + "log-symbols": "^2.2.0", + "mem-fs": "^1.1.0", + "strip-ansi": "^4.0.0", + "text-table": "^0.2.0", + "untildify": "^3.0.3" } } } }, - "eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "@salesforce/plugin-trust": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-trust/-/plugin-trust-1.1.0.tgz", + "integrity": "sha512-hk9A2GwNHgzho5E3ZGw+hMUlqRTaRXHNLpiIQwZjLOnOPYS3lT6dGR9vidQb6WXs7zYZIW2feI+sN36FZjcIDA==", "dev": true, "requires": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", - "has": "^1.0.3", - "is-core-module": "^2.8.0", - "is-glob": "^4.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "@oclif/config": "^1.18.1", + "@salesforce/command": "^4.2.0", + "@salesforce/core": "^2.31.0", + "npm": "^7.21.0", + "npm-run-path": "^4.0.1", + "shelljs": "^0.8.4", + "tslib": "^2" } }, - "eslint-plugin-jest": { - "version": "23.8.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-23.8.2.tgz", - "integrity": "sha512-xwbnvOsotSV27MtAe7s8uGWOori0nUsrXh2f1EnpmXua8sDfY6VZhHAhHg2sqK7HBNycRQExF074XSZ7DvfoFg==", + "@salesforce/plugin-user": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@salesforce/plugin-user/-/plugin-user-1.7.1.tgz", + "integrity": "sha512-nM0j/AqtJYV9VH67DSQ/TkXlB3J1SxlngOH8byzyPWTAhbrNDFxo44Up7nsiLYyrdMrKrmJ3eOWjDm9rKRFUtA==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "^2.5.0" + "@oclif/config": "^1.18.1", + "@salesforce/command": "^4.2.0", + "@salesforce/core": "^2.31.0", + "@salesforce/kit": "^1.5.18", + "tslib": "^2" } }, - "eslint-restricted-globals": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.2.0.tgz", - "integrity": "sha512-kwYJALm5KS2QW3Mc1PgObO4V+pTR6RQtRT65L1GQILlEnAhabUQqGAX7/qUjoQR4KZJKehWpBtyDEiDecwmY9A==", - "dev": true - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "@salesforce/require-analytics": { + "version": "0.9.21", + "resolved": "https://registry.npmjs.org/@salesforce/require-analytics/-/require-analytics-0.9.21.tgz", + "integrity": "sha512-BACe6i2c4AwBD72jsOWN3pbpVl0YMZlJjgLFWskigvKCSypW8oXK+klabF1lBPS0rIssAvyIBs9HGKVrXtsqhg==", "dev": true, "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "tslib": "^2.2.0" } }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "@salesforce/schemas": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@salesforce/schemas/-/schemas-1.1.0.tgz", + "integrity": "sha512-6D7DvE6nFxpLyyTnrOIbbAeCJw2r/EpinFAcMh6gU0gA/CGfSbwV/8uR3uHLYL2zCyCZLH8jJ4dZ3BzCMqc+Eg==", + "dev": true + }, + "@salesforce/sfdx-lwc-jest": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@salesforce/sfdx-lwc-jest/-/sfdx-lwc-jest-1.1.0.tgz", + "integrity": "sha512-bYhvs9Th4qMjk4Vs66GDwloVh2LAcV8cg/j0WWbIug8MiI+KOSZL0IWZA7fqr8vXkSdArt5WjoTv4ckzfklzQA==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "@lwc/compiler": "2.2.11", + "@lwc/engine-dom": "2.2.11", + "@lwc/jest-preset": "11.2.0", + "@lwc/jest-resolver": "11.2.0", + "@lwc/jest-serializer": "11.2.0", + "@lwc/jest-transformer": "11.2.0", + "@lwc/module-resolver": "2.2.11", + "@lwc/synthetic-shadow": "2.2.11", + "@lwc/wire-service": "2.2.11", + "@salesforce/wire-service-jest-util": "4.0.0", + "chalk": "~4.1.1", + "fast-glob": "^3.2.7", + "jest": "27.0.6", + "yargs": "~17.0.1" }, "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - }, - "espree": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", - "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "yargs": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.0.1.tgz", + "integrity": "sha512-xBBulfCc8Y6gLFcrPvtqKz9hz8SO0l1Ni8GgDekvBX2ro0HRQImDGnikfc33cgzcYUSncapnNcZDjVFIH3f6KQ==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } } } }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "@salesforce/sfdx-plugin-lwc-test": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@salesforce/sfdx-plugin-lwc-test/-/sfdx-plugin-lwc-test-0.1.7.tgz", + "integrity": "sha512-Cipsf/VimgyoOWWSlnaUKh58oCCZQ7wyGmvTfGY5QJkxUGVgUvXzIlTWEHi+oLzSMH7GZQDHU2KLWWq82rgd4A==", "dev": true, "requires": { - "estraverse": "^5.2.0" + "@oclif/command": "^1.5.19", + "@oclif/config": "1.13.3", + "@oclif/errors": "^1.2.2", + "@salesforce/command": "^3.0.0", + "@salesforce/core": "^2.2.0", + "@salesforce/kit": "^1.2.1", + "semver-compare": "^1.0.0", + "signal-exit": "^3.0.2", + "tslib": "^1.10.0" }, "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "@oclif/config": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.13.3.tgz", + "integrity": "sha512-qs5XvGRw+1M41abOKCjd0uoeHCgsMxa2MurD2g2K8CtQlzlMXl0rW5idVeimIg5208LLuxkfzQo8TKAhhRCWLg==", + "dev": true, + "requires": { + "@oclif/parser": "^3.8.0", + "debug": "^4.1.1", + "tslib": "^1.9.3" + } + }, + "@salesforce/command": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@salesforce/command/-/command-3.1.3.tgz", + "integrity": "sha512-Yg9lhl3ghwPN7WwqFmgfWIn6i7vz43WTpEsYsChz80bKORlVbDvhwPZQUj0XTv3DKDnPZVU8FFIDsrLSOa9G1A==", + "dev": true, + "requires": { + "@oclif/command": "^1.5.17", + "@oclif/errors": "^1.2.2", + "@oclif/parser": "^3.8.3", + "@oclif/plugin-help": "^2.2.0", + "@oclif/test": "^1.2.4", + "@salesforce/core": "^2.23.4", + "@salesforce/kit": "^1.2.2", + "@salesforce/ts-types": "^1.2.0", + "chalk": "^2.4.2", + "cli-ux": "^4.9.3" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true } } }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "@salesforce/sfdx-scanner": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/@salesforce/sfdx-scanner/-/sfdx-scanner-2.13.1.tgz", + "integrity": "sha512-ln0Uo/+rNkBK3CBcBEKdTjcnc/t8uwefoi9S+7PyeBIrXQNyMNeBpWBZKyMekdSYj1E7y6uk9BwGGo69sknkGg==", "dev": true, "requires": { + "@lwc/eslint-plugin-lwc": "^0.10.0", + "@oclif/command": "^1", + "@oclif/config": "^1", + "@oclif/errors": "^1", + "@salesforce/command": "^3", + "@salesforce/core": "^2.1.6", + "@salesforce/eslint-config-lwc": "^0.7.0", + "@typescript-eslint/eslint-plugin": "^2.21.0", + "@typescript-eslint/parser": "^2.21.0", + "babel-eslint": "^10.1.0", "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "exit-on-epipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", - "dev": true - }, - "expect": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.4.2.tgz", - "integrity": "sha512-BjAXIDC6ZOW+WBFNg96J22D27Nq5ohn+oGcuP2rtOtcjuxNoV9McpQ60PcQWhdFOSBIQdR72e+4HdnbZTFSTyg==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "ansi-styles": "^5.0.0", - "jest-get-type": "^27.4.0", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-regex-util": "^27.4.0" + "eslint": "^6.8.0", + "find-java-home": "1.1.0", + "globby": "^11.0.0", + "html-escaper": "^3.0.0", + "is-zip": "^1.0.0", + "isbinaryfile": "^4.0.8", + "mustache": "^4.0.1", + "node-stream-zip": "1.13.2", + "normalize-path": "^3.0.0", + "picomatch": "^2.2.2", + "reflect-metadata": "^0.1.13", + "retire": "^2.2.5", + "semver": "^7.3.4", + "ts-node": "^8", + "tslib": "^2", + "tsyringe": "^4.1.0", + "typescript": "^3.8.2", + "untildify": "^4.0.0", + "word-wrap": "^1.2.3", + "xml-js": "^1.6.11" }, "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "extract-stack": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/extract-stack/-/extract-stack-1.0.0.tgz", - "integrity": "sha1-uXrK+UQe6iMyUpYktzL8WhyBZfo=", - "dev": true - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "@lwc/eslint-plugin-lwc": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@lwc/eslint-plugin-lwc/-/eslint-plugin-lwc-0.10.0.tgz", + "integrity": "sha512-UsosUow0xWrzzcSK1fWDWHKBT81/pJz1/icfv7w8T+BCE9G4Kb4TwJexHLOIZvY7e/dv4Fjme4lTOWehuNE5Sg==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "@salesforce/command": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@salesforce/command/-/command-3.1.3.tgz", + "integrity": "sha512-Yg9lhl3ghwPN7WwqFmgfWIn6i7vz43WTpEsYsChz80bKORlVbDvhwPZQUj0XTv3DKDnPZVU8FFIDsrLSOa9G1A==", + "dev": true, + "requires": { + "@oclif/command": "^1.5.17", + "@oclif/errors": "^1.2.2", + "@oclif/parser": "^3.8.3", + "@oclif/plugin-help": "^2.2.0", + "@oclif/test": "^1.2.4", + "@salesforce/core": "^2.23.4", + "@salesforce/kit": "^1.2.2", + "@salesforce/ts-types": "^1.2.0", + "chalk": "^2.4.2", + "cli-ux": "^4.9.3" + } + }, + "@salesforce/eslint-config-lwc": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@salesforce/eslint-config-lwc/-/eslint-config-lwc-0.7.0.tgz", + "integrity": "sha512-x87H9+amXcPDmOnOZoLdajp5yNZqv8ieyzfE4R8QDOJeZfj1X5I2AOSZYG0pUV51eUV/kOdGjAj28zU296t2yQ==", + "dev": true, + "requires": { + "@lwc/eslint-plugin-lwc": "~0.10.0", + "babel-eslint": "~10.1.0", + "eslint-plugin-import": "~2.20.2", + "eslint-plugin-jest": "~23.8.2", + "eslint-restricted-globals": "~0.2.0" + } + }, + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.20.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.2.tgz", + "integrity": "sha512-FObidqpXrR8OnCh4iNsxy+WACztJLXAHBO5hK79T1Hc77PgQZkyDGA5Ag9xAvRpglvLNxhH/zSmZ70/pZ31dHg==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.1", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", + "read-pkg-up": "^2.0.0", + "resolve": "^1.12.0" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "html-escaper": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@salesforce/source-deploy-retrieve": { + "version": "5.12.8", + "resolved": "https://registry.npmjs.org/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-5.12.8.tgz", + "integrity": "sha512-kEl+SKtJczJtZb/xzl10+UrY52v9roWE+W/k/bOBgtAT/1MkWhX5tCmFqjs4yPgGtk9sRIGhsntfgeedNvCPTg==", + "dev": true, + "requires": { + "@salesforce/core": "^2.35.0", + "@salesforce/kit": "^1.5.32", + "@salesforce/ts-types": "^1.4.2", + "archiver": "^5.3.0", + "fast-xml-parser": "^3.17.4", + "graceful-fs": "^4.2.8", + "ignore": "^5.1.8", + "mime": "2.6.0", + "unzipper": "0.10.11", + "xmldom-sfdx-encoding": "^0.1.29" + } + }, + "@salesforce/source-tracking": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@salesforce/source-tracking/-/source-tracking-1.3.1.tgz", + "integrity": "sha512-I9NVwliT2nP/FlOeYtFFZ896GdldUDxhSGtTa/eopoGm6YQAIwqlnorBR9ypWd4l4x3i8t4fX0pJR4R5I00l9Q==", + "dev": true, + "requires": { + "@salesforce/core": "^2.33.1", + "@salesforce/kit": "^1.5.17", + "@salesforce/source-deploy-retrieve": "^5.9.4", + "graceful-fs": "^4.2.9", + "isomorphic-git": "1.17.0", + "ts-retry-promise": "^0.6.0" + } + }, + "@salesforce/telemetry": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@salesforce/telemetry/-/telemetry-3.2.0.tgz", + "integrity": "sha512-WMKnuWfZx/iOg/OErJCt4OS72Fp4lru+EFaxPHgZIuhrLxpNOHrqni31QkYmY62eYKr0tLSuJFOs8vkgAcGcrw==", + "dev": true, + "requires": { + "@salesforce/core": "^2.31.0", + "@salesforce/ts-types": "^1.2.1", + "applicationinsights": "^1.4.0", + "axios": "^0.21.2" + } + }, + "@salesforce/templates": { + "version": "54.3.0", + "resolved": "https://registry.npmjs.org/@salesforce/templates/-/templates-54.3.0.tgz", + "integrity": "sha512-MYWjTVj6wgEht6UWvPgl1v8FY47zAAqAyc/VjdZ4PCwrxGm1RYOyep15B4pF1dkBELD3eses2McN5qKjUPIruw==", + "dev": true, + "requires": { + "@salesforce/core": "^2.33.1", + "got": "^11.8.2", + "mime-types": "^2.1.27", + "tar": "^6.1.10", + "tslib": "^1", + "yeoman-environment": "2.4.0", + "yeoman-generator": "^4.8.2" + }, + "dependencies": { + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "got": { + "version": "11.8.3", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", + "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", + "dev": true, + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + } + }, + "grouped-queue": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/grouped-queue/-/grouped-queue-0.3.3.tgz", + "integrity": "sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw=", + "dev": true, + "requires": { + "lodash": "^4.17.2" + } + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "minipass": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dev": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "untildify": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", + "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yeoman-environment": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-2.4.0.tgz", + "integrity": "sha512-SsvoL0RNAFIX69eFxkUhwKUN2hG1UwUjxrcP+T2ytwdhqC/kHdnFOH2SXdtSN1Ju4aO4xuimmzfRoheYY88RuA==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "debug": "^3.1.0", + "diff": "^3.5.0", + "escape-string-regexp": "^1.0.2", + "globby": "^8.0.1", + "grouped-queue": "^0.3.3", + "inquirer": "^6.0.0", + "is-scoped": "^1.0.0", + "lodash": "^4.17.10", + "log-symbols": "^2.2.0", + "mem-fs": "^1.1.0", + "strip-ansi": "^4.0.0", + "text-table": "^0.2.0", + "untildify": "^3.0.3" + } + } + } + }, + "@salesforce/ts-types": { + "version": "1.5.20", + "resolved": "https://registry.npmjs.org/@salesforce/ts-types/-/ts-types-1.5.20.tgz", + "integrity": "sha512-Ov6um4CWd63EvkRavkHG0J/P9XYL55sdkDWPMr7+AIgqh5flHxDRz09/C4e9M94aX30rzJxW4TVX6EBf4Cu2BQ==", + "dev": true, + "requires": { + "tslib": "^2.2.0" + } + }, + "@salesforce/wire-service-jest-util": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@salesforce/wire-service-jest-util/-/wire-service-jest-util-4.0.0.tgz", + "integrity": "sha512-YJO/bMq5l6IYIZG6bAqYzzbmZMPCzB2GE2TKGLA1U7B9HpmNHZS7DdDcy154P03dfLSgF+tgVYeklh2HRYGk9g==", + "dev": true + }, + "@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@sideway/formula": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", + "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==", + "dev": true + }, + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true + }, + "@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.0" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", + "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/cacheable-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", + "integrity": "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==", + "dev": true, + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" + } + }, + "@types/chai": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.0.tgz", + "integrity": "sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==", + "dev": true + }, + "@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, + "@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/graceful-fs": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", + "dev": true + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jsforce": { + "version": "1.9.41", + "resolved": "https://registry.npmjs.org/@types/jsforce/-/jsforce-1.9.41.tgz", + "integrity": "sha512-J0dReK6EPGR98b4fAowqqQqFXH4DGtPxY2lLrZGcuCthrHYkYNrKnfGf2xM1jwiBC5CGdSEDmWEDwRwwmX25tA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, + "@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/linkify-it": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz", + "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==", + "dev": true + }, + "@types/lodash": { + "version": "4.14.181", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.181.tgz", + "integrity": "sha512-n3tyKthHJbkiWhDZs3DkhkCzt2MexYHXlX0td5iMplyfwketaOeKboEVBqzceH7juqvEg3q5oUoBFxSLu7zFag==", + "dev": true + }, + "@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "dev": true, + "requires": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, + "@types/mdurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", + "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "@types/mkdirp": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.2.tgz", + "integrity": "sha512-o0K1tSO0Dx5X6xlU5F1D6625FawhC3dU3iqr25lluNv/+/QIVH8RLNEiVokgIZo+mz+87w/3Mkg/VvQS+J51fQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "17.0.23", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz", + "integrity": "sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw==", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "@types/prettier": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.0.tgz", + "integrity": "sha512-G/AdOadiZhnJp0jXCaBQU449W2h716OW/EoXeYkCytxKL06X1WCXB4DZpp8TpZ8eyIJVS1cw4lrlkkSYU21cDw==", + "dev": true + }, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/semver": { + "version": "7.3.9", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz", + "integrity": "sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ==", + "dev": true + }, + "@types/sinon": { + "version": "10.0.11", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.11.tgz", + "integrity": "sha512-dmZsHlBsKUtBpHriNjlK0ndlvEh8dcb9uV9Afsbt89QIyydpC7NcR+nWlAhASfy3GHnxTl4FX/aKE7XZUt/B4g==", + "dev": true, + "requires": { + "@types/sinonjs__fake-timers": "*" + } + }, + "@types/sinonjs__fake-timers": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz", + "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", + "dev": true + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/yargs": { + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz", + "integrity": "sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "2.34.0", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "tsutils": "^3.17.1" + } + }, + "@typescript-eslint/experimental-utils": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz", + "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/typescript-estree": "2.34.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/parser": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.34.0.tgz", + "integrity": "sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==", + "dev": true, + "requires": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "2.34.0", + "@typescript-eslint/typescript-estree": "2.34.0", + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "@typescript-eslint/typescript-estree": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz", + "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@xml-tools/parser": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@xml-tools/parser/-/parser-1.0.11.tgz", + "integrity": "sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==", + "dev": true, + "requires": { + "chevrotain": "7.1.1" + } + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "dev": true + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "acorn": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.4.1.tgz", + "integrity": "sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==", + "dev": true + }, + "acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + } + } + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true + }, + "adm-zip": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz", + "integrity": "sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "dependencies": { + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + } + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "alce": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/alce/-/alce-1.2.0.tgz", + "integrity": "sha1-qL4trKrEJJRhLxjcCdtpHz3qSqs=", + "dev": true, + "requires": { + "esprima": "^1.2.0", + "estraverse": "^1.5.0" + }, + "dependencies": { + "esprima": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", + "integrity": "sha1-CZNQL+r2aBODJXVvMPmlH+7sEek=", + "dev": true + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "dev": true + } + } + }, + "ansi-escape-sequences": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-escape-sequences/-/ansi-escape-sequences-4.1.0.tgz", + "integrity": "sha512-dzW9kHxH011uBsidTXd14JXgzye/YLb2LzeKZ4bsgl/Knwx8AtbSFkkGxagdNOoh0DlqHCmfiEjWKBaqjOanVw==", + "dev": true, + "requires": { + "array-back": "^3.0.1" + }, + "dependencies": { + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true + } + } + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", + "dev": true + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "applicationinsights": { + "version": "1.8.10", + "resolved": "https://registry.npmjs.org/applicationinsights/-/applicationinsights-1.8.10.tgz", + "integrity": "sha512-ZLDA7mShh4mP2Z/HlFolmvhBPX1LfnbIWXrselyYVA7EKjHhri1fZzpu2EiWAmfbRxNBY6fRjoPJWbx5giKy4A==", + "dev": true, + "requires": { + "cls-hooked": "^4.2.2", + "continuation-local-storage": "^3.2.1", + "diagnostic-channel": "0.3.1", + "diagnostic-channel-publishers": "0.4.4" + } + }, + "archiver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.0.tgz", + "integrity": "sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg==", + "dev": true, + "requires": { + "archiver-utils": "^2.1.0", + "async": "^3.2.0", + "buffer-crc32": "^0.2.1", + "readable-stream": "^3.6.0", + "readdir-glob": "^1.0.0", + "tar-stream": "^2.2.0", + "zip-stream": "^4.1.0" + } + }, + "archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "requires": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-back": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", + "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", + "dev": true + }, + "array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "dev": true + }, + "array-includes": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "array.prototype.flat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "ast-metadata-inferer": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/ast-metadata-inferer/-/ast-metadata-inferer-0.7.0.tgz", + "integrity": "sha512-OkMLzd8xelb3gmnp6ToFvvsHLtS6CbagTkFQvQ+ZYFe3/AIl9iKikNR9G7pY3GfOR/2Xc222hwBjzI7HLkE76Q==", + "dev": true, + "requires": { + "@mdn/browser-compat-data": "^3.3.14" + }, + "dependencies": { + "@mdn/browser-compat-data": { + "version": "3.3.14", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-3.3.14.tgz", + "integrity": "sha512-n2RC9d6XatVbWFdHLimzzUJxJ1KY8LdjqrW6YvGPiRmsHkhOUx74/Ct10x5Yo7bC/Jvqx7cDEW8IMPv/+vwEzA==", + "dev": true + } + } + }, + "ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "requires": { + "tslib": "^2.0.1" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "astring": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.7.6.tgz", + "integrity": "sha512-7ofuRb7zx2u7T4OGZTtfkGKAfPKq72XQ7zgpI2b3pR3wdROrDIDmKPtrel7D8S4t+97SGpYTpDR6lq5cNX/DJw==", + "dev": true + }, + "async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "dev": true + }, + "async-hook-jl": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/async-hook-jl/-/async-hook-jl-1.7.6.tgz", + "integrity": "sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==", + "dev": true, + "requires": { + "stack-chain": "^1.3.7" + } + }, + "async-listener": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", + "integrity": "sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==", + "dev": true, + "requires": { + "semver": "^5.3.0", + "shimmer": "^1.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "async-lock": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.3.1.tgz", + "integrity": "sha512-zK7xap9UnttfbE23JmcrNIyueAn6jWshihJqA33U/hEnKprF/lVGBDsBv/bqLm2YMMl1DnpHhUY044eA0t1TUw==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dev": true, + "requires": { + "follow-redirects": "^1.14.0" + } + }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "dev": true, + "requires": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "base64-url": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-2.3.3.tgz", + "integrity": "sha512-dLMhIsK7OplcDauDH/tZLvK7JmUZK3A7KiQpjNzsBrM6Etw7hzNI1tLEywqJk9NnwkgWuFKSlx/IUO7vF6Mo8Q==", + "dev": true + }, + "base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true + }, + "binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", + "dev": true, + "requires": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + } + }, + "binaryextensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.3.0.tgz", + "integrity": "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "browserslist": { + "version": "4.20.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz", + "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001317", + "electron-to-chromium": "^1.4.84", + "escalade": "^3.1.1", + "node-releases": "^2.0.2", + "picocolors": "^1.0.0" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=", + "dev": true + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "buffer-indexof-polyfill": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", + "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "dev": true + }, + "buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", + "dev": true + }, + "byline": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", + "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=", + "dev": true + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "cache-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-2.0.0.tgz", + "integrity": "sha512-4gkeHlFpSKgm3vm2gJN5sPqfmijYRFYCQ6tv5cLw0xVmT6r1z1vd4FNnpuOREco3cBs1G709sZ72LdgddKvL5w==", + "dev": true, + "requires": { + "array-back": "^4.0.1", + "fs-then-native": "^2.0.0", + "mkdirp2": "^1.0.4" + }, + "dependencies": { + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true + } + } + }, + "cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true + }, + "cacheable-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001331", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001331.tgz", + "integrity": "sha512-Y1xk6paHpUXKP/P6YjQv1xqyTbgAP05ycHBcRdQjTcyXlWol868sJJPlmk5ylOekw2BrucWes5jk+LvVd7WZ5Q==", + "dev": true + }, + "capital-case": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", + "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, + "capture-stack-trace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", + "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", + "dev": true + }, + "cardinal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", + "integrity": "sha1-fMEFXYItISlU0HsIXeolHMe8VQU=", + "dev": true, + "requires": { + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", + "dev": true, + "requires": { + "traverse": ">=0.3.0 <0.4" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "change-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz", + "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==", + "dev": true, + "requires": { + "camel-case": "^4.1.2", + "capital-case": "^1.0.4", + "constant-case": "^3.0.4", + "dot-case": "^3.0.4", + "header-case": "^2.0.4", + "no-case": "^3.0.4", + "param-case": "^3.0.4", + "pascal-case": "^3.1.2", + "path-case": "^3.0.4", + "sentence-case": "^3.0.4", + "snake-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "chevrotain": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-7.1.1.tgz", + "integrity": "sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw==", + "dev": true, + "requires": { + "regexp-to-ast": "0.5.0" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "ci-info": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", + "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "clean-git-ref": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz", + "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==", + "dev": true + }, + "clean-stack": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", + "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", + "dev": true, + "requires": { + "escape-string-regexp": "4.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + } + } + }, + "cli-boxes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", + "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-progress": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.10.0.tgz", + "integrity": "sha512-kLORQrhYCAtUPLZxqsAt2YJGOvRdt34+O6jl5cQGb7iF3dM55FQZlTR+rQyIK9JUcO9bBMwZsTlND+3dmFU2Cw==", + "dev": true, + "requires": { + "string-width": "^4.2.0" + } + }, + "cli-table": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz", + "integrity": "sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==", + "dev": true, + "requires": { + "colors": "1.0.3" + }, + "dependencies": { + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + } + } + }, + "cli-table3": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.2.tgz", + "integrity": "sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw==", + "dev": true, + "requires": { + "@colors/colors": "1.5.0", + "string-width": "^4.2.0" + } + }, + "cli-truncate": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", + "integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==", + "dev": true, + "requires": { + "slice-ansi": "^5.0.0", + "string-width": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "ansi-styles": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz", + "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true + }, + "slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + } + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "cli-ux": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/cli-ux/-/cli-ux-4.9.3.tgz", + "integrity": "sha512-/1owvF0SZ5Gn54cgrikJ0QskgTzeg30HGjkmjFoaHDJzAqFpuX1DBpFR8aLvsE1J5s9MgeYRENQK4BFwOag5VA==", + "dev": true, + "requires": { + "@oclif/errors": "^1.2.2", + "@oclif/linewrap": "^1.0.0", + "@oclif/screen": "^1.0.3", + "ansi-escapes": "^3.1.0", + "ansi-styles": "^3.2.1", + "cardinal": "^2.1.1", + "chalk": "^2.4.1", + "clean-stack": "^2.0.0", + "extract-stack": "^1.0.0", + "fs-extra": "^7.0.0", + "hyperlinker": "^1.0.0", + "indent-string": "^3.2.0", + "is-wsl": "^1.1.0", + "lodash": "^4.17.11", + "password-prompt": "^1.0.7", + "semver": "^5.6.0", + "strip-ansi": "^5.0.0", + "supports-color": "^5.5.0", + "supports-hyperlinks": "^1.0.1", + "treeify": "^1.1.0", + "tslib": "^1.9.3" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "dev": true + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "dev": true + }, + "cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "cls-hooked": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/cls-hooked/-/cls-hooked-4.2.2.tgz", + "integrity": "sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==", + "dev": true, + "requires": { + "async-hook-jl": "^1.7.6", + "emitter-listener": "^1.0.1", + "semver": "^5.4.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "co-prompt": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/co-prompt/-/co-prompt-1.0.0.tgz", + "integrity": "sha1-+zcOntrEhXayenMv5dfyHZ/G5vY=", + "dev": true, + "requires": { + "keypress": "~0.2.1" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "coffeescript": { + "version": "1.12.7", + "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.12.7.tgz", + "integrity": "sha512-pLXHFxQMPklVoEekowk8b3erNynC+DVJzChxS/LCBBgR6/8AJkHivkm//zbowcfc7BTCAjryuhx6gPqPRfsFoA==", + "dev": true + }, + "collect-all": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/collect-all/-/collect-all-1.0.4.tgz", + "integrity": "sha512-RKZhRwJtJEP5FWul+gkSMEnaK6H3AGPTTWOiRimCcs+rc/OmQE3Yhy1Q7A7KsdkG3ZXVdZq68Y6ONSdvkeEcKA==", + "dev": true, + "requires": { + "stream-connect": "^1.0.2", + "stream-via": "^1.0.4" + } + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "dev": true + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "dev": true, + "requires": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "dependencies": { + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true + }, + "typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "dev": true + } + } + }, + "command-line-tool": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/command-line-tool/-/command-line-tool-0.8.0.tgz", + "integrity": "sha512-Xw18HVx/QzQV3Sc5k1vy3kgtOeGmsKIqwtFFoyjI4bbcpSgnw2CWVULvtakyw4s6fhyAdI6soQQhXc2OzJy62g==", + "dev": true, + "requires": { + "ansi-escape-sequences": "^4.0.0", + "array-back": "^2.0.0", + "command-line-args": "^5.0.0", + "command-line-usage": "^4.1.0", + "typical": "^2.6.1" + }, + "dependencies": { + "array-back": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", + "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "dev": true, + "requires": { + "typical": "^2.6.1" + } + } + } + }, + "command-line-usage": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-4.1.0.tgz", + "integrity": "sha512-MxS8Ad995KpdAC0Jopo/ovGIroV/m0KHwzKfXxKag6FHOkGsH8/lv5yjgablcRxCJJC0oJeUMuO/gmaq+Wq46g==", + "dev": true, + "requires": { + "ansi-escape-sequences": "^4.0.0", + "array-back": "^2.0.0", + "table-layout": "^0.4.2", + "typical": "^2.6.1" + }, + "dependencies": { + "array-back": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz", + "integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==", + "dev": true, + "requires": { + "typical": "^2.6.1" + } + } + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "common-sequence": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-2.0.2.tgz", + "integrity": "sha512-jAg09gkdkrDO9EWTdXfv80WWH3yeZl5oT69fGfedBNS9pXUKYInVJ1bJ+/ht2+Moeei48TmSbQDYMc8EOx9G0g==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "compress-brotli": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.6.tgz", + "integrity": "sha512-au99/GqZtUtiCBliqLFbWlhnCxn+XSYjwZ77q6mKN4La4qOXDoLVPZ50iXr0WmAyMxl8yqoq3Yq4OeQNPPkyeQ==", + "dev": true, + "requires": { + "@types/json-buffer": "~3.0.0", + "json-buffer": "~3.0.1" + } + }, + "compress-commons": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz", + "integrity": "sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==", + "dev": true, + "requires": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^4.0.2", + "normalize-path": "^3.0.0", + "readable-stream": "^3.6.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concurrently": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-7.1.0.tgz", + "integrity": "sha512-Bz0tMlYKZRUDqJlNiF/OImojMB9ruKUz6GCfmhFnSapXgPe+3xzY4byqoKG9tUZ7L2PGEUjfLPOLfIX3labnmw==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "date-fns": "^2.16.1", + "lodash": "^4.17.21", + "rxjs": "^6.6.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^16.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "config-master": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/config-master/-/config-master-3.1.0.tgz", + "integrity": "sha1-ZnZjWQUFooO/JqSE1oSJ10xUhdo=", + "dev": true, + "requires": { + "walk-back": "^2.0.1" + }, + "dependencies": { + "walk-back": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-2.0.1.tgz", + "integrity": "sha1-VU4qnYdPrEeoywBr9EwvDEmYoKQ=", + "dev": true + } + } + }, + "confusing-browser-globals": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz", + "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==", + "dev": true + }, + "constant-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", + "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case": "^2.0.2" + } + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "continuation-local-storage": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", + "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==", + "dev": true, + "requires": { + "async-listener": "^0.6.0", + "emitter-listener": "^1.1.1" + } + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-js": { + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", + "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==", + "dev": true + }, + "core-js-pure": { + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz", + "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==", + "dev": true + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true + }, + "crc32-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz", + "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==", + "dev": true, + "requires": { + "crc-32": "^1.2.0", + "readable-stream": "^3.4.0" + } + }, + "create-error-class": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "dev": true, + "requires": { + "capture-stack-trace": "^1.0.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "csprng": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/csprng/-/csprng-0.1.2.tgz", + "integrity": "sha1-S8aPEvo2jSUqWYQcusqXSxirReI=", + "dev": true, + "requires": { + "sequin": "*" + } + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "requires": { + "cssom": "~0.3.6" + }, + "dependencies": { + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + } + } + }, + "csv-parse": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", + "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", + "dev": true + }, + "csv-stringify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-1.1.2.tgz", + "integrity": "sha1-d6QVJlgbzjOA8SsA18W7rHDIK1g=", + "dev": true, + "requires": { + "lodash.get": "~4.4.2" + } + }, + "dargs": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-6.1.0.tgz", + "integrity": "sha512-5dVBvpBLBnPwSsYXqfybFyehMmC/EenKEcf23AhCTgTf48JFBbmJKqoZBsERDnjL0FyiVTYWdFsRfTLHxLyKdQ==", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-uri-to-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", + "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", + "dev": true + }, + "data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "requires": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + } + }, + "date-fns": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", + "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==", + "dev": true + }, + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true + }, + "dayjs": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.0.tgz", + "integrity": "sha512-JLC809s6Y948/FuCZPm5IX8rRhQwOiyMb2TfVVQEixG7P8Lm/gt5S7yoQZmC8x1UehI9Pb7sksEt4xx14m+7Ug==", + "dev": true + }, + "dayjs-plugin-utc": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dayjs-plugin-utc/-/dayjs-plugin-utc-0.1.2.tgz", + "integrity": "sha512-ExERH5o3oo6jFOdkvMP3gytTCQ9Ksi5PtylclJWghr7k7m3o2U5QrwtdiJkOxLOH4ghr0EKhpqGefzGz1VvVJg==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decimal.js": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + } + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "degenerator": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.2.tgz", + "integrity": "sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==", + "dev": true, + "requires": { + "ast-types": "^0.13.2", + "escodegen": "^1.8.1", + "esprima": "^4.0.0", + "vm2": "^3.9.8" + }, + "dependencies": { + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "diagnostic-channel": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/diagnostic-channel/-/diagnostic-channel-0.3.1.tgz", + "integrity": "sha512-6eb9YRrimz8oTr5+JDzGmSYnXy5V7YnK5y/hd8AUDK1MssHjQKm9LlD6NSrHx4vMDF3+e/spI2hmWTviElgWZA==", + "dev": true, + "requires": { + "semver": "^5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "diagnostic-channel-publishers": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.4.4.tgz", + "integrity": "sha512-l126t01d2ZS9EreskvEtZPrcgstuvH3rbKy82oUhUrVmBaGx4hO9wECdl3cvZbKDYjMF3QJDB5z5dL9yWAjvZQ==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "dev": true + }, + "diff3": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", + "integrity": "sha1-1OXDpM305f4SEatC5pP8tDIVgPw=", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dmd": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/dmd/-/dmd-6.1.0.tgz", + "integrity": "sha512-0zQIJ873gay1scCTFZvHPWM9mVJBnaylB2NQDI8O9u8O32m00Jb6uxDKexZm8hjTRM7RiWe0FJ32pExHoXdwoQ==", + "dev": true, + "requires": { + "array-back": "^6.2.2", + "cache-point": "^2.0.0", + "common-sequence": "^2.0.2", + "file-set": "^4.0.2", + "handlebars": "^4.7.7", + "marked": "^4.0.12", + "object-get": "^2.1.1", + "reduce-flatten": "^3.0.1", + "reduce-unique": "^2.0.1", + "reduce-without": "^1.0.1", + "test-value": "^3.0.0", + "walk-back": "^5.1.0" + }, + "dependencies": { + "marked": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.14.tgz", + "integrity": "sha512-HL5sSPE/LP6U9qKgngIIPTthuxC0jrfxpYMZ3LdGDD3vTnLs59m2Z7r6+LNDR3ToqEQdkKd6YaaEfJhodJmijQ==", + "dev": true + }, + "reduce-flatten": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-3.0.1.tgz", + "integrity": "sha512-bYo+97BmUUOzg09XwfkwALt4PQH1M5L0wzKerBt6WLm3Fhdd43mMS89HiT1B9pJIqko/6lWx3OnV4J9f2Kqp5Q==", + "dev": true + } + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "requires": { + "webidl-conversions": "^5.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true + } + } + }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "download-stats": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/download-stats/-/download-stats-0.3.4.tgz", + "integrity": "sha512-ic2BigbyUWx7/CBbsfGjf71zUNZB4edBGC3oRliSzsoNmvyVx3Ycfp1w3vp2Y78Ee0eIIkjIEO5KzW0zThDGaA==", + "dev": true, + "requires": { + "JSONStream": "^1.2.1", + "lazy-cache": "^2.0.1", + "moment": "^2.15.1" + } + }, + "dtrace-provider": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.6.0.tgz", + "integrity": "sha1-CweNVReTfYcxAUUtkUZzdVe3XlE=", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.0.8" + } + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "editions": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/editions/-/editions-2.3.1.tgz", + "integrity": "sha512-ptGvkwTvGdGfC0hfhKg0MT+TRLRKGtUiWGBInxOm5pz7ssADezahjCUaYuZ8Dr+C05FW0AECIIPt4WBxVINEhA==", + "dev": true, + "requires": { + "errlop": "^2.0.0", + "semver": "^6.3.0" + } + }, + "ejs": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", + "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", + "dev": true, + "requires": { + "jake": "^10.6.1" + } + }, + "electron-to-chromium": { + "version": "1.4.107", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.107.tgz", + "integrity": "sha512-Huen6taaVrUrSy8o7mGStByba8PfOWWluHNxSHGBrCgEdFVLtvdQDBr9LBCF9Uci8SYxh28QNNMO0oC17wbGAg==", + "dev": true + }, + "emitter-listener": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", + "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "dev": true, + "requires": { + "shimmer": "^1.2.0" + } + }, + "emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "errlop": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/errlop/-/errlop-2.2.0.tgz", + "integrity": "sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw==", + "dev": true + }, + "error": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", + "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", + "dev": true, + "requires": { + "string-template": "~0.2.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.19.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.4.tgz", + "integrity": "sha512-flV8e5g9/xulChMG48Fygk1ptpo4lQRJ0eJYtxJFgi7pklLx7EFcOJ34jnvr8pbWlaFN/AT1cZpe0hiFel9Hqg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", + "dev": true, + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "eslint": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.13.0.tgz", + "integrity": "sha512-D+Xei61eInqauAyTJ6C0q6x9mx7kTUC1KZ0m0LSEexR0V+e94K12LmWX076ZIsldwfQ2RONdaJe0re0TRGQbRQ==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.2.1", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "dev": true, + "requires": { + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true + }, + "eslint-config-xo": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/eslint-config-xo/-/eslint-config-xo-0.36.0.tgz", + "integrity": "sha512-RCaqCyI38awe3qgiO0Z8CqHs9yw7dMKdV6ZRTFSR7lm0//370tbDEZaQBXnztgpwe5m6D+VvFWc3vLMP/W6EAg==", + "dev": true, + "requires": { + "confusing-browser-globals": "1.0.10" + } + }, + "eslint-config-xo-space": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/eslint-config-xo-space/-/eslint-config-xo-space-0.27.0.tgz", + "integrity": "sha512-b8UjW+nQyOkhiANVpIptqlKPyE7XRyQ40uQ1NoBhzVfu95gxfZGrpliq8ZHBpaOF2wCLZaexTSjg7Rvm99vj4A==", + "dev": true, + "requires": { + "eslint-config-xo": "^0.35.0" + }, + "dependencies": { + "eslint-config-xo": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/eslint-config-xo/-/eslint-config-xo-0.35.0.tgz", + "integrity": "sha512-+WyZTLWUJlvExFrBU/Ldw8AB/S0d3x+26JQdBWbcqig2ZaWh0zinYcHok+ET4IoPaEcRRf3FE9kjItNVjBwnAg==", + "dev": true, + "requires": { + "confusing-browser-globals": "1.0.10" + } + } + } + }, + "eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-module-utils": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", + "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "find-up": "^2.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "eslint-plugin-compat": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-4.0.2.tgz", + "integrity": "sha512-xqvoO54CLTVaEYGMzhu35Wzwk/As7rCvz/2dqwnFiWi0OJccEtGIn+5qq3zqIu9nboXlpdBN579fZcItC73Ycg==", + "dev": true, + "requires": { + "@mdn/browser-compat-data": "^4.1.5", + "ast-metadata-inferer": "^0.7.0", + "browserslist": "^4.16.8", + "caniuse-lite": "^1.0.30001304", + "core-js": "^3.16.2", + "find-up": "^5.0.0", + "lodash.memoize": "4.1.2", + "semver": "7.3.5" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "eslint-plugin-jest": { + "version": "23.8.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-23.8.2.tgz", + "integrity": "sha512-xwbnvOsotSV27MtAe7s8uGWOori0nUsrXh2f1EnpmXua8sDfY6VZhHAhHg2sqK7HBNycRQExF074XSZ7DvfoFg==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "^2.5.0" + } + }, + "eslint-restricted-globals": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.2.0.tgz", + "integrity": "sha512-kwYJALm5KS2QW3Mc1PgObO4V+pTR6RQtRT65L1GQILlEnAhabUQqGAX7/qUjoQR4KZJKehWpBtyDEiDecwmY9A==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/extend-object/-/extend-object-1.0.0.tgz", + "integrity": "sha1-QlFPhAFdE1bK9Rh5ad+yvBvaCCM=", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extract-stack": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/extract-stack/-/extract-stack-1.0.0.tgz", + "integrity": "sha1-uXrK+UQe6iMyUpYktzL8WhyBZfo=", + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fancy-test": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/fancy-test/-/fancy-test-1.4.10.tgz", + "integrity": "sha512-AaUX6wKS7D5OP2YK2q5G7c8PGx2lgoyLUD7Bbg8z323sb9aebBqzb9UN6phzI73UgO/ViihmNfOxF3kdfZLhew==", + "dev": true, + "requires": { + "@types/chai": "*", + "@types/lodash": "*", + "@types/node": "*", + "@types/sinon": "*", + "lodash": "^4.17.13", + "mock-stdin": "^1.0.0", + "nock": "^13.0.0", + "stdout-stderr": "^0.1.9" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fast-xml-parser": { + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.21.1.tgz", + "integrity": "sha512-FTFVjYoBOZTJekiUsawGsSYV9QL0A+zDYCRj7y34IO6Jg+2IMYEtQa+bbictpdpV8dHxXywqU7C0gRDEOFtBFg==", + "dev": true, + "requires": { + "strnum": "^1.0.4" + } + }, + "fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "faye": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/faye/-/faye-1.4.0.tgz", + "integrity": "sha512-kRrIg4be8VNYhycS2PY//hpBJSzZPr/DBbcy9VWelhZMW3KhyLkQR0HL0k0MNpmVoNFF4EdfMFkNAWjTP65g6w==", + "dev": true, + "requires": { + "asap": "*", + "csprng": "*", + "faye-websocket": ">=0.9.1", + "safe-buffer": "*", + "tough-cookie": "*", + "tunnel-agent": "*" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fb-watchman": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "file-set": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/file-set/-/file-set-4.0.2.tgz", + "integrity": "sha512-fuxEgzk4L8waGXaAkd8cMr73Pm0FxOVkn8hztzUW7BAHhOGH90viQNXbiOsnecCWmfInqU6YmAMwxRMdKETceQ==", + "dev": true, + "requires": { + "array-back": "^5.0.0", + "glob": "^7.1.6" + }, + "dependencies": { + "array-back": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-5.0.0.tgz", + "integrity": "sha512-kgVWwJReZWmVuWOQKEOohXKJX+nD02JAZ54D1RRWlv8L0NebauKAaFxACKzB74RTclt1+WNz5KHaLRDAPZbDEw==", + "dev": true + } + } + }, + "file-uri-to-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", + "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", + "dev": true + }, + "filelist": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", + "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "filesize": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.4.0.tgz", + "integrity": "sha512-mjFIpOHC4jbfcTfoh4rkWpI31mF7viw9ikj/JyLoKzqlwG/YsefKfvYlYhdYdg/9mtK2z1AzgN/0LvVQ3zdlSQ==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-java-home": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-java-home/-/find-java-home-1.1.0.tgz", + "integrity": "sha512-bSTCKNZ193UM/+ZZoNDzICAEHcVywovkhsWCkZALjCvRXQ+zXTe/XATrrP4CpxkaP6YFhQJOpyRpH0P2U/woDA==", + "dev": true, + "requires": { + "which": "~1.0.5", + "winreg": "~1.2.2" + }, + "dependencies": { + "which": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", + "integrity": "sha1-RgwdoPgQED0DIam2M6+eV15kSG8=", + "dev": true + } + } + }, + "find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dev": true, + "requires": { + "array-back": "^3.0.1" + }, + "dependencies": { + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true + } + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "first-chunk-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz", + "integrity": "sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "dependencies": { + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "follow-redirects": { + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "fs-extra": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", + "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "dependencies": { + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "fs-then-native": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fs-then-native/-/fs-then-native-2.0.0.tgz", + "integrity": "sha1-GaEk2U2QwiyOBF8ujdbr6jbUjGc=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "dev": true, + "requires": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "get-uri": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", + "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "data-uri-to-buffer": "3", + "debug": "4", + "file-uri-to-path": "2", + "fs-extra": "^8.1.0", + "ftp": "^0.3.10" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "gh-got": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gh-got/-/gh-got-5.0.0.tgz", + "integrity": "sha1-7pW+NxBv2HSKlvjR20uuqJ4b+oo=", + "dev": true, + "requires": { + "got": "^6.2.0", + "is-plain-obj": "^1.1.0" + } + }, + "github-username": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/github-username/-/github-username-3.0.0.tgz", + "integrity": "sha1-CnciGbMTB0NCnyRW0L3T21Xc57E=", + "dev": true, + "requires": { + "gh-got": "^5.0.0" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "got": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "dev": true, + "requires": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + }, + "dependencies": { + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + } + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "grouped-queue": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grouped-queue/-/grouped-queue-1.1.0.tgz", + "integrity": "sha512-rZOFKfCqLhsu5VqjBjEWiwrYqJR07KxIkH4mLZlNlGDfntbb4FbMyGFP14TlvRPrU9S3Hnn/sgxbC5ZeN0no3Q==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + } + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "dev": true, + "requires": { + "has-symbol-support-x": "^1.4.1" + } + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "header-case": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz", + "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==", + "dev": true, + "requires": { + "capital-case": "^1.0.4", + "tslib": "^2.0.3" + } + }, + "heroku-cli-util": { + "version": "8.0.12", + "resolved": "https://registry.npmjs.org/heroku-cli-util/-/heroku-cli-util-8.0.12.tgz", + "integrity": "sha512-63wB17oSktlA/HzpIV/PGe8Isq5AZArT51KAW1gg54zyYRIiHOwXik93HZuuRVUaVrWvVUhItFeLgqMwAwlTsw==", + "dev": true, + "requires": { + "@heroku-cli/color": "^1.1.3", + "ansi-escapes": "^3.1.0", + "ansi-styles": "^3.2.1", + "cardinal": "^2.0.1", + "chalk": "^2.4.1", + "co": "^4.6.0", + "got": "^8.3.1", + "heroku-client": "^3.1.0", + "lodash": "^4.17.10", + "netrc-parser": "^3.1.4", + "opn": "^3.0.3", + "strip-ansi": "^4.0.0", + "supports-color": "^5.4.0", + "tslib": "^1.9.0", + "tunnel-agent": "^0.6.0" + }, + "dependencies": { + "@sindresorhus/is": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true + }, + "cacheable-request": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", + "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", + "dev": true, + "requires": { + "clone-response": "1.0.2", + "get-stream": "3.0.0", + "http-cache-semantics": "3.8.1", + "keyv": "3.0.0", + "lowercase-keys": "1.0.0", + "normalize-url": "2.0.1", + "responselike": "1.0.2" + }, + "dependencies": { + "lowercase-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", + "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=", + "dev": true + } + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "got": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", + "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.7.0", + "cacheable-request": "^2.1.1", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "into-stream": "^3.1.0", + "is-retry-allowed": "^1.1.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "mimic-response": "^1.0.0", + "p-cancelable": "^0.4.0", + "p-timeout": "^2.0.1", + "pify": "^3.0.0", + "safe-buffer": "^5.1.1", + "timed-out": "^4.0.1", + "url-parse-lax": "^3.0.0", + "url-to-options": "^1.0.1" + } + }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "keyv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", + "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "dev": true, + "requires": { + "prepend-http": "^2.0.0", + "query-string": "^5.0.1", + "sort-keys": "^2.0.0" + } + }, + "opn": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/opn/-/opn-3.0.3.tgz", + "integrity": "sha1-ttmec5n3jWXDuq/+8fsojpuFJDo=", + "dev": true, + "requires": { + "object-assign": "^4.0.1" + } + }, + "p-cancelable": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", + "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + } + } + }, + "heroku-client": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/heroku-client/-/heroku-client-3.1.0.tgz", + "integrity": "sha512-UfGKwUm5duzzSVI8uUXlNAE1mus6uPxmZPji4vuG1ArV5DYL1rXsZShp0OoxraWdEwYoxCUrM6KGztC68x5EZQ==", + "dev": true, + "requires": { + "is-retry-allowed": "^1.0.0", + "tunnel-agent": "^0.6.0" + } + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.5" + } + }, + "html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "http-call": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/http-call/-/http-call-5.3.0.tgz", + "integrity": "sha512-ahwimsC23ICE4kPl9xTBjKB4inbRaeLyZeRunC/1Jy/Z6X8tv22MEAjK+KBOMSVLaqXPTTmd8638waVIKLGx2w==", + "dev": true, + "requires": { + "content-type": "^1.0.4", + "debug": "^4.1.1", + "is-retry-allowed": "^1.1.0", + "is-stream": "^2.0.0", + "parse-json": "^4.0.0", + "tunnel-agent": "^0.6.0" + }, + "dependencies": { + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + } + } + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-parser-js": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", + "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==", + "dev": true + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "husky": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", + "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "dev": true + }, + "hyperlinker": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hyperlinker/-/hyperlinker-1.0.0.tgz", + "integrity": "sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" + }, + "into-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", + "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", + "dev": true, + "requires": { + "from2": "^2.1.1", + "p-is-promise": "^1.1.0" + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-core-module": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", + "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true + }, + "is-scoped": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-scoped/-/is-scoped-1.0.0.tgz", + "integrity": "sha1-RJypgpnnEwOCViieyytUDcQ3yzA=", + "dev": true, + "requires": { + "scoped-regex": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "is-zip": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-zip/-/is-zip-1.0.0.tgz", + "integrity": "sha1-R7Co/004p2QxzP2ZqOFaTIa6IyU=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "isomorphic-git": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.17.0.tgz", + "integrity": "sha512-8ToEVqYLeTE1Ys3UQ21yAxQf0rW7GYRvsENhvXNDONAHgNks1fsgUJH3mVzgbsGf4LpW3kuJI6e/e3VIeaTW3w==", + "dev": true, + "requires": { + "async-lock": "^1.1.0", + "clean-git-ref": "^2.0.1", + "crc-32": "^1.2.0", + "diff3": "0.0.3", + "ignore": "^5.1.4", + "minimisted": "^2.0.0", + "pako": "^1.0.10", + "pify": "^4.0.1", + "readable-stream": "^3.4.0", + "sha.js": "^2.4.9", + "simple-get": "^4.0.1" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", + "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", + "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "istextorbinary": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.6.0.tgz", + "integrity": "sha512-+XRlFseT8B3L9KyjxxLjfXSLMuErKDsd8DBNrsaxoViABMEZlOSCstwmw0qpoFX3+U6yWU1yhLudAe6/lETGGA==", + "dev": true, + "requires": { + "binaryextensions": "^2.1.2", + "editions": "^2.2.0", + "textextensions": "^2.5.0" + } + }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "dev": true, + "requires": { + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" + } + }, + "jake": { + "version": "10.8.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.4.tgz", + "integrity": "sha512-MtWeTkl1qGsWUtbl/Jsca/8xSoK3x0UmS82sNbjqxxG/de/M/3b1DntdjHgPMC50enlTNwXOCRqPXLLt5cCfZA==", + "dev": true, + "requires": { + "async": "0.9.x", + "chalk": "^4.0.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest": { + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.0.6.tgz", + "integrity": "sha512-EjV8aETrsD0wHl7CKMibKwQNQc3gIRBXlTikBmmHUeVMKaPFxdcUIBfoDqTSXDoGJIivAYGqCWVlzCSaVjPQsA==", + "dev": true, + "requires": { + "@jest/core": "^27.0.6", + "import-local": "^3.0.2", + "jest-cli": "^27.0.6" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "dev": true, + "requires": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + } + }, + "jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "dev": true, + "requires": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + } + }, + "jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + } + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true + }, + "jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + } + }, + "jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "dev": true, + "requires": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + } + }, + "jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true + }, + "jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "dev": true + }, + "jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-resolve-dependencies": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + } + }, + "jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "dev": true, + "requires": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-runtime": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "dev": true, + "requires": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + } + }, + "jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "dev": true, + "requires": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "dev": true, + "requires": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "dev": true, + "requires": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.0.1" + }, + "dependencies": { + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "joi": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", + "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.0.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "dev": true, + "requires": { + "xmlcreate": "^2.0.4" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true }, - "fancy-test": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/fancy-test/-/fancy-test-1.4.10.tgz", - "integrity": "sha512-AaUX6wKS7D5OP2YK2q5G7c8PGx2lgoyLUD7Bbg8z323sb9aebBqzb9UN6phzI73UgO/ViihmNfOxF3kdfZLhew==", + "jsdoc": { + "version": "3.6.10", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.10.tgz", + "integrity": "sha512-IdQ8ppSo5LKZ9o3M+LKIIK8i00DIe5msDvG3G81Km+1dhy0XrOWD0Ji8H61ElgyEj/O9KRLokgKbAM9XX9CJAg==", + "dev": true, + "requires": { + "@babel/parser": "^7.9.4", + "@types/markdown-it": "^12.2.3", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^4.0.1", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "taffydb": "2.6.2", + "underscore": "~1.13.2" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + } + } + }, + "jsdoc-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-7.1.1.tgz", + "integrity": "sha512-0pkuPCzVXiqsDAsVrNFXCkHzlyNepBIDVtwwehry4RJAnZmXtlAz7rh8F9FRz53u3NeynGbex+bpYWwi8lE66A==", "dev": true, "requires": { - "@types/chai": "*", - "@types/lodash": "*", - "@types/node": "*", - "@types/sinon": "*", - "lodash": "^4.17.13", - "mock-stdin": "^1.0.0", - "nock": "^13.0.0", - "stdout-stderr": "^0.1.9" + "array-back": "^6.2.2", + "cache-point": "^2.0.0", + "collect-all": "^1.0.4", + "file-set": "^4.0.2", + "fs-then-native": "^2.0.0", + "jsdoc": "^3.6.10", + "object-to-spawn-args": "^2.0.1", + "temp-path": "^1.0.0", + "walk-back": "^5.1.0" } }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "jsdoc-parse": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-6.1.0.tgz", + "integrity": "sha512-n/hDGQJa69IBun1yZAjqzV4gVR41+flZ3bIlm9fKvNe2Xjsd1/+zCo2+R9ls8LxtePgIWbpA1jU7xkB2lRdLLg==", + "dev": true, + "requires": { + "array-back": "^6.2.2", + "lodash.omit": "^4.5.0", + "lodash.pick": "^4.4.0", + "reduce-extract": "^1.0.0", + "sort-array": "^4.1.4", + "test-value": "^3.0.0" + } + }, + "jsdoc-to-markdown": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-7.1.1.tgz", + "integrity": "sha512-CI86d63xAVNO+ENumWwmJ034lYe5iGU5GwjtTA11EuphP9tpnoi4hrKgR/J8uME0D+o4KUpVfwX1fjZhc8dEtg==", + "dev": true, + "requires": { + "array-back": "^6.2.2", + "command-line-tool": "^0.8.0", + "config-master": "^3.1.0", + "dmd": "^6.1.0", + "jsdoc-api": "^7.1.1", + "jsdoc-parse": "^6.1.0", + "walk-back": "^5.1.0" + } + }, + "jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dev": true, + "requires": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, + "jsen": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/jsen/-/jsen-0.6.6.tgz", + "integrity": "sha1-AkDBjPETUKwCFFb0in6xO9Z+BCA=", "dev": true }, - "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "jsforce": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/jsforce/-/jsforce-1.11.0.tgz", + "integrity": "sha512-vYNXJXXdz9ZQNdfRqq/MCJ/zU7JGA7iEduwafQDzChR9FeqXgTNfHTppLVbw9mIniKkQZemmxSOtl7N04lj/5Q==", "dev": true, "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "base64-url": "^2.2.0", + "co-prompt": "^1.0.0", + "coffeescript": "^1.10.0", + "commander": "^2.9.0", + "csv-parse": "^4.10.1", + "csv-stringify": "^1.0.4", + "faye": "^1.4.0", + "inherits": "^2.0.1", + "lodash": "^4.17.19", + "multistream": "^2.0.5", + "opn": "^5.3.0", + "promise": "^7.1.1", + "readable-stream": "^2.1.0", + "request": "^2.72.0", + "xml2js": "^0.4.16" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } } }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "dev": true, "requires": { - "reusify": "^1.0.4" + "graceful-fs": "^4.1.6" } }, - "faye": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/faye/-/faye-1.4.0.tgz", - "integrity": "sha512-kRrIg4be8VNYhycS2PY//hpBJSzZPr/DBbcy9VWelhZMW3KhyLkQR0HL0k0MNpmVoNFF4EdfMFkNAWjTP65g6w==", + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true + }, + "jsonwebtoken": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz", + "integrity": "sha512-IqEycp0znWHNA11TpYi77bVgyBO/pGESDh7Ajhas+u0ttkGkKYIIAjniL4Bw5+oVejVF+SYkaI7XKfwCCyeTuA==", "dev": true, "requires": { - "asap": "*", - "csprng": "*", - "faye-websocket": ">=0.9.1", - "safe-buffer": "*", - "tough-cookie": "*", - "tunnel-agent": "*" + "jws": "^3.2.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, - "faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, "requires": { - "websocket-driver": ">=0.5.1" + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" } }, - "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dev": true, + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", "dev": true, "requires": { - "bser": "2.1.1" + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" } }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "keypress": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.2.1.tgz", + "integrity": "sha1-HoBFQlABjbrUw/6USX1uZ7YmnHc=", + "dev": true + }, + "keyv": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.2.2.tgz", + "integrity": "sha512-uYS0vKTlBIjNCAUqrjlxmruxOEiZxZIHXyp32sdcGmP+ukFrmWUnE//RcPXJH3Vxrni1H2gsQbjHE0bH7MtMQQ==", "dev": true, "requires": { - "escape-string-regexp": "^1.0.5" + "compress-brotli": "^1.3.6", + "json-buffer": "3.0.1" } }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "klaw": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-4.0.1.tgz", + "integrity": "sha512-pgsE40/SvC7st04AHiISNewaIMUbY5V/K8b21ekiPiFoYs/EYSdsGa+FJArB1d441uq4Q8zZyIxvAzkGNlBdRw==", + "dev": true + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "lazy-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", + "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", "dev": true, "requires": { - "flat-cache": "^2.0.1" + "set-getter": "^0.1.0" } }, - "file-set": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/file-set/-/file-set-4.0.2.tgz", - "integrity": "sha512-fuxEgzk4L8waGXaAkd8cMr73Pm0FxOVkn8hztzUW7BAHhOGH90viQNXbiOsnecCWmfInqU6YmAMwxRMdKETceQ==", + "lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", "dev": true, "requires": { - "array-back": "^5.0.0", - "glob": "^7.1.6" + "readable-stream": "^2.0.5" }, "dependencies": { - "array-back": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-5.0.0.tgz", - "integrity": "sha512-kgVWwJReZWmVuWOQKEOohXKJX+nD02JAZ54D1RRWlv8L0NebauKAaFxACKzB74RTclt1+WNz5KHaLRDAPZbDEw==", + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true } } }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, "requires": { - "to-regex-range": "^5.0.1" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" } }, - "find-java-home": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-java-home/-/find-java-home-1.1.0.tgz", - "integrity": "sha512-bSTCKNZ193UM/+ZZoNDzICAEHcVywovkhsWCkZALjCvRXQ+zXTe/XATrrP4CpxkaP6YFhQJOpyRpH0P2U/woDA==", + "lilconfig": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", + "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "dev": true + }, + "line-column": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/line-column/-/line-column-1.0.2.tgz", + "integrity": "sha1-0lryk2tvSEkXKzEuR5LR2Ye8NKI=", "dev": true, "requires": { - "which": "~1.0.5", - "winreg": "~1.2.2" - }, - "dependencies": { - "which": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", - "integrity": "sha1-RgwdoPgQED0DIam2M6+eV15kSG8=", - "dev": true - } + "isarray": "^1.0.0", + "isobject": "^2.0.0" } }, - "find-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", - "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "lint-staged": { + "version": "12.3.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.3.7.tgz", + "integrity": "sha512-/S4D726e2GIsDVWIk1XGvheCaDm1SJRQp8efamZFWJxQMVEbOwSysp7xb49Oo73KYCdy97mIWinhlxcoNqIfIQ==", "dev": true, "requires": { - "array-back": "^3.0.1" + "cli-truncate": "^3.1.0", + "colorette": "^2.0.16", + "commander": "^8.3.0", + "debug": "^4.3.3", + "execa": "^5.1.1", + "lilconfig": "2.0.4", + "listr2": "^4.0.1", + "micromatch": "^4.0.4", + "normalize-path": "^3.0.0", + "object-inspect": "^1.12.0", + "pidtree": "^0.5.0", + "string-argv": "^0.3.1", + "supports-color": "^9.2.1", + "yaml": "^1.10.2" }, "dependencies": { - "array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true + }, + "supports-color": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.2.tgz", + "integrity": "sha512-XC6g/Kgux+rJXmwokjm9ECpD6k/smUoS5LKlUCcsYr4IY3rW0XyAympon2RmxGrlnZURMpg5T18gWDP9CsHXFA==", "dev": true } } }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } + "listenercount": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", + "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", + "dev": true }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "listr2": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz", + "integrity": "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==", "dev": true, "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.5", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" }, "dependencies": { - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "glob": "^7.1.3" + "color-convert": "^2.0.1" + } + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "rxjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.5.tgz", + "integrity": "sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" } } } }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "follow-redirects": { - "version": "1.14.8", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", - "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==" - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } } }, - "fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "requires": { - "minipass": "^2.6.0" + "p-locate": "^5.0.0" } }, - "fs-then-native": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fs-then-native/-/fs-then-native-2.0.0.tgz", - "integrity": "sha1-GaEk2U2QwiyOBF8ujdbr6jbUjGc=", + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", "dev": true }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", "dev": true }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", "dev": true }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", "dev": true }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", "dev": true }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=", + "dev": true }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=", + "dev": true }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=", + "dev": true }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=", "dev": true }, - "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - } + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", + "dev": true }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", "dev": true }, - "handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", - "dev": true, - "requires": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4", - "wordwrap": "^1.0.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "dev": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } + "lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=", + "dev": true }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", + "dev": true }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "lodash.padend": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", + "integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=", "dev": true }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=", "dev": true }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=", "dev": true }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", "dev": true, "requires": { - "has-symbols": "^1.0.2" + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" } }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", "dev": true, "requires": { - "whatwg-encoding": "^1.0.5" + "lodash._reinterpolate": "^3.0.0" } }, - "html-entities": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", - "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==", - "dev": true - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-parser-js": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", - "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==", + "lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=", "dev": true }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "log-chopper": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-chopper/-/log-chopper-1.0.2.tgz", + "integrity": "sha512-tEWS6Fb+Xv0yLChJ6saA1DP3H1yPL0PfiIN7SDJ+U/CyP+fD4G/dhKfow+P5UuJWi6BdE4mUcPkJclGXCWxDrg==", "dev": true, "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "byline": "5.x" } }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", "dev": true, "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "chalk": "^2.0.1" } }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", "dev": true, "requires": { - "agent-base": "6", - "debug": "4" + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } } }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "husky": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", - "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", - "dev": true - }, - "hyperlinker": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hyperlinker/-/hyperlinker-1.0.0.tgz", - "integrity": "sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "dev": true, "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "tslib": "^2.0.3" } }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "ignore": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz", - "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==", + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", "dev": true }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "yallist": "^4.0.0" }, "dependencies": { - "resolve-from": { + "yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true } } }, - "import-local": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", - "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" + "semver": "^6.0.0" } }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "requires": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" + }, + "linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "requires": { + "uc.micro": "^1.0.1" + } + } + } + }, + "markdown-it-anchor": { + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.2.tgz", + "integrity": "sha512-JNaekTlIwwyYGBN3zifZDxgz4bSL8sbEj58fdTZGmPSMMGXBZapFjcZk2I33Jy79c1fvCKHpF7MA/67FOTjvzA==", "dev": true }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "marked": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.10.tgz", + "integrity": "sha512-+QvuFj0nGgO970fySghXGmuw+Fd0gD2x3+MqCWLIPf5oxdv1Ka6b2q+z9RP01P/IaKPMEramy+7cNy/Lw8c3hw==" }, - "inquirer": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "marked-terminal": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-4.2.0.tgz", + "integrity": "sha512-DQfNRV9svZf0Dm9Cf5x5xaVJ1+XjxQW6XjFJ5HFkVyK52SDpj5PCBzS5X5r2w9nHr3mlB0T5201UMLue9fmhUw==", "dev": true, "requires": { - "ansi-escapes": "^4.2.1", + "ansi-escapes": "^4.3.1", + "cardinal": "^2.1.1", "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" + "cli-table3": "^0.6.0", + "node-emoji": "^1.10.0", + "supports-hyperlinks": "^2.1.0" }, "dependencies": { + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -5693,445 +14719,1311 @@ "requires": { "has-flag": "^4.0.0" } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } } } }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "mem-fs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mem-fs/-/mem-fs-1.2.0.tgz", + "integrity": "sha512-b8g0jWKdl8pM0LqAPdK9i8ERL7nYrzmJfRhxMiWH2uYdfYnb7uXnmwVb0ZGe7xyEl4lj+nLIU3yf4zPUT+XsVQ==", "dev": true, "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true - }, - "is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", - "requires": { - "has": "^1.0.3" + "through2": "^3.0.0", + "vinyl": "^2.0.1", + "vinyl-file": "^3.0.0" } }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "mem-fs-editor": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/mem-fs-editor/-/mem-fs-editor-6.0.0.tgz", + "integrity": "sha512-e0WfJAMm8Gv1mP5fEq/Blzy6Lt1VbLg7gNnZmZak7nhrBTibs+c6nQ4SKs/ZyJYHS1mFgDJeopsLAv7Ow0FMFg==", "dev": true, "requires": { - "has-tostringtag": "^1.0.0" + "commondir": "^1.0.1", + "deep-extend": "^0.6.0", + "ejs": "^2.6.1", + "glob": "^7.1.4", + "globby": "^9.2.0", + "isbinaryfile": "^4.0.0", + "mkdirp": "^0.5.0", + "multimatch": "^4.0.0", + "rimraf": "^2.6.3", + "through2": "^3.0.1", + "vinyl": "^2.2.0" + }, + "dependencies": { + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + } + }, + "ejs": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", + "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", + "dev": true + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "globby": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.2", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } } }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "requires": { - "is-extglob": "^2.1.1" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true }, - "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "requires": { - "has-tostringtag": "^1.0.0" + "mime-db": "1.52.0" } }, - "is-potential-custom-element-name": { + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mimic-response": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", "dev": true }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "brace-expansion": "^1.1.7" } }, - "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, - "is-stream": { + "minimisted": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true + "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz", + "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", "dev": true, "requires": { - "has-tostringtag": "^1.0.0" + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" } }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", "dev": true, "requires": { - "has-symbols": "^1.0.2" + "minipass": "^2.9.0" } }, - "is-typedarray": { + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "mkdirp2": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/mkdirp2/-/mkdirp2-1.0.5.tgz", + "integrity": "sha512-xOE9xbICroUDmG1ye2h4bZ8WBie9EGmACaco8K8cx6RlkJJrxGIqjGqztAI+NMhexXBcdGbSEzI6N3EJPevxZw==", + "dev": true + }, + "mock-stdin": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "resolved": "https://registry.npmjs.org/mock-stdin/-/mock-stdin-1.0.0.tgz", + "integrity": "sha512-tukRdb9Beu27t6dN+XztSRHq9J0B/CoAOySGzHfn8UTfmqipA5yNT/sDUEyYdAV3Hpka6Wx6kOMxuObdOex60Q==", "dev": true }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "moment": { + "version": "2.29.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz", + "integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "multimatch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz", + "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", "dev": true, "requires": { - "call-bind": "^1.0.2" + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true + } } }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "multistream": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/multistream/-/multistream-2.1.1.tgz", + "integrity": "sha512-xasv76hl6nr1dEy3lPvy7Ej7K/Lx3O/FCvwge8PeVJpciPPoNCbaANcNiBug3IpdvTveZUcAV0DJzdnUDMesNQ==", "dev": true, "requires": { - "is-docker": "^2.0.0" + "inherits": "^2.0.1", + "readable-stream": "^2.0.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } } }, - "is-zip": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-zip/-/is-zip-1.0.0.tgz", - "integrity": "sha1-R7Co/004p2QxzP2ZqOFaTIa6IyU=", + "mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", "dev": true }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "isbinaryfile": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", - "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", + "mv": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", + "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", + "dev": true, + "optional": true, + "requires": { + "mkdirp": "~0.5.1", + "ncp": "~2.0.0", + "rimraf": "~2.4.0" + } + }, + "nan": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", + "dev": true, + "optional": true + }, + "nanoid": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", + "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==" + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "isexe": { + "natural-orderby": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-2.0.3.tgz", + "integrity": "sha512-p7KTHxU0CUrcOXe62Zfrb5Z13nLvPhSWR/so3kFulUQU0sgUll2Z0LwpsLN351eOOD+hRGu/F1g+6xDfPeD++Q==", + "dev": true + }, + "ncp": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "dev": true, + "optional": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", "dev": true }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "netrc-parser": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/netrc-parser/-/netrc-parser-3.1.6.tgz", + "integrity": "sha512-lY+fmkqSwntAAjfP63jB4z5p5WbuZwyMCD3pInT7dpHU/Gc6Vv90SAC6A0aNiqaRGHiuZFBtiwu+pu8W/Eyotw==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "execa": "^0.10.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "execa": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", + "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + } + } + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, - "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "nock": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.4.tgz", + "integrity": "sha512-8GPznwxcPNCH/h8B+XZcKjYPXnUV5clOKCjAqyjsiqA++MpNx9E9+t8YPp0MbThO+KauRo7aZJ1WuIZmOrT2Ug==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "lodash.set": "^4.3.2", + "propagate": "^2.0.0" + } + }, + "node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", "dev": true, "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" + "lodash": "^4.17.21" } }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "dev": true, "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" + "whatwg-url": "^5.0.0" }, "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", "dev": true, "requires": { - "has-flag": "^4.0.0" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } } } }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-releases": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.3.tgz", + "integrity": "sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw==", + "dev": true + }, + "node-stream-zip": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.13.2.tgz", + "integrity": "sha512-159NUO3quDIRVSVOQiQ/0VG8NFrGvVyUa+MUUleiOys3NLtrGtNkodqYYTRHU/kiXu/ygHZcNy/tZ4NUCcDUmQ==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" }, "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } }, - "istanbul-reports": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.3.tgz", - "integrity": "sha512-x9LtDVtfm/t1GFiLl3NffC7hz+I1ragvgX1P/Lg1NlIagifZDKUkuuaAxH/qpwj2IuEfD8G2Bs/UKp+sZ/pKkg==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true }, - "jest": { - "version": "27.0.6", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.0.6.tgz", - "integrity": "sha512-EjV8aETrsD0wHl7CKMibKwQNQc3gIRBXlTikBmmHUeVMKaPFxdcUIBfoDqTSXDoGJIivAYGqCWVlzCSaVjPQsA==", + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true + }, + "npm": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/npm/-/npm-7.24.2.tgz", + "integrity": "sha512-120p116CE8VMMZ+hk8IAb1inCPk4Dj3VZw29/n2g6UI77urJKVYb7FZUDW8hY+EBnfsjI/2yrobBgFyzo7YpVQ==", "dev": true, "requires": { - "@jest/core": "^27.0.6", - "import-local": "^3.0.2", - "jest-cli": "^27.0.6" + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^2.9.0", + "@npmcli/ci-detect": "^1.2.0", + "@npmcli/config": "^2.3.0", + "@npmcli/map-workspaces": "^1.0.4", + "@npmcli/package-json": "^1.0.1", + "@npmcli/run-script": "^1.8.6", + "abbrev": "~1.1.1", + "ansicolors": "~0.3.2", + "ansistyles": "~0.1.3", + "archy": "~1.0.0", + "cacache": "^15.3.0", + "chalk": "^4.1.2", + "chownr": "^2.0.0", + "cli-columns": "^3.1.2", + "cli-table3": "^0.6.0", + "columnify": "~1.5.4", + "fastest-levenshtein": "^1.0.12", + "glob": "^7.2.0", + "graceful-fs": "^4.2.8", + "hosted-git-info": "^4.0.2", + "ini": "^2.0.0", + "init-package-json": "^2.0.5", + "is-cidr": "^4.0.2", + "json-parse-even-better-errors": "^2.3.1", + "libnpmaccess": "^4.0.2", + "libnpmdiff": "^2.0.4", + "libnpmexec": "^2.0.1", + "libnpmfund": "^1.1.0", + "libnpmhook": "^6.0.2", + "libnpmorg": "^2.0.2", + "libnpmpack": "^2.0.1", + "libnpmpublish": "^4.0.1", + "libnpmsearch": "^3.1.1", + "libnpmteam": "^2.0.3", + "libnpmversion": "^1.2.1", + "make-fetch-happen": "^9.1.0", + "minipass": "^3.1.3", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "mkdirp-infer-owner": "^2.0.0", + "ms": "^2.1.2", + "node-gyp": "^7.1.2", + "nopt": "^5.0.0", + "npm-audit-report": "^2.1.5", + "npm-install-checks": "^4.0.0", + "npm-package-arg": "^8.1.5", + "npm-pick-manifest": "^6.1.1", + "npm-profile": "^5.0.3", + "npm-registry-fetch": "^11.0.0", + "npm-user-validate": "^1.0.1", + "npmlog": "^5.0.1", + "opener": "^1.5.2", + "pacote": "^11.3.5", + "parse-conflict-json": "^1.1.1", + "qrcode-terminal": "^0.12.0", + "read": "~1.0.7", + "read-package-json": "^4.1.1", + "read-package-json-fast": "^2.0.3", + "readdir-scoped-modules": "^1.1.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "ssri": "^8.0.1", + "tar": "^6.1.11", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^1.0.4", + "validate-npm-package-name": "~3.0.0", + "which": "^2.0.2", + "write-file-atomic": "^3.0.3" }, "dependencies": { + "@gar/promisify": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "@isaacs/string-locale-compare": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "@npmcli/arborist": { + "version": "2.9.0", + "bundled": true, + "dev": true, + "requires": { + "@isaacs/string-locale-compare": "^1.0.1", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/map-workspaces": "^1.0.2", + "@npmcli/metavuln-calculator": "^1.1.0", + "@npmcli/move-file": "^1.1.0", + "@npmcli/name-from-folder": "^1.0.1", + "@npmcli/node-gyp": "^1.0.1", + "@npmcli/package-json": "^1.0.1", + "@npmcli/run-script": "^1.8.2", + "bin-links": "^2.2.1", + "cacache": "^15.0.3", + "common-ancestor-path": "^1.0.1", + "json-parse-even-better-errors": "^2.3.1", + "json-stringify-nice": "^1.1.4", + "mkdirp": "^1.0.4", + "mkdirp-infer-owner": "^2.0.0", + "npm-install-checks": "^4.0.0", + "npm-package-arg": "^8.1.5", + "npm-pick-manifest": "^6.1.0", + "npm-registry-fetch": "^11.0.0", + "pacote": "^11.3.5", + "parse-conflict-json": "^1.1.1", + "proc-log": "^1.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^1.0.1", + "read-package-json-fast": "^2.0.2", + "readdir-scoped-modules": "^1.1.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "ssri": "^8.0.1", + "treeverse": "^1.0.4", + "walk-up-path": "^1.0.0" + } + }, + "@npmcli/ci-detect": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "@npmcli/config": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "requires": { + "ini": "^2.0.0", + "mkdirp-infer-owner": "^2.0.0", + "nopt": "^5.0.0", + "semver": "^7.3.4", + "walk-up-path": "^1.0.0" + } + }, + "@npmcli/disparity-colors": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "^4.3.0" + } + }, + "@npmcli/fs": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^1.3.2", + "lru-cache": "^6.0.0", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^6.1.1", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + } + }, + "@npmcli/installed-package-contents": { + "version": "1.0.7", + "bundled": true, + "dev": true, + "requires": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "@npmcli/map-workspaces": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/name-from-folder": "^1.0.1", + "glob": "^7.1.6", + "minimatch": "^3.0.4", + "read-package-json-fast": "^2.0.1" + } + }, + "@npmcli/metavuln-calculator": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "cacache": "^15.0.5", + "pacote": "^11.1.11", + "semver": "^7.3.2" + } + }, + "@npmcli/move-file": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@npmcli/name-from-folder": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "@npmcli/node-gyp": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "@npmcli/package-json": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.1" + } + }, + "@npmcli/promise-spawn": { + "version": "1.3.2", + "bundled": true, + "dev": true, + "requires": { + "infer-owner": "^1.0.4" + } + }, + "@npmcli/run-script": { + "version": "1.8.6", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/node-gyp": "^1.0.2", + "@npmcli/promise-spawn": "^1.3.2", + "node-gyp": "^7.1.0", + "read-package-json-fast": "^2.0.1" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "bundled": true, + "dev": true, + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.1.4", + "bundled": true, + "dev": true, + "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + } + }, + "aggregate-error": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "bundled": true, + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, "ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "bundled": true, + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "archy": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.6", + "bundled": true, + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "asap": { + "version": "2.0.6", + "bundled": true, + "dev": true + }, + "asn1": { + "version": "0.2.4", + "bundled": true, + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "bundled": true, + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "bundled": true, + "dev": true + }, + "aws4": { + "version": "1.11.0", + "bundled": true, + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bin-links": { + "version": "2.2.1", + "bundled": true, + "dev": true, + "requires": { + "cmd-shim": "^4.0.1", + "mkdirp": "^1.0.3", + "npm-normalize-package-bin": "^1.0.0", + "read-cmd-shim": "^2.0.0", + "rimraf": "^3.0.0", + "write-file-atomic": "^3.0.3" + } + }, + "binary-extensions": { + "version": "2.2.0", + "bundled": true, + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "builtins": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "cacache": { + "version": "15.3.0", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" } }, + "caseless": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "bundled": true, "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "chownr": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "cidr-regex": { + "version": "3.1.1", + "bundled": true, "dev": true, "requires": { - "color-name": "~1.1.4" + "ip-regex": "^4.1.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "clean-stack": { + "version": "2.2.0", + "bundled": true, "dev": true }, - "jest-cli": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.4.5.tgz", - "integrity": "sha512-hrky3DSgE0u7sQxaCL7bdebEPHx5QzYmrGuUjaPLmPE8jx5adtvGuOlRspvMoVLTTDOHRnZDoRLYJuA+VCI7Hg==", + "cli-columns": { + "version": "3.1.2", + "bundled": true, "dev": true, "requires": { - "@jest/core": "^27.4.5", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "jest-config": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "prompts": "^2.0.1", - "yargs": "^16.2.0" + "string-width": "^2.0.0", + "strip-ansi": "^3.0.1" } }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-changed-files": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz", - "integrity": "sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "execa": "^5.0.0", - "throat": "^6.0.1" - } - }, - "jest-circus": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.4.5.tgz", - "integrity": "sha512-eTNWa9wsvBwPykhMMShheafbwyakcdHZaEYh5iRrQ0PFJxkDP/e3U/FvzGuKWu2WpwUA3C3hPlfpuzvOdTVqnw==", - "dev": true, - "requires": { - "@jest/environment": "^27.4.4", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.4.2", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.2", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-runtime": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "cli-table3": { + "version": "0.6.0", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^4.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "string-width": { + "version": "4.2.2", + "bundled": true, + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "clone": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "cmd-shim": { + "version": "4.1.0", + "bundled": true, "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "mkdirp-infer-owner": "^2.0.0" } }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, "color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "bundled": true, "dev": true, "requires": { "color-name": "~1.1.4" @@ -6139,2221 +16031,1554 @@ }, "color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "bundled": true, "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "color-support": { + "version": "1.1.3", + "bundled": true, "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "colors": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true + }, + "columnify": { + "version": "1.5.4", + "bundled": true, "dev": true, "requires": { - "has-flag": "^4.0.0" + "strip-ansi": "^3.0.0", + "wcwidth": "^1.0.0" } - } - } - }, - "jest-config": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.4.5.tgz", - "integrity": "sha512-t+STVJtPt+fpqQ8GBw850NtSQbnDOw/UzdPfzDaHQ48/AylQlW7LHj3dH+ndxhC1UxJ0Q3qkq7IH+nM1skwTwA==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.4.5", - "@jest/types": "^27.4.2", - "babel-jest": "^27.4.5", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-circus": "^27.4.5", - "jest-environment-jsdom": "^27.4.4", - "jest-environment-node": "^27.4.4", - "jest-get-type": "^27.4.0", - "jest-jasmine2": "^27.4.5", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.5", - "jest-runner": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "micromatch": "^4.0.4", - "pretty-format": "^27.4.2", - "slash": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + }, + "combined-stream": { + "version": "1.0.8", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "delayed-stream": "~1.0.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "common-ancestor-path": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "bundled": true, "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "assert-plus": "^1.0.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "debug": { + "version": "4.3.2", + "bundled": true, "dev": true, "requires": { - "color-name": "~1.1.4" + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "bundled": true, + "dev": true + } } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "debuglog": { + "version": "1.0.1", + "bundled": true, "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "defaults": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true, "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "depd": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "dezalgo": { + "version": "1.0.3", + "bundled": true, "dev": true, "requires": { - "has-flag": "^4.0.0" + "asap": "^2.0.0", + "wrappy": "1" } - } - } - }, - "jest-diff": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.2.tgz", - "integrity": "sha512-ujc9ToyUZDh9KcqvQDkk/gkbf6zSaeEg9AiBxtttXW59H/AcqEYp1ciXAtJp+jXWva5nAf/ePtSsgWwE5mqp4Q==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^27.4.0", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + }, + "diff": { + "version": "5.0.0", + "bundled": true, + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "emoji-regex": { + "version": "8.0.0", + "bundled": true, + "dev": true + }, + "encoding": { + "version": "0.1.13", + "bundled": true, "dev": true, + "optional": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "iconv-lite": "^0.6.2" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "env-paths": { + "version": "2.2.1", + "bundled": true, + "dev": true + }, + "err-code": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "extend": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "bundled": true, + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "fastest-levenshtein": { + "version": "1.0.12", + "bundled": true, + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true, + "dev": true + }, + "fs-minipass": { + "version": "2.1.0", + "bundled": true, "dev": true, "requires": { - "color-name": "~1.1.4" + "minipass": "^3.0.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "fs.realpath": { + "version": "1.0.0", + "bundled": true, "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "function-bind": { + "version": "1.1.1", + "bundled": true, "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "gauge": { + "version": "3.0.1", + "bundled": true, "dev": true, "requires": { - "has-flag": "^4.0.0" + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1 || ^2.0.0", + "strip-ansi": "^3.0.1 || ^4.0.0", + "wide-align": "^1.1.2" } - } - } - }, - "jest-docblock": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.4.0.tgz", - "integrity": "sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.4.2.tgz", - "integrity": "sha512-53V2MNyW28CTruB3lXaHNk6PkiIFuzdOC9gR3C6j8YE/ACfrPnz+slB0s17AgU1TtxNzLuHyvNlLJ+8QYw9nBg==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + }, + "getpass": { + "version": "0.1.7", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "assert-plus": "^1.0.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "glob": { + "version": "7.2.0", + "bundled": true, "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "graceful-fs": { + "version": "4.2.8", + "bundled": true, + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "bundled": true, "dev": true, "requires": { - "color-name": "~1.1.4" + "ajv": "^6.12.3", + "har-schema": "^2.0.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "has": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } }, "has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "bundled": true, "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "hosted-git-info": { + "version": "4.0.2", + "bundled": true, "dev": true, "requires": { - "has-flag": "^4.0.0" + "lru-cache": "^6.0.0" } - } - } - }, - "jest-environment-jsdom": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.4.4.tgz", - "integrity": "sha512-cYR3ndNfHBqQgFvS1RL7dNqSvD//K56j/q1s2ygNHcfTCAp12zfIromO1w3COmXrxS8hWAh7+CmZmGCIoqGcGA==", - "dev": true, - "requires": { - "@jest/environment": "^27.4.4", - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2", - "jsdom": "^16.6.0" - } - }, - "jest-environment-node": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.4.4.tgz", - "integrity": "sha512-D+v3lbJ2GjQTQR23TK0kY3vFVmSeea05giInI41HHOaJnAwOnmUHTZgUaZL+VxUB43pIzoa7PMwWtCVlIUoVoA==", - "dev": true, - "requires": { - "@jest/environment": "^27.4.4", - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/node": "*", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2" - } - }, - "jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", - "dev": true - }, - "jest-haste-map": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.4.5.tgz", - "integrity": "sha512-oJm1b5qhhPs78K24EDGifWS0dELYxnoBiDhatT/FThgB9yxqUm5F6li3Pv+Q+apMBmmPNzOBnZ7ZxWMB1Leq1Q==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.4.0", - "jest-serializer": "^27.4.0", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.5", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - } - }, - "jest-jasmine2": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.4.5.tgz", - "integrity": "sha512-oUnvwhJDj2LhOiUB1kdnJjkx8C5PwgUZQb9urF77mELH9DGR4e2GqpWQKBOYXWs5+uTN9BGDqRz3Aeg5Wts7aw==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.4.4", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.4.2", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.2", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-runtime": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2", - "throat": "^6.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + }, + "http-cache-semantics": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "http-proxy-agent": { + "version": "4.0.1", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "http-signature": { + "version": "1.2.0", + "bundled": true, "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "https-proxy-agent": { + "version": "5.0.0", + "bundled": true, "dev": true, "requires": { - "color-name": "~1.1.4" + "agent-base": "6", + "debug": "4" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "humanize-ms": { + "version": "1.2.1", + "bundled": true, "dev": true, "requires": { - "has-flag": "^4.0.0" + "ms": "^2.0.0" } - } - } - }, - "jest-leak-detector": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.4.2.tgz", - "integrity": "sha512-ml0KvFYZllzPBJWDei3mDzUhyp/M4ubKebX++fPaudpe8OsxUE+m+P6ciVLboQsrzOCWDjE20/eXew9QMx/VGw==", - "dev": true, - "requires": { - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" - } - }, - "jest-matcher-utils": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.4.2.tgz", - "integrity": "sha512-jyP28er3RRtMv+fmYC/PKG8wvAmfGcSNproVTW2Y0P/OY7/hWUOmsPfxN1jOhM+0u2xU984u2yEagGivz9OBGQ==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^27.4.2", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + }, + "iconv-lite": { + "version": "0.6.3", + "bundled": true, "dev": true, + "optional": true, "requires": { - "color-convert": "^2.0.1" + "safer-buffer": ">= 2.1.2 < 3.0.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "ignore-walk": { + "version": "3.0.4", + "bundled": true, "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "minimatch": "^3.0.4" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "imurmurhash": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, "dev": true, "requires": { - "color-name": "~1.1.4" + "once": "^1.3.0", + "wrappy": "1" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "inherits": { + "version": "2.0.4", + "bundled": true, "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "ini": { + "version": "2.0.0", + "bundled": true, "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "init-package-json": { + "version": "2.0.5", + "bundled": true, "dev": true, "requires": { - "has-flag": "^4.0.0" + "npm-package-arg": "^8.1.5", + "promzard": "^0.3.0", + "read": "~1.0.1", + "read-package-json": "^4.1.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^3.0.0" } - } - } - }, - "jest-message-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.2.tgz", - "integrity": "sha512-OMRqRNd9E0DkBLZpFtZkAGYOXl6ZpoMtQJWTAREJKDOFa0M6ptB7L67tp+cszMBkvSgKOhNtQp2Vbcz3ZZKo/w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.4.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.4", - "pretty-format": "^27.4.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "ansi-styles": { + }, + "ip": { + "version": "1.1.5", + "bundled": true, + "dev": true + }, + "ip-regex": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "bundled": true, + "dev": true + }, + "is-cidr": { + "version": "4.0.2", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "cidr-regex": "^3.1.1" + } + }, + "is-core-module": { + "version": "2.7.0", + "bundled": true, + "dev": true, + "requires": { + "has": "^1.0.3" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-lambda": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true, + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "bundled": true, + "dev": true }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } + "json-schema": { + "version": "0.2.3", + "bundled": true, + "dev": true }, - "color-name": { + "json-schema-traverse": { + "version": "0.4.1", + "bundled": true, + "dev": true + }, + "json-stringify-nice": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "bundled": true, "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true, "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "jsonparse": { + "version": "1.3.1", + "bundled": true, + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "bundled": true, "dev": true, "requires": { - "has-flag": "^4.0.0" + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" } - } - } - }, - "jest-mock": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.2.tgz", - "integrity": "sha512-PDDPuyhoukk20JrQKeofK12hqtSka7mWH0QQuxSNgrdiPsrnYYLS6wbzu/HDlxZRzji5ylLRULeuI/vmZZDrYA==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "@types/node": "*" - } - }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true - }, - "jest-regex-util": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.4.0.tgz", - "integrity": "sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg==", - "dev": true - }, - "jest-resolve": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.4.5.tgz", - "integrity": "sha512-xU3z1BuOz/hUhVUL+918KqUgK+skqOuUsAi7A+iwoUldK6/+PW+utK8l8cxIWT9AW7IAhGNXjSAh1UYmjULZZw==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + }, + "just-diff": { + "version": "3.1.1", + "bundled": true, + "dev": true + }, + "just-diff-apply": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "libnpmaccess": { + "version": "4.0.3", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "aproba": "^2.0.0", + "minipass": "^3.1.1", + "npm-package-arg": "^8.1.2", + "npm-registry-fetch": "^11.0.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "libnpmdiff": { + "version": "2.0.4", + "bundled": true, "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@npmcli/disparity-colors": "^1.0.1", + "@npmcli/installed-package-contents": "^1.0.7", + "binary-extensions": "^2.2.0", + "diff": "^5.0.0", + "minimatch": "^3.0.4", + "npm-package-arg": "^8.1.4", + "pacote": "^11.3.4", + "tar": "^6.1.0" } }, - "color-convert": { + "libnpmexec": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "bundled": true, "dev": true, "requires": { - "color-name": "~1.1.4" + "@npmcli/arborist": "^2.3.0", + "@npmcli/ci-detect": "^1.3.0", + "@npmcli/run-script": "^1.8.4", + "chalk": "^4.1.0", + "mkdirp-infer-owner": "^2.0.0", + "npm-package-arg": "^8.1.2", + "pacote": "^11.3.1", + "proc-log": "^1.0.0", + "read": "^1.0.7", + "read-package-json-fast": "^2.0.2", + "walk-up-path": "^1.0.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "libnpmfund": { + "version": "1.1.0", + "bundled": true, "dev": true, "requires": { - "has-flag": "^4.0.0" + "@npmcli/arborist": "^2.5.0" } - } - } - }, - "jest-resolve-dependencies": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.5.tgz", - "integrity": "sha512-elEVvkvRK51y037NshtEkEnukMBWvlPzZHiL847OrIljJ8yIsujD2GXRPqDXC4rEVKbcdsy7W0FxoZb4WmEs7w==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-snapshot": "^27.4.5" - } - }, - "jest-runner": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.4.5.tgz", - "integrity": "sha512-/irauncTfmY1WkTaRQGRWcyQLzK1g98GYG/8QvIPviHgO1Fqz1JYeEIsSfF+9mc/UTA6S+IIHFgKyvUrtiBIZg==", - "dev": true, - "requires": { - "@jest/console": "^27.4.2", - "@jest/environment": "^27.4.4", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-docblock": "^27.4.0", - "jest-environment-jsdom": "^27.4.4", - "jest-environment-node": "^27.4.4", - "jest-haste-map": "^27.4.5", - "jest-leak-detector": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-resolve": "^27.4.5", - "jest-runtime": "^27.4.5", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.5", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + }, + "libnpmhook": { + "version": "6.0.3", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "aproba": "^2.0.0", + "npm-registry-fetch": "^11.0.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "libnpmorg": { + "version": "2.0.3", + "bundled": true, "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "aproba": "^2.0.0", + "npm-registry-fetch": "^11.0.0" } }, - "color-convert": { + "libnpmpack": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "bundled": true, "dev": true, "requires": { - "color-name": "~1.1.4" + "@npmcli/run-script": "^1.8.3", + "npm-package-arg": "^8.1.0", + "pacote": "^11.2.6" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "libnpmpublish": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "normalize-package-data": "^3.0.2", + "npm-package-arg": "^8.1.2", + "npm-registry-fetch": "^11.0.0", + "semver": "^7.1.3", + "ssri": "^8.0.1" + } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "libnpmsearch": { + "version": "3.1.2", + "bundled": true, + "dev": true, + "requires": { + "npm-registry-fetch": "^11.0.0" + } }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "libnpmteam": { + "version": "2.0.4", + "bundled": true, "dev": true, "requires": { - "has-flag": "^4.0.0" + "aproba": "^2.0.0", + "npm-registry-fetch": "^11.0.0" } - } - } - }, - "jest-runtime": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.4.5.tgz", - "integrity": "sha512-CIYqwuJQXHQtPd/idgrx4zgJ6iCb6uBjQq1RSAGQrw2S8XifDmoM1Ot8NRd80ooAm+ZNdHVwsktIMGlA1F1FAQ==", - "dev": true, - "requires": { - "@jest/console": "^27.4.2", - "@jest/environment": "^27.4.4", - "@jest/globals": "^27.4.4", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", - "jest-message-util": "^27.4.2", - "jest-mock": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^16.2.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + }, + "libnpmversion": { + "version": "1.2.1", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "@npmcli/git": "^2.0.7", + "@npmcli/run-script": "^1.8.4", + "json-parse-even-better-errors": "^2.3.1", + "semver": "^7.3.5", + "stringify-package": "^1.0.1" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "lru-cache": { + "version": "6.0.0", + "bundled": true, "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "yallist": "^4.0.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "make-fetch-happen": { + "version": "9.1.0", + "bundled": true, "dev": true, "requires": { - "color-name": "~1.1.4" + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "mime-db": { + "version": "1.49.0", + "bundled": true, "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "mime-types": { + "version": "2.1.32", + "bundled": true, + "dev": true, + "requires": { + "mime-db": "1.49.0" + } }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "minimatch": { + "version": "3.0.4", + "bundled": true, "dev": true, "requires": { - "has-flag": "^4.0.0" + "brace-expansion": "^1.1.7" } - } - } - }, - "jest-serializer": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.4.0.tgz", - "integrity": "sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ==", - "dev": true, - "requires": { - "@types/node": "*", - "graceful-fs": "^4.2.4" - } - }, - "jest-snapshot": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.4.5.tgz", - "integrity": "sha512-eCi/iM1YJFrJWiT9de4+RpWWWBqsHiYxFG9V9o/n0WXs6GpW4lUt4FAHAgFPTLPqCUVzrMQmSmTZSgQzwqR7IQ==", - "dev": true, - "requires": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/parser": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.4.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^27.4.2", - "jest-get-type": "^27.4.0", - "jest-haste-map": "^27.4.5", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-resolve": "^27.4.5", - "jest-util": "^27.4.2", - "natural-compare": "^1.4.0", - "pretty-format": "^27.4.2", - "semver": "^7.3.2" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + }, + "minipass": { + "version": "3.1.5", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "yallist": "^4.0.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "minipass-collect": { + "version": "1.0.2", + "bundled": true, "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "minipass": "^3.0.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "minipass-fetch": { + "version": "1.4.1", + "bundled": true, "dev": true, "requires": { - "color-name": "~1.1.4" + "encoding": "^0.1.12", + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "minipass-flush": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.0.0" + } }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "minipass-json-stream": { + "version": "1.0.1", + "bundled": true, "dev": true, "requires": { - "lru-cache": "^6.0.0" + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" } }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "minipass-pipeline": { + "version": "1.2.4", + "bundled": true, "dev": true, "requires": { - "has-flag": "^4.0.0" + "minipass": "^3.0.0" } - } - } - }, - "jest-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz", - "integrity": "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.4", - "picomatch": "^2.2.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + }, + "minipass-sized": { + "version": "1.0.3", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "minipass": "^3.0.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "minizlib": { + "version": "2.1.2", + "bundled": true, "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "minipass": "^3.0.0", + "yallist": "^4.0.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "mkdirp": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "mkdirp-infer-owner": { + "version": "2.0.0", + "bundled": true, "dev": true, "requires": { - "color-name": "~1.1.4" + "chownr": "^2.0.0", + "infer-owner": "^1.0.4", + "mkdirp": "^1.0.3" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "ms": { + "version": "2.1.3", + "bundled": true, "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "mute-stream": { + "version": "0.0.8", + "bundled": true, "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "negotiator": { + "version": "0.6.2", + "bundled": true, + "dev": true + }, + "node-gyp": { + "version": "7.1.2", + "bundled": true, "dev": true, "requires": { - "has-flag": "^4.0.0" + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.3", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "request": "^2.88.2", + "rimraf": "^3.0.2", + "semver": "^7.3.2", + "tar": "^6.0.2", + "which": "^2.0.2" + }, + "dependencies": { + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } } - } - } - }, - "jest-validate": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.2.tgz", - "integrity": "sha512-hWYsSUej+Fs8ZhOm5vhWzwSLmVaPAxRy+Mr+z5MzeaHm9AxUpXdoVMEW4R86y5gOobVfBsMFLk4Rb+QkiEpx1A==", - "dev": true, - "requires": { - "@jest/types": "^27.4.2", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "leven": "^3.1.0", - "pretty-format": "^27.4.2" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + }, + "nopt": { + "version": "5.0.0", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "abbrev": "1" } }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "normalize-package-data": { + "version": "3.0.3", + "bundled": true, "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "npm-audit-report": { + "version": "2.1.5", + "bundled": true, "dev": true, "requires": { - "color-name": "~1.1.4" + "chalk": "^4.0.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "npm-bundled": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } }, - "has-flag": { + "npm-install-checks": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "bundled": true, + "dev": true, + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "bundled": true, "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "npm-package-arg": { + "version": "8.1.5", + "bundled": true, "dev": true, "requires": { - "has-flag": "^4.0.0" + "hosted-git-info": "^4.0.1", + "semver": "^7.3.4", + "validate-npm-package-name": "^3.0.0" } - } - } - }, - "jest-watcher": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.2.tgz", - "integrity": "sha512-NJvMVyyBeXfDezhWzUOCOYZrUmkSCiatpjpm+nFUid74OZEHk6aMLrZAukIiFDwdbqp6mTM6Ui1w4oc+8EobQg==", - "dev": true, - "requires": { - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.4.2", - "string-length": "^4.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + }, + "npm-packlist": { + "version": "2.2.2", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "glob": "^7.1.6", + "ignore-walk": "^3.0.3", + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "npm-pick-manifest": { + "version": "6.1.1", + "bundled": true, "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "npm-install-checks": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^8.1.2", + "semver": "^7.3.4" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "npm-profile": { + "version": "5.0.4", + "bundled": true, "dev": true, "requires": { - "color-name": "~1.1.4" + "npm-registry-fetch": "^11.0.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "npm-registry-fetch": { + "version": "11.0.0", + "bundled": true, + "dev": true, + "requires": { + "make-fetch-happen": "^9.0.1", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + } + }, + "npm-user-validate": { + "version": "1.0.1", + "bundled": true, "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "npmlog": { + "version": "5.0.1", + "bundled": true, + "dev": true, + "requires": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + }, + "dependencies": { + "are-we-there-yet": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + } + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, "dev": true }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "oauth-sign": { + "version": "0.9.0", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true + }, + "once": { + "version": "1.4.0", + "bundled": true, "dev": true, "requires": { - "has-flag": "^4.0.0" + "wrappy": "1" } - } - } - }, - "jest-worker": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", - "integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "has-flag": { + }, + "opener": { + "version": "1.5.2", + "bundled": true, + "dev": true + }, + "p-map": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "bundled": true, + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "pacote": { + "version": "11.3.5", + "bundled": true, + "dev": true, + "requires": { + "@npmcli/git": "^2.1.0", + "@npmcli/installed-package-contents": "^1.0.6", + "@npmcli/promise-spawn": "^1.2.0", + "@npmcli/run-script": "^1.8.2", + "cacache": "^15.0.5", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.3", + "mkdirp": "^1.0.3", + "npm-package-arg": "^8.0.1", + "npm-packlist": "^2.1.4", + "npm-pick-manifest": "^6.0.0", + "npm-registry-fetch": "^11.0.0", + "promise-retry": "^2.0.1", + "read-package-json-fast": "^2.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.0" + } + }, + "parse-conflict-json": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.0", + "just-diff": "^3.0.1", + "just-diff-apply": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "bundled": true, "dev": true }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "proc-log": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "promise-all-reject-late": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "promise-call-limit": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "promise-retry": { + "version": "2.0.1", + "bundled": true, "dev": true, "requires": { - "has-flag": "^4.0.0" + "err-code": "^2.0.2", + "retry": "^0.12.0" } - } - } - }, - "joi": { - "version": "17.5.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.5.0.tgz", - "integrity": "sha512-R7hR50COp7StzLnDi4ywOXHrBrgNXuUUfJWIR5lPY5Bm/pOD3jZaTwpluUXVLRWcoWZxkrHBBJ5hLxgnlehbdw==", - "dev": true, - "requires": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.0", - "@sideway/pinpoint": "^2.0.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "js2xmlparser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", - "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", - "dev": true, - "requires": { - "xmlcreate": "^2.0.4" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "jsdoc": { - "version": "3.6.7", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.7.tgz", - "integrity": "sha512-sxKt7h0vzCd+3Y81Ey2qinupL6DpRSZJclS04ugHDNmRUXGzqicMJ6iwayhSA0S0DwwX30c5ozyUthr1QKF6uw==", - "dev": true, - "requires": { - "@babel/parser": "^7.9.4", - "bluebird": "^3.7.2", - "catharsis": "^0.9.0", - "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.1", - "klaw": "^3.0.0", - "markdown-it": "^10.0.0", - "markdown-it-anchor": "^5.2.7", - "marked": "^2.0.3", - "mkdirp": "^1.0.4", - "requizzle": "^0.2.3", - "strip-json-comments": "^3.1.0", - "taffydb": "2.6.2", - "underscore": "~1.13.1" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true }, - "markdown-it": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", - "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "promzard": { + "version": "0.3.0", + "bundled": true, "dev": true, "requires": { - "argparse": "^1.0.7", - "entities": "~2.0.0", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" + "read": "1" } }, - "marked": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz", - "integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==", + "psl": { + "version": "1.8.0", + "bundled": true, "dev": true - } - } - }, - "jsdoc-api": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-7.1.0.tgz", - "integrity": "sha512-yjIiZa6LFOgd0dyFW/R+3unnVUhhbU1CeBhisgjBPRHkar83rkgDtTMRdgQotSvt+pGlmknZqfwR5AQuMh9/6w==", - "dev": true, - "requires": { - "array-back": "^6.2.0", - "cache-point": "^2.0.0", - "collect-all": "^1.0.4", - "file-set": "^4.0.2", - "fs-then-native": "^2.0.0", - "jsdoc": "^3.6.7", - "object-to-spawn-args": "^2.0.1", - "temp-path": "^1.0.0", - "walk-back": "^5.1.0" - } - }, - "jsdoc-parse": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-6.0.1.tgz", - "integrity": "sha512-ij3Az5y2dp+ajMxYnEJH7kjKK5v6+yZ3Cg/KtRdoT15pIm6qTk/W8q72QdNLZ9jQm/U2/ifENFXXTOe6xIxGeA==", - "dev": true, - "requires": { - "array-back": "^6.1.1", - "lodash.omit": "^4.5.0", - "lodash.pick": "^4.4.0", - "reduce-extract": "^1.0.0", - "sort-array": "^4.1.4", - "test-value": "^3.0.0" - } - }, - "jsdoc-to-markdown": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-7.1.0.tgz", - "integrity": "sha512-LJAiwrUaOpPqOmllqnVVqfBZh6KI/rHHfSwL7DerTpjLQWHfpndz/JUNlF5ngYjbL4aHNf7uJ1TuXl6xGfq5rg==", - "dev": true, - "requires": { - "array-back": "^6.2.0", - "command-line-tool": "^0.8.0", - "config-master": "^3.1.0", - "dmd": "^6.0.0", - "jsdoc-api": "^7.1.0", - "jsdoc-parse": "^6.0.1", - "walk-back": "^5.1.0" - } - }, - "jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "requires": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - } - }, - "jsen": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/jsen/-/jsen-0.6.6.tgz", - "integrity": "sha1-AkDBjPETUKwCFFb0in6xO9Z+BCA=", - "dev": true - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "jsforce": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/jsforce/-/jsforce-1.11.0.tgz", - "integrity": "sha512-vYNXJXXdz9ZQNdfRqq/MCJ/zU7JGA7iEduwafQDzChR9FeqXgTNfHTppLVbw9mIniKkQZemmxSOtl7N04lj/5Q==", - "dev": true, - "requires": { - "base64-url": "^2.2.0", - "co-prompt": "^1.0.0", - "coffeescript": "^1.10.0", - "commander": "^2.9.0", - "csv-parse": "^4.10.1", - "csv-stringify": "^1.0.4", - "faye": "^1.4.0", - "inherits": "^2.0.1", - "lodash": "^4.17.19", - "multistream": "^2.0.5", - "opn": "^5.3.0", - "promise": "^7.1.1", - "readable-stream": "^2.1.0", - "request": "^2.72.0", - "xml2js": "^0.4.16" - } - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsonwebtoken": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz", - "integrity": "sha512-IqEycp0znWHNA11TpYi77bVgyBO/pGESDh7Ajhas+u0ttkGkKYIIAjniL4Bw5+oVejVF+SYkaI7XKfwCCyeTuA==", - "dev": true, - "requires": { - "jws": "^3.2.1", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "dependencies": { + }, + "punycode": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "qrcode-terminal": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "qs": { + "version": "6.5.2", + "bundled": true, + "dev": true + }, + "read": { + "version": "1.0.7", + "bundled": true, + "dev": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "read-cmd-shim": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "read-package-json": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^3.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "read-package-json-fast": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "bundled": true, + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdir-scoped-modules": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "request": { + "version": "2.88.2", + "bundled": true, + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "bundled": true, + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "tough-cookie": { + "version": "2.5.0", + "bundled": true, + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + } + } + }, + "retry": { + "version": "0.12.0", + "bundled": true, + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.2.1", + "bundled": true, + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true + }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "7.3.5", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, "dev": true - } - } - }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dev": true, - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dev": true, - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, - "keypress": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.2.1.tgz", - "integrity": "sha1-HoBFQlABjbrUw/6USX1uZ7YmnHc=", - "dev": true - }, - "klaw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", - "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.9" - } - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "dev": true, - "requires": { - "readable-stream": "^2.0.5" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "lilconfig": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", - "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", - "dev": true - }, - "line-column": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/line-column/-/line-column-1.0.2.tgz", - "integrity": "sha1-0lryk2tvSEkXKzEuR5LR2Ye8NKI=", - "dev": true, - "requires": { - "isarray": "^1.0.0", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + }, + "signal-exit": { + "version": "3.0.3", + "bundled": true, + "dev": true + }, + "smart-buffer": { + "version": "4.2.0", + "bundled": true, + "dev": true + }, + "socks": { + "version": "2.6.1", + "bundled": true, "dev": true, "requires": { - "isarray": "1.0.0" + "ip": "^1.1.5", + "smart-buffer": "^4.1.0" } - } - } - }, - "linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", - "dev": true, - "requires": { - "uc.micro": "^1.0.1" - } - }, - "lint-staged": { - "version": "12.2.1", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.2.1.tgz", - "integrity": "sha512-VCVcA9C2Vt5HHxSR4EZVZFJcQRJH984CGBeY+cJ/xed4mBd+JidbM/xbKcCq5ASaygAV0iITtdsCTnID7h/1OQ==", - "dev": true, - "requires": { - "cli-truncate": "^3.1.0", - "colorette": "^2.0.16", - "commander": "^8.3.0", - "debug": "^4.3.3", - "execa": "^5.1.1", - "lilconfig": "2.0.4", - "listr2": "^3.13.5", - "micromatch": "^4.0.4", - "normalize-path": "^3.0.0", - "object-inspect": "^1.11.1", - "string-argv": "^0.3.1", - "supports-color": "^9.2.1", - "yaml": "^1.10.2" - }, - "dependencies": { - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + }, + "socks-proxy-agent": { + "version": "6.1.0", + "bundled": true, + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.1", + "socks": "^2.6.1" + } + }, + "spdx-correct": { + "version": "3.1.1", + "bundled": true, + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "bundled": true, "dev": true }, - "supports-color": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.1.tgz", - "integrity": "sha512-Obv7ycoCTG51N7y175StI9BlAXrmgZrFhZOb0/PyjHBher/NmsdBgbbQ1Inhq+gIhz6+7Gb+jWF2Vqi7Mf1xnQ==", + "spdx-expression-parse": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.10", + "bundled": true, "dev": true - } - } - }, - "listr2": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", - "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", - "dev": true, - "requires": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.5.1", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + }, + "sshpk": { + "version": "1.16.1", + "bundled": true, + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "8.0.1", + "bundled": true, + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.3.0", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "safe-buffer": "~5.2.0" } }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "stringify-package": { + "version": "1.0.1", + "bundled": true, "dev": true }, - "cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "strip-ansi": { + "version": "3.0.1", + "bundled": true, "dev": true, "requires": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" + "ansi-regex": "^2.0.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "supports-color": { + "version": "7.2.0", + "bundled": true, "dev": true, "requires": { - "color-name": "~1.1.4" + "has-flag": "^4.0.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "rxjs": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.2.tgz", - "integrity": "sha512-PwDt186XaL3QN5qXj/H9DGyHhP3/RYYgZZwqBv9Tv8rsAaiwFH1IsJJlcgD37J7UW5a6O67qX0KWKS3/pu0m4w==", + "tar": { + "version": "6.1.11", + "bundled": true, "dev": true, "requires": { - "tslib": "^2.1.0" + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" } }, - "slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "text-table": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "tiny-relative-date": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "treeverse": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "bundled": true, "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "safe-buffer": "^5.0.1" } - } - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, "dev": true - } - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - }, - "lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", - "dev": true - }, - "lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", - "dev": true - }, - "lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", - "dev": true - }, - "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", - "dev": true - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", - "dev": true - }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=", - "dev": true - }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=", - "dev": true - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=", - "dev": true - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=", - "dev": true - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", - "dev": true - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", - "dev": true - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lodash.omit": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", - "integrity": "sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA=", - "dev": true - }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", - "dev": true - }, - "lodash.padend": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz", - "integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=", - "dev": true - }, - "lodash.pick": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", - "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=", - "dev": true - }, - "lodash.set": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", - "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=", - "dev": true - }, - "lodash.template": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", - "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0" - } - }, - "lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=", - "dev": true - }, - "log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", - "dev": true, - "requires": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "bundled": true, + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "unique-filename": { + "version": "1.1.1", + "bundled": true, "dev": true, "requires": { - "color-convert": "^2.0.1" + "unique-slug": "^2.0.0" } }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true + "unique-slug": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "uri-js": { + "version": "4.4.1", + "bundled": true, "dev": true, "requires": { - "color-name": "~1.1.4" + "punycode": "^2.1.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "util-deprecate": { + "version": "1.0.2", + "bundled": true, "dev": true }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "uuid": { + "version": "3.4.0", + "bundled": true, + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "bundled": true, "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "validate-npm-package-name": { + "version": "3.0.0", + "bundled": true, "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "builtins": "^1.0.3" } - } - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "requires": { - "tmpl": "1.0.5" - } - }, - "markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "requires": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==" }, - "linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "verror": { + "version": "1.10.0", + "bundled": true, + "dev": true, "requires": { - "uc.micro": "^1.0.1" + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" } - } - } - }, - "markdown-it-anchor": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", - "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", - "dev": true - }, - "marked": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.10.tgz", - "integrity": "sha512-+QvuFj0nGgO970fySghXGmuw+Fd0gD2x3+MqCWLIPf5oxdv1Ka6b2q+z9RP01P/IaKPMEramy+7cNy/Lw8c3hw==" - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "dev": true - }, - "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "dev": true, - "requires": { - "mime-db": "1.51.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - }, - "dependencies": { - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + }, + "walk-up-path": { + "version": "1.0.0", + "bundled": true, "dev": true - } - } - }, - "minizlib": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", - "dev": true, - "requires": { - "minipass": "^2.9.0" - } - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "mkdirp2": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/mkdirp2/-/mkdirp2-1.0.5.tgz", - "integrity": "sha512-xOE9xbICroUDmG1ye2h4bZ8WBie9EGmACaco8K8cx6RlkJJrxGIqjGqztAI+NMhexXBcdGbSEzI6N3EJPevxZw==", - "dev": true - }, - "mock-stdin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mock-stdin/-/mock-stdin-1.0.0.tgz", - "integrity": "sha512-tukRdb9Beu27t6dN+XztSRHq9J0B/CoAOySGzHfn8UTfmqipA5yNT/sDUEyYdAV3Hpka6Wx6kOMxuObdOex60Q==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "multistream": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/multistream/-/multistream-2.1.1.tgz", - "integrity": "sha512-xasv76hl6nr1dEy3lPvy7Ej7K/Lx3O/FCvwge8PeVJpciPPoNCbaANcNiBug3IpdvTveZUcAV0DJzdnUDMesNQ==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.5" - } - }, - "mustache": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", - "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "mv": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", - "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", - "dev": true, - "optional": true, - "requires": { - "mkdirp": "~0.5.1", - "ncp": "~2.0.0", - "rimraf": "~2.4.0" - }, - "dependencies": { - "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + }, + "wcwidth": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "which": { + "version": "2.0.2", + "bundled": true, "dev": true, - "optional": true, "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "isexe": "^2.0.0" } }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "wide-align": { + "version": "1.1.3", + "bundled": true, "dev": true, - "optional": true, "requires": { - "minimist": "^1.2.5" + "string-width": "^1.0.2 || 2" } }, - "rimraf": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", - "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "bundled": true, "dev": true, - "optional": true, "requires": { - "glob": "^6.0.1" + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } + }, + "yallist": { + "version": "4.0.0", + "bundled": true, + "dev": true } } }, - "nan": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", - "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", - "dev": true, - "optional": true - }, - "nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==" - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "ncp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", - "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", - "dev": true, - "optional": true - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "nock": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/nock/-/nock-13.2.1.tgz", - "integrity": "sha512-CoHAabbqq/xZEknubuyQMjq6Lfi5b7RtK6SoNK6m40lebGp3yiMagWtIoYaw2s9sISD7wPuCfwFpivVHX/35RA==", - "dev": true, - "requires": { - "debug": "^4.1.0", - "json-stringify-safe": "^5.0.1", - "lodash.set": "^4.3.2", - "propagate": "^2.0.0" - } - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node-releases": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", - "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==", - "dev": true - }, - "node-stream-zip": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.13.2.tgz", - "integrity": "sha512-159NUO3quDIRVSVOQiQ/0VG8NFrGvVyUa+MUUleiOys3NLtrGtNkodqYYTRHU/kiXu/ygHZcNy/tZ4NUCcDUmQ==", - "dev": true - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "npm-api": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-api/-/npm-api-1.0.1.tgz", + "integrity": "sha512-4sITrrzEbPcr0aNV28QyOmgn6C9yKiF8k92jn4buYAK8wmA5xo1qL3II5/gT1r7wxbXBflSduZ2K3FbtOrtGkA==", "dev": true, "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } + "JSONStream": "^1.3.5", + "clone-deep": "^4.0.1", + "download-stats": "^0.3.4", + "moment": "^2.24.0", + "node-fetch": "^2.6.0", + "paged-request": "^2.0.1" } }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, "npm-normalize-package-bin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", @@ -8367,8 +17592,22 @@ "dev": true, "requires": { "path-key": "^3.0.0" + }, + "dependencies": { + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + } } }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, "nwsapi": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", @@ -8381,6 +17620,43 @@ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "object-get": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/object-get/-/object-get-2.1.1.tgz", @@ -8405,6 +17681,29 @@ "integrity": "sha512-6FuKFQ39cOID+BMZ3QaphcC8Y4cw6LXBLyIgPU+OhIYwviJamPAn+4mITapnSBQrejB+NNp+FMskhD8Cq+Ys3w==", "dev": true }, + "object-treeify": { + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz", + "integrity": "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, "object.assign": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", @@ -8417,6 +17716,23 @@ "object-keys": "^1.1.1" } }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, "object.values": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", @@ -8445,6 +17761,16 @@ "mimic-fn": "^2.1.0" } }, + "open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "requires": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + } + }, "opn": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", @@ -8462,6 +17788,12 @@ } } }, + "optional-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/optional-js/-/optional-js-1.3.1.tgz", + "integrity": "sha1-HW8knW2kaC5ps1u49bOrLhy12Wo=", + "dev": true + }, "optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -8482,6 +17814,24 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", + "dev": true + }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -8509,12 +17859,80 @@ "aggregate-error": "^3.0.0" } }, + "p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "pac-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", + "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4", + "get-uri": "3", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "5", + "pac-resolver": "^5.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "5" + } + }, + "pac-resolver": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.0.tgz", + "integrity": "sha512-H+/A6KitiHNNW+bxBKREk2MCGSxljfqRX76NjummWEYIat7ldVXRU3dhRIE3iXZ0nvGBk6smv3nntxKkzRL8NA==", + "dev": true, + "requires": { + "degenerator": "^3.0.1", + "ip": "^1.1.5", + "netmask": "^2.0.1" + } + }, + "pad-component": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pad-component/-/pad-component-0.0.1.tgz", + "integrity": "sha1-rR8izhvw/cDW3dkIrxfzUaQEuKw=", + "dev": true + }, + "paged-request": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/paged-request/-/paged-request-2.0.2.tgz", + "integrity": "sha512-NWrGqneZImDdcMU/7vMcAOo1bIi5h/pmpJqe7/jdsy85BA/s5MSaU/KlpxwW/IVPmIwBcq2uKPrBWWhEWhtxag==", + "dev": true, + "requires": { + "axios": "^0.21.1" + } + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -8525,12 +17943,15 @@ } }, "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { - "error-ex": "^1.2.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" } }, "parse5": { @@ -8546,75 +17967,58 @@ "dev": true, "requires": { "@types/node": "^6.0.46" - } - }, - "password-prompt": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.2.tgz", - "integrity": "sha512-bpuBhROdrhuN3E7G/koAju0WjVw9/uQOG5Co5mokNj0MiOSBVZS1JTwM4zl55hu0WFmIEFvO9cU9sJQiBIYeIA==", - "dev": true, - "requires": { - "ansi-escapes": "^3.1.0", - "cross-spawn": "^6.0.5" }, "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "@types/node": { + "version": "6.14.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.14.13.tgz", + "integrity": "sha512-J1F0XJ/9zxlZel5ZlbeSuHW2OpabrUAqpFuC2sm2I3by8sERQ8+KCjNKUcq8QHuzpGMWiJpo9ZxeHrqrP2KzQw==", "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } } } }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "password-prompt": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.2.tgz", + "integrity": "sha512-bpuBhROdrhuN3E7G/koAju0WjVw9/uQOG5Co5mokNj0MiOSBVZS1JTwM4zl55hu0WFmIEFvO9cU9sJQiBIYeIA==", + "dev": true, + "requires": { + "ansi-escapes": "^3.1.0", + "cross-spawn": "^6.0.5" + } + }, + "path-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz", + "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==", + "dev": true, + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -8627,9 +18031,9 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, "path-parse": { @@ -8656,9 +18060,15 @@ "dev": true }, "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pidtree": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.5.0.tgz", + "integrity": "sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA==", "dev": true }, "pify": { @@ -8668,9 +18078,9 @@ "dev": true }, "pirates": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", - "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true }, "pkg-dir": { @@ -8721,6 +18131,12 @@ } } }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, "postcss": { "version": "8.3.11", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.11.tgz", @@ -8733,9 +18149,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.8", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz", - "integrity": "sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==", + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", "dev": true, "requires": { "cssesc": "^3.0.0", @@ -8754,10 +18170,16 @@ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, "prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", "dev": true }, "prettier-plugin-apex": { @@ -8773,9 +18195,9 @@ }, "dependencies": { "yargs": { - "version": "17.3.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz", - "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==", + "version": "17.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.1.tgz", + "integrity": "sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==", "dev": true, "requires": { "cliui": "^7.0.2", @@ -8788,20 +18210,25 @@ } }, "yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==", + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", "dev": true } } }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true + }, "pretty-format": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.2.tgz", - "integrity": "sha512-p0wNtJ9oLuvgOQDEIZ9zQjZffK7KtyR6Si0jnXULIDwrlNF8Cuir3AZP0hHv0jmKuNN/edOnbMjnzd4uTcmWiw==", + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "requires": { - "@jest/types": "^27.4.2", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" @@ -8815,12 +18242,6 @@ } } }, - "printj": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.3.1.tgz", - "integrity": "sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg==", - "dev": true - }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -8858,12 +18279,55 @@ "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", "dev": true }, + "proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz", + "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==", + "dev": true, + "requires": { + "agent-base": "^6.0.0", + "debug": "4", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "lru-cache": "^5.1.1", + "pac-proxy-agent": "^5.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^5.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + } + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", "dev": true }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -8880,23 +18344,90 @@ } }, "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + } + } + }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "read-chunk": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-3.2.0.tgz", + "integrity": "sha512-CEjy9LCzhmD7nUpJ1oVOE6s/hBkejlcJEgLQHVnQznOSilOPb+kpKktlLfFDK3/WP43+F80xkUTM2VOkYoSYvQ==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "with-open-file": "^0.1.6" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, "read-installed": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", @@ -9016,18 +18547,14 @@ } }, "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, "readdir-glob": { @@ -9095,67 +18622,238 @@ "array-back": "^1.0.2", "typical": "^2.4.2" } - } - } - }, - "reduce-flatten": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-1.0.1.tgz", - "integrity": "sha1-JYx479FT3fk8tWEjf2EYTzaW4yc=", - "dev": true - }, - "reduce-unique": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/reduce-unique/-/reduce-unique-2.0.1.tgz", - "integrity": "sha512-x4jH/8L1eyZGR785WY+ePtyMNhycl1N2XOLxhCbzZFaqF4AXjLzqSxa2UHgJ2ZVR/HHyPOvl1L7xRnW8ye5MdA==", - "dev": true - }, - "reduce-without": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/reduce-without/-/reduce-without-1.0.1.tgz", - "integrity": "sha1-aK0OrRGFXJo31OglbBW7+Hly/Iw=", - "dev": true, - "requires": { - "test-value": "^2.0.0" - }, - "dependencies": { - "array-back": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", - "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", + } + } + }, + "reduce-flatten": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-1.0.1.tgz", + "integrity": "sha1-JYx479FT3fk8tWEjf2EYTzaW4yc=", + "dev": true + }, + "reduce-unique": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/reduce-unique/-/reduce-unique-2.0.1.tgz", + "integrity": "sha512-x4jH/8L1eyZGR785WY+ePtyMNhycl1N2XOLxhCbzZFaqF4AXjLzqSxa2UHgJ2ZVR/HHyPOvl1L7xRnW8ye5MdA==", + "dev": true + }, + "reduce-without": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/reduce-without/-/reduce-without-1.0.1.tgz", + "integrity": "sha1-aK0OrRGFXJo31OglbBW7+Hly/Iw=", + "dev": true, + "requires": { + "test-value": "^2.0.0" + }, + "dependencies": { + "array-back": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz", + "integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=", + "dev": true, + "requires": { + "typical": "^2.6.0" + } + }, + "test-value": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz", + "integrity": "sha1-Edpv9nDzRxpztiXKTz/c97t0gpE=", + "dev": true, + "requires": { + "array-back": "^1.0.3", + "typical": "^2.6.0" + } + } + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexp-to-ast": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", + "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", + "dev": true + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "replace": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/replace/-/replace-1.2.1.tgz", + "integrity": "sha512-KZCBe/tPanwBlbjSMQby4l+zjSiFi3CLEP/6VLClnRYgJ46DZ5u9tmA6ceWeFS8coaUnU4ZdGNb/puUGMHNSRg==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "minimatch": "3.0.4", + "yargs": "^15.3.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, "requires": { - "typical": "^2.6.0" + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" } }, - "test-value": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz", - "integrity": "sha1-Edpv9nDzRxpztiXKTz/c97t0gpE=", + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, "requires": { - "array-back": "^1.0.3", - "typical": "^2.6.0" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" } } } }, - "reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", - "dev": true - }, - "regexp-to-ast": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", - "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", - "dev": true - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "replace-ext": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", + "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", "dev": true }, "request": { @@ -9186,17 +18884,6 @@ "uuid": "^3.3.2" }, "dependencies": { - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, "tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", @@ -9215,6 +18902,12 @@ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, "requizzle": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", @@ -9233,6 +18926,12 @@ "path-parse": "^1.0.6" } }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, "resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", @@ -9248,12 +18947,35 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, "resolve.exports": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", "dev": true }, + "responselike": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", + "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", + "dev": true, + "requires": { + "lowercase-keys": "^2.0.0" + }, + "dependencies": { + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, "restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -9264,6 +18986,12 @@ "signal-exit": "^3.0.2" } }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, "retire": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/retire/-/retire-2.2.5.tgz", @@ -9298,12 +19026,27 @@ "dev": true }, "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", + "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", "dev": true, "requires": { - "glob": "^7.1.3" + "glob": "^6.0.1" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } } }, "run-async": { @@ -9338,25 +19081,334 @@ } } }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "safe-json-stringify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", - "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safe-json-stringify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", + "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", + "dev": true, + "optional": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "salesforce-alm": { + "version": "54.1.0", + "resolved": "https://registry.npmjs.org/salesforce-alm/-/salesforce-alm-54.1.0.tgz", + "integrity": "sha512-orQcWk/TgQjrvHlzsFk2Pbm8fnh45eg765Q8tU1SvqAKZzyoLMkwwtOoP37wEEl7M6t3NyvvuFTnG6GvvOZflQ==", + "dev": true, + "requires": { + "@oclif/config": "^1.18.1", + "@oclif/errors": "^1.3.5", + "@salesforce/command": "^4.2.2", + "@salesforce/core": "^2.35.0", + "@salesforce/kit": "^1.5.13", + "@salesforce/source-deploy-retrieve": "^5.9.4", + "@salesforce/source-tracking": "^1.1.1", + "@salesforce/ts-types": "^1.5.17", + "adm-zip": "^0.5.9", + "ansi-styles": "^3.2.1", + "archiver": "^5.3.0", + "bluebird": "^3.5.5", + "bunyan-sfdx-no-dtrace": "^1.8.2", + "chalk": "^2.4.2", + "cli-ux": "^5.4.4", + "debug": "^3.2.6", + "fast-xml-parser": "^3.17.4", + "fs-extra": "^4.0.3", + "glob": "^7.1.6", + "heroku-cli-util": "^8.0.12", + "js2xmlparser": "^3.0.0", + "jsforce": "^1.11.0", + "klaw": "^2.1.1", + "lodash": "^4.17.21", + "mime": "^1.6.0", + "mkdirp": "^0.5.1", + "moment": "^2.24.0", + "optional-js": "^1.3.1", + "replace": "^1.2.1", + "request": "^2.88.0", + "strip-ansi": "^5.2.0", + "ts-retry-promise": "^0.6.0", + "xml2js": "0.4.19", + "xmldom-sfdx-encoding": "^0.1.30" + }, + "dependencies": { + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "bunyan-sfdx-no-dtrace": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/bunyan-sfdx-no-dtrace/-/bunyan-sfdx-no-dtrace-1.8.2.tgz", + "integrity": "sha1-EGgt4H/sF+0UUosWaZWx8Yu9T5o=", + "dev": true, + "requires": { + "dtrace-provider": "~0.6", + "moment": "^2.10.6", + "mv": "~2", + "safe-json-stringify": "~1" + } + }, + "cli-ux": { + "version": "5.6.7", + "resolved": "https://registry.npmjs.org/cli-ux/-/cli-ux-5.6.7.tgz", + "integrity": "sha512-dsKAurMNyFDnO6X1TiiRNiVbL90XReLKcvIq4H777NMqXGBxBws23ag8ubCJE97vVZEgWG2eSUhsyLf63Jv8+g==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.15", + "@oclif/errors": "^1.3.5", + "@oclif/linewrap": "^1.0.0", + "@oclif/screen": "^1.0.4", + "ansi-escapes": "^4.3.0", + "ansi-styles": "^4.2.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.0", + "clean-stack": "^3.0.0", + "cli-progress": "^3.4.0", + "extract-stack": "^2.0.0", + "fs-extra": "^8.1", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.13.1", + "lodash": "^4.17.21", + "natural-orderby": "^2.0.1", + "object-treeify": "^1.1.4", + "password-prompt": "^1.1.2", + "semver": "^7.3.2", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "supports-color": "^8.1.0", + "supports-hyperlinks": "^2.1.0", + "tslib": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "extract-stack": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extract-stack/-/extract-stack-2.0.0.tgz", + "integrity": "sha512-AEo4zm+TenK7zQorGK1f9mJ8L14hnTDi2ZQPR+Mub1NX8zimka1mXpV5LpH8x9HoUmFSHZCfLHqWvp0Y4FxxzQ==", + "dev": true + }, + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "js2xmlparser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", + "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=", + "dev": true, + "requires": { + "xmlcreate": "^1.0.1" + } + }, + "klaw": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.1.1.tgz", + "integrity": "sha1-QrdolHARacyRD9DRnOZ3tfs3ivE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.9" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + } + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true + }, + "xmlcreate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz", + "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=", + "dev": true + } + } + }, "sanitize-filename-ts": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/sanitize-filename-ts/-/sanitize-filename-ts-1.0.2.tgz", @@ -9381,31 +19433,266 @@ "xmlchars": "^2.2.0" } }, + "scoped-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/scoped-regex/-/scoped-regex-1.0.0.tgz", + "integrity": "sha1-o0a7Gs1CB65wvXwMfKnlZra63bg=", + "dev": true + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true + }, + "sentence-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz", + "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, "sequin": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/sequin/-/sequin-0.1.1.tgz", "integrity": "sha1-XC04nWajg3NOqvvEXt6ywcsb5wE=", "dev": true }, - "shebang-command": { + "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-getter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.1.tgz", + "integrity": "sha512-9sVWOy+gthr+0G9DzqqLaYNA7+5OKkSmcqjL9cBpDEaZrr3ShQlyX2cZ/O/ozE41oxn/Tt0LGEM/w4Rub3A3gw==", + "dev": true, + "requires": { + "to-object-path": "^0.3.0" + } + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "sfdx-cli": { + "version": "7.145.0", + "resolved": "https://registry.npmjs.org/sfdx-cli/-/sfdx-cli-7.145.0.tgz", + "integrity": "sha512-PCjxcBwNzsdLhrboayaK3zO2M/3JGft7sj7HoXdAFhWDDAs/LrQmKjNgss6/OrhkermPc+l9G+qgl24fDD/gcw==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.0", + "@oclif/config": "^1.17.0", + "@oclif/errors": "^1.3.4", + "@oclif/plugin-autocomplete": "^0.3.0", + "@oclif/plugin-commands": "^1.3.0", + "@oclif/plugin-help": "^3.2.2", + "@oclif/plugin-not-found": "^1.2.4", + "@oclif/plugin-plugins": "^1.10.1", + "@oclif/plugin-update": "1.5.0", + "@oclif/plugin-warn-if-update-available": "^1.7.0", + "@oclif/plugin-which": "^1.0.3", + "@salesforce/kit": "^1.5.13", + "@salesforce/lazy-require": "^0.4.0", + "@salesforce/plugin-alias": "2.0.0", + "@salesforce/plugin-apex": "0.11.0", + "@salesforce/plugin-auth": "1.8.2", + "@salesforce/plugin-community": "1.1.4", + "@salesforce/plugin-config": "1.3.24", + "@salesforce/plugin-custom-metadata": "1.0.12", + "@salesforce/plugin-data": "0.6.12", + "@salesforce/plugin-generator": "1.2.2", + "@salesforce/plugin-info": "1.3.1", + "@salesforce/plugin-limits": "1.3.0", + "@salesforce/plugin-org": "1.11.2", + "@salesforce/plugin-schema": "1.1.0", + "@salesforce/plugin-source": "1.9.2", + "@salesforce/plugin-telemetry": "1.4.0", + "@salesforce/plugin-templates": "54.3.0", + "@salesforce/plugin-trust": "^1.0.8", + "@salesforce/plugin-user": "1.7.1", + "@salesforce/require-analytics": "^0.9.16", + "@salesforce/sfdx-plugin-lwc-test": "0.1.7", + "@salesforce/ts-types": "^1.5.17", + "debug": "^4.3.1", + "salesforce-alm": "54.1.0", + "shelljs": "^0.8.4", + "tslib": "^2.1.0", + "v8-compile-cache": "^2.2.0" + }, + "dependencies": { + "@oclif/plugin-help": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-3.3.1.tgz", + "integrity": "sha512-QuSiseNRJygaqAdABYFWn/H1CwIZCp9zp/PLid6yXvy6VcQV7OenEFF5XuYaCvSARe2Tg9r8Jqls5+fw1A9CbQ==", + "dev": true, + "requires": { + "@oclif/command": "^1.8.15", + "@oclif/config": "1.18.2", + "@oclif/errors": "1.3.5", + "@oclif/help": "^1.0.1", + "chalk": "^4.1.2", + "indent-string": "^4.0.0", + "lodash": "^4.17.21", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "widest-line": "^3.1.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "@oclif/config": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.2.tgz", + "integrity": "sha512-cE3qfHWv8hGRCP31j7fIS7BfCflm/BNZ2HNqHexH+fDrdF2f1D5S8VmXWLC77ffv3oDvWyvE9AZeR0RfmHCCaA==", + "dev": true, + "requires": { + "@oclif/errors": "^1.3.3", + "@oclif/parser": "^3.8.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-wsl": "^2.1.1", + "tslib": "^2.0.0" + } + } + } + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "shebang-regex": "^3.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, "shelljs": { @@ -9418,14 +19705,20 @@ "rechoir": "^0.6.2" } }, + "shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==", + "dev": true + }, "shx": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.3.tgz", - "integrity": "sha512-nZJ3HFWVoTSyyB+evEKjJ1STiixGztlqwKLTUNV5KqMWtGey9fTd4KU1gdZ1X9BV6215pswQ/Jew9NsuS/fNDA==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", + "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", "dev": true, "requires": { "minimist": "^1.2.3", - "shelljs": "^0.8.4" + "shelljs": "^0.8.5" } }, "side-channel": { @@ -9440,9 +19733,9 @@ } }, "signal-exit": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", - "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, "simple-concat": { @@ -9497,10 +19790,175 @@ "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", "dev": true }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, + "snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dev": true, + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz", + "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "4", + "socks": "^2.3.3" + } + }, "sort-array": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-4.1.4.tgz", - "integrity": "sha512-GVFN6Y1sHKrWaSYOJTk9093ZnrBMc9sP3nuhANU44S4xg3rE6W5Z5WyamuT8VpMBbssnetx5faKCua0LEmUnSw==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-4.1.5.tgz", + "integrity": "sha512-Ya4peoS1fgFN42RN1REk2FgdNOeLIEMKFGJvs7VTP3OklF8+kl2SkpVliZ4tk/PurWsrWRsdNdU+tgyOBkB9sA==", "dev": true, "requires": { "array-back": "^5.0.0", @@ -9521,6 +19979,24 @@ } } }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "sort-pjson": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sort-pjson/-/sort-pjson-1.0.3.tgz", + "integrity": "sha512-h/xRX+8zuV9tbnbkRwmdNNyyJbjzVTh8YFpMgEgGU2umFDFg2EDfWKtA5YOfnBwT4YoZfJf6hrc0yuXLUvUDFA==", + "dev": true, + "requires": { + "@oclif/fixpack": "^2.3.0" + } + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -9533,6 +20009,19 @@ "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", "dev": true }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, "source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -9551,6 +20040,18 @@ } } }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "dev": true + }, + "spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=", + "dev": true + }, "spdx-correct": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -9583,6 +20084,15 @@ "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", "dev": true }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -9590,9 +20100,9 @@ "dev": true }, "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", "dev": true, "requires": { "asn1": "~0.2.3", @@ -9606,6 +20116,12 @@ "tweetnacl": "~0.14.0" } }, + "stack-chain": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-1.3.7.tgz", + "integrity": "sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU=", + "dev": true + }, "stack-utils": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", @@ -9623,6 +20139,33 @@ } } }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + }, "stdout-stderr": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/stdout-stderr/-/stdout-stderr-0.1.13.tgz", @@ -9659,6 +20202,12 @@ "integrity": "sha512-DBp0lSvX5G9KGRDTkR/R+a29H+Wk2xItOF+MpZLLNDWbEV9tGPnqLPxHEYjmiz8xGtJHRIqmI+hCjmNzqoA4nQ==", "dev": true }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, "string-argv": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", @@ -9675,6 +20224,12 @@ "strip-ansi": "^6.0.0" } }, + "string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", + "dev": true + }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -9713,6 +20268,14 @@ "dev": true, "requires": { "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } } }, "strip-ansi": { @@ -9730,6 +20293,42 @@ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true }, + "strip-bom-buf": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz", + "integrity": "sha1-HLRar1dTD0yvhsf3UXnSyaUd1XI=", + "dev": true, + "requires": { + "is-utf8": "^0.2.1" + } + }, + "strip-bom-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz", + "integrity": "sha1-+H217yYT9paKpUWr/h7HKLaoKco=", + "dev": true, + "requires": { + "first-chunk-stream": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + } + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, "strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -9742,6 +20341,12 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "dev": true + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -9752,32 +20357,29 @@ } }, "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz", + "integrity": "sha512-HHi5kVSefKaJkGYXbDuKbUGRVxqnWGn3J2e39CYcNJEfWciGq2zYtOhXLTlvrOZW1QU7VX67w7fMmWafHX9Pfw==", "dev": true, "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" + "has-flag": "^2.0.0", + "supports-color": "^5.0.0" }, "dependencies": { "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -9797,9 +20399,9 @@ }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true }, "emoji-regex": { @@ -9866,6 +20468,16 @@ "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=", "dev": true }, + "taketalk": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/taketalk/-/taketalk-1.0.0.tgz", + "integrity": "sha1-tNTw3u0gauffd1sSnqLKbeUvJt0=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1", + "minimist": "^1.1.0" + } + }, "tar": { "version": "4.4.19", "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", @@ -9879,29 +20491,18 @@ "mkdirp": "^0.5.5", "safe-buffer": "^5.2.1", "yallist": "^3.1.1" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - } + } + }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" } }, "tar-stream": { @@ -9915,19 +20516,6 @@ "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } } }, "temp-path": { @@ -9944,6 +20532,42 @@ "requires": { "ansi-escapes": "^4.2.1", "supports-hyperlinks": "^2.0.0" + }, + "dependencies": { + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + } } }, "test-exclude": { @@ -9984,6 +20608,12 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "textextensions": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.6.0.tgz", + "integrity": "sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ==", + "dev": true + }, "throat": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", @@ -9996,6 +20626,22 @@ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, + "through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -10017,6 +20663,38 @@ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -10026,6 +20704,12 @@ "is-number": "^7.0.0" } }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, "tough-cookie": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", @@ -10046,6 +20730,18 @@ "punycode": "^2.1.1" } }, + "traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", + "dev": true + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, "treeify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", @@ -10075,20 +20771,20 @@ } }, "ts-retry-promise": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/ts-retry-promise/-/ts-retry-promise-0.6.0.tgz", - "integrity": "sha512-8DF80uA7JPu6m8ouHxGkyBpPTIGQnsgIUgLDqcRaD7EEhVowjG72KqCX334gsa1P+AmzeTVdd/xEzVFCAuPCtg==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/ts-retry-promise/-/ts-retry-promise-0.6.1.tgz", + "integrity": "sha512-6L9PAWahkRtZ4mG48wz3Mxk7LfW1eZKEPsCteIa5fbDE1G2kFk4ThHXbynKlIZLg0RdenDBDw6CLME5liOrBSQ==", "dev": true }, "tsconfig-paths": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", - "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dev": true, "requires": { "@types/json5": "^0.0.29", "json5": "^1.0.1", - "minimist": "^1.2.0", + "minimist": "^1.2.6", "strip-bom": "^3.0.0" }, "dependencies": { @@ -10212,9 +20908,9 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, "uglify-js": { - "version": "3.14.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.5.tgz", - "integrity": "sha512-qZukoSxOG0urUTvjc2ERMTcAy+BiFh3weWAkeurLwjrCba73poHmG3E36XEjd/JGukMzwTL7uCxZiAexj8ppvQ==", + "version": "3.15.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.4.tgz", + "integrity": "sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA==", "dev": true, "optional": true }, @@ -10236,18 +20932,153 @@ "integrity": "sha512-ekY1NhRzq0B08g4bGuX4wd2jZx5GnKz6mKSqFL4nqBlfyMGiG10gDFhDTMEfYmDL6Jy0FUIZp7wiRB+0BP7J2g==", "dev": true }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, "untildify": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", "dev": true }, + "unzip-response": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", + "dev": true + }, + "unzipper": { + "version": "0.10.11", + "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", + "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", + "dev": true, + "requires": { + "big-integer": "^1.6.17", + "binary": "~0.3.0", + "bluebird": "~3.4.1", + "buffer-indexof-polyfill": "~1.0.0", + "duplexer2": "~0.1.4", + "fstream": "^1.0.12", + "graceful-fs": "^4.2.2", + "listenercount": "~1.0.1", + "readable-stream": "~2.3.6", + "setimmediate": "~1.0.4" + }, + "dependencies": { + "bluebird": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", + "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "upper-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz", + "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + } + }, + "upper-case-first": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", + "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + } + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -10257,6 +21088,33 @@ "punycode": "^2.1.0" } }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, "utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", @@ -10288,9 +21146,9 @@ "dev": true }, "v8-to-istanbul": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", - "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.1", @@ -10335,6 +21193,57 @@ } } }, + "vinyl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", + "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + } + }, + "vinyl-file": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/vinyl-file/-/vinyl-file-3.0.0.tgz", + "integrity": "sha1-sQTZ5ECf+jJfqt1SBkLQo7SIs2U=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.3.0", + "strip-bom-buf": "^1.0.0", + "strip-bom-stream": "^2.0.0", + "vinyl": "^2.0.1" + } + }, + "vm2": { + "version": "3.9.9", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.9.tgz", + "integrity": "sha512-xwTm7NLh/uOjARRBs8/95H0e8fT3Ukw5D/JJWhxMbhKzNh1Nu981jQKvkep9iKYNxzlVrdzD0mlBGkDKZWprlw==", + "dev": true, + "requires": { + "acorn": "^8.7.0", + "acorn-walk": "^8.2.0" + }, + "dependencies": { + "acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + } + } + }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -10437,9 +21346,9 @@ } }, "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -10458,6 +21367,12 @@ "is-symbol": "^1.0.3" } }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, "widest-line": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", @@ -10473,6 +21388,25 @@ "integrity": "sha1-ugZWKbepJRMOFXeRCM9UCZDpjRs=", "dev": true }, + "with-open-file": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/with-open-file/-/with-open-file-0.1.7.tgz", + "integrity": "sha512-ecJS2/oHtESJ1t3ZfMI3B7KIDKyfN0O16miWxdn30zdh66Yd3LsRFebXZXq6GU4xfxLf6nVxp9kIqElb5fqczA==", + "dev": true, + "requires": { + "p-finally": "^1.0.0", + "p-try": "^2.1.0", + "pify": "^4.0.1" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -10495,168 +21429,923 @@ "typical": "^2.6.1" } }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", + "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "dev": true + }, + "xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "dev": true, + "requires": { + "sax": "^1.2.4" + } + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "dev": true + }, + "xmldom-sfdx-encoding": { + "version": "0.1.30", + "resolved": "https://registry.npmjs.org/xmldom-sfdx-encoding/-/xmldom-sfdx-encoding-0.1.30.tgz", + "integrity": "sha512-NOZCfMfwvCMBlSMBr971cnjmToNswV68A1CA3pnM0WGauo1BhWpTgSsj6Lbq8HNAI2OOdWktCSMLtaZU5wVBHA==", + "dev": true + }, + "xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + }, + "yarn": { + "version": "1.22.18", + "resolved": "https://registry.npmjs.org/yarn/-/yarn-1.22.18.tgz", + "integrity": "sha512-oFffv6Jp2+BTUBItzx1Z0dpikTX+raRdqupfqzeMKnoh7WD6RuPAxcqDkMUy9vafJkrB0YaV708znpuMhEBKGQ==", + "dev": true + }, + "yeoman-environment": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-2.10.3.tgz", + "integrity": "sha512-pLIhhU9z/G+kjOXmJ2bPFm3nejfbH+f1fjYRSOteEXDBrv1EoJE/e+kuHixSXfCYfTkxjYsvRaDX+1QykLCnpQ==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "debug": "^3.1.0", + "diff": "^3.5.0", + "escape-string-regexp": "^1.0.2", + "execa": "^4.0.0", + "globby": "^8.0.1", + "grouped-queue": "^1.1.0", + "inquirer": "^7.1.0", + "is-scoped": "^1.0.0", + "lodash": "^4.17.10", + "log-symbols": "^2.2.0", + "mem-fs": "^1.1.0", + "mem-fs-editor": "^6.0.0", + "npm-api": "^1.0.0", + "semver": "^7.1.3", + "strip-ansi": "^4.0.0", + "text-table": "^0.2.0", + "untildify": "^3.0.3", + "yeoman-generator": "^4.8.2" + }, + "dependencies": { + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "path-type": "^3.0.0" + } + }, + "execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "globby": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz", + "integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "2.0.0", + "fast-glob": "^2.0.2", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + } + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "untildify": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", + "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "yeoman-generator": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/yeoman-generator/-/yeoman-generator-4.13.0.tgz", + "integrity": "sha512-f2/5N5IR3M2Ozm+QocvZQudlQITv2DwI6Mcxfy7R7gTTzaKgvUpgo/pQMJ+WQKm0KN0YMWCFOZpj0xFGxevc1w==", "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "async": "^2.6.2", + "chalk": "^2.4.2", + "cli-table": "^0.3.1", + "cross-spawn": "^6.0.5", + "dargs": "^6.1.0", + "dateformat": "^3.0.3", + "debug": "^4.1.1", + "diff": "^4.0.1", + "error": "^7.0.2", + "find-up": "^3.0.0", + "github-username": "^3.0.0", + "grouped-queue": "^1.1.0", + "istextorbinary": "^2.5.1", + "lodash": "^4.17.11", + "make-dir": "^3.0.0", + "mem-fs-editor": "^7.0.1", + "minimist": "^1.2.5", + "pretty-bytes": "^5.2.0", + "read-chunk": "^3.2.0", + "read-pkg-up": "^5.0.0", + "rimraf": "^2.6.3", + "run-async": "^2.0.0", + "semver": "^7.2.1", + "shelljs": "^0.8.4", + "text-table": "^0.2.0", + "through2": "^3.0.1", + "yeoman-environment": "^2.9.5" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + } + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "globby": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.2", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mem-fs-editor": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/mem-fs-editor/-/mem-fs-editor-7.1.0.tgz", + "integrity": "sha512-BH6QEqCXSqGeX48V7zu+e3cMwHU7x640NB8Zk8VNvVZniz+p4FK60pMx/3yfkzo6miI6G3a8pH6z7FeuIzqrzA==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "deep-extend": "^0.6.0", + "ejs": "^3.1.5", + "glob": "^7.1.4", + "globby": "^9.2.0", + "isbinaryfile": "^4.0.0", + "mkdirp": "^1.0.0", + "multimatch": "^4.0.0", + "rimraf": "^3.0.0", + "through2": "^3.0.2", + "vinyl": "^2.2.1" + }, + "dependencies": { + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { - "color-convert": "^2.0.1" + "p-try": "^2.0.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "color-name": "~1.1.4" + "p-limit": "^2.0.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - }, - "dependencies": { - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + } + }, + "read-pkg-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-5.0.0.tgz", + "integrity": "sha512-XBQjqOBtTzyol2CpsQOw8LHV0XbDZVG7xMMjmXAJomlVY03WOBRmYgDJETlvcg0H63AJvPRwT7GFi5rvOzUOKg==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^5.0.0" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "dev": true, "requires": { - "minimist": "^1.2.5" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true } } }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", - "dev": true - }, - "xml-js": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", - "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", - "dev": true, - "requires": { - "sax": "^1.2.4" - } - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "xmlcreate": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", - "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true - }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", @@ -10669,6 +22358,132 @@ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true }, + "yosay": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/yosay/-/yosay-2.0.2.tgz", + "integrity": "sha512-avX6nz2esp7IMXGag4gu6OyQBsMh/SEn+ZybGu3yKPlOTE6z9qJrzG/0X5vCq/e0rPFy0CUYCze0G5hL310ibA==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0", + "ansi-styles": "^3.0.0", + "chalk": "^1.0.0", + "cli-boxes": "^1.0.0", + "pad-component": "0.0.1", + "string-width": "^2.0.0", + "strip-ansi": "^3.0.0", + "taketalk": "^1.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + } + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + } + } + }, "zip-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", @@ -10678,19 +22493,6 @@ "archiver-utils": "^2.1.0", "compress-commons": "^4.1.0", "readable-stream": "^3.6.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } } } } diff --git a/package.json b/package.json index a25333e03..662b8009d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nebula-logger", - "version": "4.7.0", + "version": "4.7.1", "description": "Designed for Salesforce admins, developers & architects. A robust logger for Apex, Flow, Process Builder & Integrations.", "author": "Jonathan Gillespie", "license": "MIT", @@ -22,7 +22,8 @@ "flow", "lightning components", "lwc", - "aura" + "aura", + "big objects" ], "engines": { "node": ">= 12.18.0", @@ -37,7 +38,7 @@ "docs:fix:lwc": "pwsh ./scripts/build/generate-lwc-docs.ps1 && git add ./docs/lightning-components", "docs:verify": "pwsh ./scripts/build/verify-docs-up-to-date.ps1", "experience:create": "sfdx force:community:create --name \"Logger Test Site\" --templatename \"Customer Service\" --urlpathprefix logger --description \"Logger Test Site\"", - "experience:deploy": "sfdx force:source:deploy --sourcepath ./nebula-logger/experience-cloud --wait 30", + "experience:deploy": "sfdx force:source:deploy --sourcepath ./config/experience-cloud --wait 30", "husky:pre-commit": "lint-staged --config ./config/linters/lint-staged.config.js", "lint:fix:lwc": "eslint --config ./config/linters/.eslintrc.json **/lwc/** --fix && eslint --config ./config/linters/.eslintrc.json **/aura/** --fix", "lint:verify": "npm run lint:verify:apex && npm run lint:verify:lwc", @@ -53,7 +54,11 @@ "package:version:create:unlocked": "sfdx force:package:version:create --json --package \"Nebula Logger - Core\" --skipancestorcheck --codecoverage --installationkeybypass --wait 30", "package:version:number:fix": "pwsh ./scripts/build/sync-package-version-number.ps1", "package:version:number:verify": "pwsh ./scripts/build/validate-current-package-version-number.ps1", + "permset:assign": "npm run permset:assign:admin && npm run permset:assign:big-object-admin && npm run permset:assign:slack-admin", "permset:assign:admin": "sfdx force:user:permset:assign --permsetname LoggerAdmin", + "permset:assign:big-object-admin": "sfdx force:user:permset:assign --permsetname LoggerLogEntryArchiveAdmin", + "permset:assign:slack-admin": "sfdx force:user:permset:assign --permsetname LoggerSlackPluginAdmin", + "plugin:version:create:big-object-archiving": "sfdx force:package:version:create --json --package \"Nebula Logger - Core Plugin - Big Object Archiving\" --codecoverage --installationkeybypass --wait 30", "plugin:version:create:log-retention-rules": "sfdx force:package:version:create --json --package \"Nebula Logger - Core Plugin - Log Retention Rules\" --codecoverage --installationkeybypass --wait 30", "plugin:version:create:logger-admin-dashboard": "sfdx force:package:version:create --json --package \"Nebula Logger - Core Plugin - Logger Admin Dashboard\" --codecoverage --installationkeybypass --wait 30", "plugin:version:create:slack": "sfdx force:package:version:create --json --package \"Nebula Logger - Core Plugin - Slack\" --codecoverage --installationkeybypass --wait 30", @@ -63,11 +68,14 @@ "sfdx:plugins:link:bummer": "npx sfdx plugins:link ./node_modules/@jongpie/sfdx-bummer-plugin", "sfdx:plugins:link:prettier": "npx sfdx plugins:link ./node_modules/@jayree/sfdx-plugin-prettier", "sfdx:plugins:link:scanner": "npx sfdx plugins:link ./node_modules/@salesforce/sfdx-scanner", + "source:deploy": "sfdx force:source:deploy --sourcepath ./nebula-logger/ --wait 30", + "source:deploy:core": "sfdx force:source:deploy --sourcepath ./nebula-logger/core --wait 30", "source:push": "sfdx force:source:push --forceoverwrite", "source:push:test": "npm run source:push && npm run test:apex", "test": "npm run test:lwc && npm run test:apex", "test:apex": "sfdx force:apex:test:run --verbose --testlevel RunLocalTests --wait 30 --resultformat human --codecoverage --detailedcoverage --outputdir ./test-coverage/apex", - "test:apex:suites": "sfdx force:apex:test:run --verbose --suitenames LoggerConfiguration,LoggerEngine,LoggerLogManagement,LoggerPluginFramework --wait 30 --resultformat human --codecoverage --detailedcoverage --outputdir ./tests/apex", + "test:apex:without-coverage": "sfdx force:apex:test:run --verbose --testlevel RunLocalTests --wait 30 --resultformat human --outputdir ./test-coverage/apex", + "test:apex:suites": "sfdx force:apex:test:run --verbose --suitenames LoggerConfiguration,LoggerEngine,LoggerLogManagement --wait 30 --resultformat human --codecoverage --detailedcoverage --outputdir ./tests/apex", "test:lwc": "sfdx-lwc-jest --coverage --skipApiVersionCheck --verbose" }, "dependencies": { @@ -81,7 +89,7 @@ "devDependencies": { "@babel/core": "latest", "@babel/eslint-parser": "latest", - "@cparra/apexdocs": "latest", + "@cparra/apexdocs": "1.13.7", "@jayree/sfdx-plugin-prettier": "latest", "@jongpie/sfdx-bummer-plugin": "latest", "@ljharb/eslint-config": "latest", @@ -100,7 +108,7 @@ "lint-staged": "latest", "prettier": "latest", "prettier-plugin-apex": "latest", - "pwsh": "latest", + "pwsh": "^0.3.0", "sfdx-cli": "latest" } } diff --git a/scripts/build/create-and-install-package-version.ps1 b/scripts/build/create-and-install-package-version.ps1 index e73d415d0..0583ae0b6 100644 --- a/scripts/build/create-and-install-package-version.ps1 +++ b/scripts/build/create-and-install-package-version.ps1 @@ -127,7 +127,7 @@ function Install-Package-Version { ) $packageVersionId = "$packageVersionId".Trim() - npx sfdx force:package:install --noprompt --targetusername $targetusername --wait 20 --package $packageVersionId + npx sfdx force:package:install --noprompt --targetusername $targetusername --wait 20 --publishwait 5 --package $packageVersionId if ($LASTEXITCODE -ne 0) { throw "Error installing package version ID: $packageVersionId" } diff --git a/scripts/build/create-managed-package-beta-version.ps1 b/scripts/build/create-managed-package-beta-version.ps1 index 99aed9829..73b67cc93 100644 --- a/scripts/build/create-managed-package-beta-version.ps1 +++ b/scripts/build/create-managed-package-beta-version.ps1 @@ -12,7 +12,7 @@ Copy-Item -Path $rootProject -Destination $unlockedProject -Force Write-Output "Overwriting $rootProject with $managedProject" Copy-Item -Path $managedProject -Destination $rootProject -Force -# Create a beta of the managed package version (no `--codecoverage` flag) +# Create a new version of the managed package cp -R ./nebula-logger/core/ ./nebula-logger/managed-package/ $gitBranch = (git branch --show-current) $gitCommit = (git rev-parse HEAD) diff --git a/scripts/build/generate-apex-docs.ps1 b/scripts/build/generate-apex-docs.ps1 index 9af21dfd0..766fbe7f7 100644 --- a/scripts/build/generate-apex-docs.ps1 +++ b/scripts/build/generate-apex-docs.ps1 @@ -1,21 +1,17 @@ # This script is used to generate the markdown files used by Github pages for Apex docs -rm -f ./docs/apex/*/*.md -rm -rf ./docs/apex/configuration/ -rm -rf ./docs/apex/logger-engine/ -rm -rf ./docs/apex/log-management/ -rm -rf ./docs/apex/plugin-framework/ +find ./docs/apex/ -maxdepth 2 -type f -name "*.md" -delete -npx apexdocs-generate --configPath ./config/docs/apexdocs.json --scope global public --sourceDir ./nebula-logger/core/main/ --targetDir ./docs/apex --targetGenerator jekyll +npx apexdocs-generate --configPath ./config/docs/apexdocs.json --scope global public --sourceDir ./nebula-logger/core/ ./nebula-logger/plugins/ --targetDir ./docs/apex --targetGenerator jekyll # Make a few adjustments to the generated markdown files so that they work correctly in Github Pages $indexPageFile = "docs/apex/index.md" Write-Output "Processing file: $indexPageFile" (Get-Content -path $indexPageFile -Raw) -replace "# Classes","# Nebula Logger for Apex" | Set-Content -Path $indexPageFile -NoNewline (Get-Content -path $indexPageFile -Raw) -replace ".md","" | Set-Content -Path $indexPageFile -NoNewline -(Get-Content -path $indexPageFile -Raw) -replace "/Configuration/","configuration/" | Set-Content -Path $indexPageFile -NoNewline -(Get-Content -path $indexPageFile -Raw) -replace "/Logger-Engine/","logger-engine/" | Set-Content -Path $indexPageFile -NoNewline -(Get-Content -path $indexPageFile -Raw) -replace "/Log-Management/","log-management/" | Set-Content -Path $indexPageFile -NoNewline -(Get-Content -path $indexPageFile -Raw) -replace "/Plugin-Framework/","plugin-framework/" | Set-Content -Path $indexPageFile -NoNewline +(Get-Content -path $indexPageFile -Raw) -replace "/Configuration/","Configuration/" | Set-Content -Path $indexPageFile -NoNewline +(Get-Content -path $indexPageFile -Raw) -replace "/Logger-Engine/","Logger-Engine/" | Set-Content -Path $indexPageFile -NoNewline +(Get-Content -path $indexPageFile -Raw) -replace "/Log-Management/","Log-Management/" | Set-Content -Path $indexPageFile -NoNewline +(Get-Content -path $indexPageFile -Raw) -replace "/Plugins/","Plugins/" | Set-Content -Path $indexPageFile -NoNewline $docsSubdirectories = "docs/apex/*/*.*" foreach($file in Get-ChildItem $docsSubdirectories) { @@ -24,11 +20,9 @@ foreach($file in Get-ChildItem $docsSubdirectories) { (Get-Content -path $file -Raw) -replace "../Configuration/","" | Set-Content -Path $file -NoNewline (Get-Content -path $file -Raw) -replace "../Logger-Engine/","" | Set-Content -Path $file -NoNewline (Get-Content -path $file -Raw) -replace "../Log-Management/","" | Set-Content -Path $file -NoNewline - (Get-Content -path $file -Raw) -replace "../Plugin-Framework/","" | Set-Content -Path $file -NoNewline } -mv ./docs/apex/Configuration/ ./docs/apex/configuration/ -mv ./docs/apex/Logger-Engine/ ./docs/apex/logger-engine/ -mv ./docs/apex/Log-Management/ ./docs/apex/log-management/ -mv ./docs/apex/Plugin-Framework/ ./docs/apex/plugin-framework/ +# mv ./docs/apex/Configuration/ ./docs/apex/configuration/ +# mv ./docs/apex/Logger-Engine/ ./docs/apex/logger-engine/ +# mv ./docs/apex/Log-Management/ ./docs/apex/log-management/ prettier ./docs/apex/ --write \ No newline at end of file diff --git a/scripts/data/create-sample-log-entries.apex b/scripts/data/create-sample-log-entries.apex index 59446595d..052b81d65 100644 --- a/scripts/data/create-sample-log-entries.apex +++ b/scripts/data/create-sample-log-entries.apex @@ -1,5 +1,13 @@ +Logger.getUserSettings().DefaultSaveMethod__c = Logger.SaveMethod.EVENT_BUS.name(); +// Logger.getUserSettings().DefaultSaveMethod__c = 'BIG_OBJECT_IMMEDIATE'; +// Logger.getUserSettings().DefaultSaveMethod__c = 'BIG_OBJECT_QUEUEABLE'; +// Logger.getUserSettings().IsAnonymousModeEnabled__c = true; +// Logger.getUserSettings().DefaultPlatformEventStorageLocation__c = 'BIG_OBJECT'; +// Logger.getUserSettings().DefaultPlatformEventStorageLocation__c = 'CUSTOM_OBJECTS'; +upsert Logger.getUserSettings(); + Logger.setScenario('an example transaction scenario name'); -Logger.getUserSettings().LoggingLevel__c = LoggingLevel.INFO.name(); +Logger.getUserSettings().LoggingLevel__c = LoggingLevel.FINEST.name(); Logger.getUserSettings().IsDataMaskingEnabled__c = true; User currentUser = [SELECT Id, Name, Username, Profile.Name FROM User WHERE Id = :UserInfo.getUserId()]; @@ -12,9 +20,29 @@ currentUser.AboutMe = 'I hope you dont leak my social, which is 400-11-9999, btw Logger.error('Here is my fake Visa credit card 4000-1111-2222-0004, please don\'t steal it').addTag('data masking rule').addTag('credit card masking'); Logger.warn('Here is my fake Mastercard credit card 5000-1111-2222-0005, please don\'t steal it').addTag('data masking rule').addTag('credit card masking'); Logger.info('In case you want to steal my identity, my fake social is 400-11-9999, thanks', currentUser).addTag('data masking rule').addTag('an informational tag'); +Logger.debug('Here are some accounts', [SELECT Id, Name, Description FROM Account LIMIT 5]); +Logger.debug('Here are some save results', Database.update([SELECT Id, Name, Description FROM Account LIMIT 5], false)); +Logger.saveLog(); Logger.debug('Example DEBUG entry', currentUser); Logger.fine('Example FINE entry'); Logger.finer('Example FINER entry'); Logger.finest('Example FINEST entry'); +HttpRequest request = new HttpRequest(); +request.setBody('Hello, world! Here is my credit card number 5000-1111-2222-0005'); +request.setEndpoint('https://fake.salesforce.com'); +request.setMethod('GET'); +Logger.info('logging an HTTP request').setHttpRequestDetails(request); + + +HttpResponse response = new HttpResponse(); +response.setBody('Hello, world! Here is my credit card number 5000-1111-2222-0005'); +response.setHeader('someKey', 'some string value'); +response.setHeader('anotherKey', 'an amazing example value, wow'); +response.setStatus('STATUS_GOOD_JOB_YOU_DID_IT'); +response.setStatusCode(201); +Logger.info('logging an HTTP response').setHttpResponseDetails(response); + Logger.saveLog(); + +throw new DmlException('aahhhhh!'); diff --git a/scripts/data/create-sample-log-entry-archives.apex b/scripts/data/create-sample-log-entry-archives.apex new file mode 100644 index 000000000..8a6f98213 --- /dev/null +++ b/scripts/data/create-sample-log-entry-archives.apex @@ -0,0 +1,18 @@ +// Logger.getUserSettings().DefaultSaveMethod__c = 'BIG_OBJECT_EVENT_BUS'; +// Logger.getUserSettings().DefaultSaveMethod__c = 'BIG_OBJECT_IMMEDIATE'; +// Logger.getUserSettings().DefaultSaveMethod__c = 'BIG_OBJECT_QUEUEABLE'; +//Logger.getUserSettings().IsAnonymousModeEnabled__c = true; + +for (Integer i = 0; i < 200; i++) { + Logger.info('hello, LogEntryArchive__b! entry index==' + i).addTag('test tag'); +} +Logger.saveLog(); + +// try { +// Logger.debug('about to cause an exception').addTag('error logging'); +// update new User(); +// } catch(Exception ex) { +// Logger.error('got that exception that everyone was talking about, wild stuff', ex).addTag('error logging'); +// Logger.saveLog(); +// throw ex; +// } diff --git a/scripts/data/query-log-entry-archive-big-object.apex b/scripts/data/query-log-entry-archive-big-object.apex new file mode 100644 index 000000000..b0700f0d3 --- /dev/null +++ b/scripts/data/query-log-entry-archive-big-object.apex @@ -0,0 +1,15 @@ +Id userId = UserInfo.getUserId(); +List loggingLevelNames = new List(); +for (LoggingLevel logLevel : LoggingLevel.values()) { + loggingLevelNames.add(logLevel.name()); +} + +List archives = [ + SELECT Timestamp__c, LoggedBy__c, LoggingLevel__c, TransactionId__c, TransactionEntryNumber__c, Message__c, Tags__c + FROM LogEntryArchive__b + WHERE LoggedBy__c = :userId + AND LoggingLevel__c IN :loggingLevelNames + AND Timestamp__c >= LAST_WEEK + ORDER BY LoggedBy__c, LoggingLevel__c, Timestamp__c DESC +]; +System.debug('Matching LogEntryArchive__b records:\n' + JSON.serializePretty(archives)); \ No newline at end of file diff --git a/sfdx-project.json b/sfdx-project.json index c16879b92..1f150cf23 100644 --- a/sfdx-project.json +++ b/sfdx-project.json @@ -7,36 +7,62 @@ "package": "Nebula Logger - Core", "path": "./nebula-logger/core", "definitionFile": "./config/scratch-orgs/base-scratch-def.json", - "versionNumber": "4.7.0.NEXT", - "versionName": "Spring '22 Release", - "versionDescription": "Added new settings fields for controlling saving, default log scenario, & default log owner, improved logViewer lwc, bugfixes & cleanup", + "versionNumber": "4.7.1.NEXT", + "versionName": "Plugin Framework Overhaul", + "versionDescription": "New approach implemented for plugins, providing more control within LoggerSObjectHandler, and the ability to create plugins for LogBatchPurger", "releaseNotesUrl": "https://github.com/jongpie/NebulaLogger/releases", "default": true }, + { + "package": "Nebula Logger - Plugin - Big Object Archiving", + "path": "./nebula-logger/plugins/big-object-archiving/plugin", + "dependencies": [ + { + "package": "Nebula Logger - Core@4.7.1-8-plugin-framework-overhaul" + } + ], + "versionName": "Beta Release", + "versionNumber": "0.9.0.NEXT", + "versionDescription": "Initial beta version of new plugin", + "default": false + }, + { + "package": "Nebula Logger - Plugin - Log Retention Rules", + "path": "./nebula-logger/plugins/log-retention-rules/plugin", + "dependencies": [ + { + "package": "Nebula Logger - Core@4.7.1-8-plugin-framework-overhaul" + } + ], + "versionName": "Beta Release", + "versionNumber": "0.9.0.NEXT", + "versionDescription": "Initial beta version of new plugin", + "default": false + }, { "package": "Nebula Logger - Plugin - Logger Admin Dashboard", - "path": "./nebula-logger/plugins/Logger-Admin-Dashboard/plugin", + "path": "./nebula-logger/plugins/logger-admin-dashboard/plugin", "dependencies": [ { "package": "Nebula Logger - Core@4.6.12-0-log-scenario-rules" } ], "versionName": "Beta Release", - "versionNumber": "0.9.0.0", + "versionNumber": "0.9.0.NEXT", "versionDescription": "Initial beta version of new dashboard plugin", "default": false }, { "package": "Nebula Logger - Plugin - Slack", - "path": "./nebula-logger/plugins/Slack/plugin", + "path": "./nebula-logger/plugins/slack/plugin", "dependencies": [ { - "package": "Nebula Logger - Core@4.6.9-0-custom-metadata-types-optimized" + "package": "Nebula Logger - Core@4.7.1-8-plugin-framework-overhaul" } ], "versionName": "Beta Release: Round 3", - "versionNumber": "0.9.2.0", - "versionDescription": "Updated Slack plugin metadata to use Logger v4.6.9's renamed custom metadata type LoggerParameter__mdt", + "versionNumber": "0.10.0.NEXT", + "versionDescription": "TODO", "default": false }, { @@ -77,12 +103,17 @@ "Nebula Logger - Core@4.6.15-0-small-bugfixes-and-test-improvements": "04t5Y0000015lKDQAY", "Nebula Logger - Core@4.6.16-0-ui-cleanup": "04t5Y0000015lLzQAI", "Nebula Logger - Core@4.7.0-25-spring-'22-release": "04t5Y0000015lXSQAY", + "Nebula Logger - Core@4.7.1-8-plugin-framework-overhaul": "04t5Y0000015lgBQAQ", + "Nebula Logger - Plugin - Big Object Archiving": "0Ho5Y000000blMSSAY", + "Nebula Logger - Plugin - Big Object Archiving@0.9.0-2": "04t5Y0000015lgLQAQ", "Nebula Logger - Plugin - Log Retention Rules": "0Ho5Y000000blNfSAI", + "Nebula Logger - Plugin - Log Retention Rules@0.9.0-2": "04t5Y0000015lgGQAQ", "Nebula Logger - Plugin - Logger Admin Dashboard": "0Ho5Y000000blNkSAI", "Nebula Logger - Plugin - Logger Admin Dashboard@0.9.0-0": "04t5Y0000015l3yQAA", "Nebula Logger - Plugin - Slack": "0Ho5Y000000blMDSAY", "Nebula Logger - Plugin - Slack@0.9.0-0-beta-release": "04t5e00000061lHAAQ", "Nebula Logger - Plugin - Slack@0.9.1-0-beta-release-round-2": "04t5e00000065xiAAA", - "Nebula Logger - Plugin - Slack@0.9.2-0-beta-release-round-3": "04t5Y0000015l2WQAQ" + "Nebula Logger - Plugin - Slack@0.9.2-0-beta-release-round-3": "04t5Y0000015l2WQAQ", + "Nebula Logger - Plugin - Slack@0.10.0-2": "04t5Y0000015lgQQAQ" } }