@appsemble/utils 0.20.28 → 0.20.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/api/components/schemas/AppDefinition.js +1 -0
- package/api/components/schemas/LoopPageActionsDefinition.d.ts +2 -0
- package/api/components/schemas/LoopPageActionsDefinition.js +24 -0
- package/api/components/schemas/LoopPageDefinition.d.ts +1 -0
- package/api/components/schemas/LoopPageDefinition.js +38 -0
- package/api/components/schemas/ObjectRemapperDefinition.js +4 -0
- package/api/components/schemas/index.d.ts +2 -0
- package/api/components/schemas/index.js +2 -0
- package/appMessages.js +4 -1
- package/iterApp.js +3 -0
- package/package.json +2 -2
- package/remap.d.ts +3 -0
- package/remap.js +3 -0
- package/validation.js +7 -7
- package/validation.test.js +1 -1
- package/api/components/index.js.map +0 -1
- package/api/components/index.ts +0 -15
- package/api/components/parameters/$filter.js.map +0 -1
- package/api/components/parameters/$filter.ts +0 -12
- package/api/components/parameters/$orderby.js.map +0 -1
- package/api/components/parameters/$orderby.ts +0 -12
- package/api/components/parameters/$select.js.map +0 -1
- package/api/components/parameters/$select.ts +0 -15
- package/api/components/parameters/$team.js.map +0 -1
- package/api/components/parameters/$team.ts +0 -11
- package/api/components/parameters/$top.js.map +0 -1
- package/api/components/parameters/$top.ts +0 -9
- package/api/components/parameters/appId.js.map +0 -1
- package/api/components/parameters/appId.ts +0 -9
- package/api/components/parameters/appOAuth2SecretId.js.map +0 -1
- package/api/components/parameters/appOAuth2SecretId.ts +0 -9
- package/api/components/parameters/appSamlSecretId.js.map +0 -1
- package/api/components/parameters/appSamlSecretId.ts +0 -12
- package/api/components/parameters/assetId.js.map +0 -1
- package/api/components/parameters/assetId.ts +0 -9
- package/api/components/parameters/blockId.js.map +0 -1
- package/api/components/parameters/blockId.ts +0 -15
- package/api/components/parameters/blockVersion.js.map +0 -1
- package/api/components/parameters/blockVersion.ts +0 -9
- package/api/components/parameters/endpoint.js.map +0 -1
- package/api/components/parameters/endpoint.ts +0 -9
- package/api/components/parameters/index.js.map +0 -1
- package/api/components/parameters/index.ts +0 -18
- package/api/components/parameters/language.js.map +0 -1
- package/api/components/parameters/language.ts +0 -9
- package/api/components/parameters/organizationId.js.map +0 -1
- package/api/components/parameters/organizationId.ts +0 -9
- package/api/components/parameters/resourceId.js.map +0 -1
- package/api/components/parameters/resourceId.ts +0 -9
- package/api/components/parameters/resourceType.js.map +0 -1
- package/api/components/parameters/resourceType.ts +0 -11
- package/api/components/parameters/screenshotId.js.map +0 -1
- package/api/components/parameters/screenshotId.ts +0 -9
- package/api/components/parameters/view.js.map +0 -1
- package/api/components/parameters/view.ts +0 -8
- package/api/components/requestBodies/index.js.map +0 -1
- package/api/components/requestBodies/index.ts +0 -3
- package/api/components/requestBodies/oauth2Consent.js.map +0 -1
- package/api/components/requestBodies/oauth2Consent.ts +0 -31
- package/api/components/requestBodies/resource.js.map +0 -1
- package/api/components/requestBodies/resource.ts +0 -31
- package/api/components/requestBodies/user.js.map +0 -1
- package/api/components/requestBodies/user.ts +0 -12
- package/api/components/responses/app.js.map +0 -1
- package/api/components/responses/app.ts +0 -12
- package/api/components/responses/blockVersion.js.map +0 -1
- package/api/components/responses/blockVersion.ts +0 -12
- package/api/components/responses/default.js.map +0 -1
- package/api/components/responses/default.ts +0 -10
- package/api/components/responses/index.js.map +0 -1
- package/api/components/responses/index.ts +0 -8
- package/api/components/responses/invite.js.map +0 -1
- package/api/components/responses/invite.ts +0 -12
- package/api/components/responses/oauth2AuthorizationCode.js.map +0 -1
- package/api/components/responses/oauth2AuthorizationCode.ts +0 -12
- package/api/components/responses/organization.js.map +0 -1
- package/api/components/responses/organization.ts +0 -12
- package/api/components/responses/resource.js.map +0 -1
- package/api/components/responses/resource.ts +0 -17
- package/api/components/responses/subscriptions.js.map +0 -1
- package/api/components/responses/subscriptions.ts +0 -16
- package/api/components/schemas/ActionDefinition.js.map +0 -1
- package/api/components/schemas/ActionDefinition.ts +0 -82
- package/api/components/schemas/AnalyticsActionDefinition.js.map +0 -1
- package/api/components/schemas/AnalyticsActionDefinition.ts +0 -25
- package/api/components/schemas/App.js.map +0 -1
- package/api/components/schemas/App.ts +0 -107
- package/api/components/schemas/AppAccount.js.map +0 -1
- package/api/components/schemas/AppAccount.ts +0 -39
- package/api/components/schemas/AppDefinition.js.map +0 -1
- package/api/components/schemas/AppDefinition.ts +0 -112
- package/api/components/schemas/AppLayoutDefinition.js.map +0 -1
- package/api/components/schemas/AppLayoutDefinition.ts +0 -39
- package/api/components/schemas/AppMessages.js.map +0 -1
- package/api/components/schemas/AppMessages.ts +0 -17
- package/api/components/schemas/AppOAuth2Secret.js.map +0 -1
- package/api/components/schemas/AppOAuth2Secret.ts +0 -65
- package/api/components/schemas/AppsembleMessages.js.map +0 -1
- package/api/components/schemas/AppsembleMessages.ts +0 -41
- package/api/components/schemas/Asset.js.map +0 -1
- package/api/components/schemas/Asset.ts +0 -33
- package/api/components/schemas/BaseActionDefinition.js.map +0 -1
- package/api/components/schemas/BaseActionDefinition.ts +0 -11
- package/api/components/schemas/BaseJSONSchema.js.map +0 -1
- package/api/components/schemas/BaseJSONSchema.ts +0 -25
- package/api/components/schemas/BasePageDefinition.js.map +0 -1
- package/api/components/schemas/BasePageDefinition.ts +0 -89
- package/api/components/schemas/BlockDefinition.js.map +0 -1
- package/api/components/schemas/BlockDefinition.ts +0 -86
- package/api/components/schemas/BlockVersion.js.map +0 -1
- package/api/components/schemas/BlockVersion.ts +0 -162
- package/api/components/schemas/ConditionActionDefinition.js.map +0 -1
- package/api/components/schemas/ConditionActionDefinition.ts +0 -30
- package/api/components/schemas/CronDefinition.js.map +0 -1
- package/api/components/schemas/CronDefinition.ts +0 -21
- package/api/components/schemas/CustomFontDefinition.js.map +0 -1
- package/api/components/schemas/CustomFontDefinition.ts +0 -21
- package/api/components/schemas/DialogActionDefinition.js.map +0 -1
- package/api/components/schemas/DialogActionDefinition.ts +0 -42
- package/api/components/schemas/DialogErrorActionDefinition.js.map +0 -1
- package/api/components/schemas/DialogErrorActionDefinition.ts +0 -17
- package/api/components/schemas/DialogOkActionDefinition.js.map +0 -1
- package/api/components/schemas/DialogOkActionDefinition.ts +0 -17
- package/api/components/schemas/DownloadActionDefinition.js.map +0 -1
- package/api/components/schemas/DownloadActionDefinition.ts +0 -19
- package/api/components/schemas/EachActionDefinition.js.map +0 -1
- package/api/components/schemas/EachActionDefinition.ts +0 -22
- package/api/components/schemas/EmailActionDefinition.js.map +0 -1
- package/api/components/schemas/EmailActionDefinition.ts +0 -58
- package/api/components/schemas/Error.js.map +0 -1
- package/api/components/schemas/Error.ts +0 -25
- package/api/components/schemas/EventActionDefinition.js.map +0 -1
- package/api/components/schemas/EventActionDefinition.ts +0 -28
- package/api/components/schemas/EventsDefinition.js.map +0 -1
- package/api/components/schemas/EventsDefinition.ts +0 -30
- package/api/components/schemas/FlowBackActionDefinition.js.map +0 -1
- package/api/components/schemas/FlowBackActionDefinition.ts +0 -16
- package/api/components/schemas/FlowFinishActionDefinition.js.map +0 -1
- package/api/components/schemas/FlowFinishActionDefinition.ts +0 -16
- package/api/components/schemas/FlowNextActionDefinition.js.map +0 -1
- package/api/components/schemas/FlowNextActionDefinition.ts +0 -17
- package/api/components/schemas/FlowPageActionsDefinition.js.map +0 -1
- package/api/components/schemas/FlowPageActionsDefinition.ts +0 -20
- package/api/components/schemas/FlowPageDefinition.js.map +0 -1
- package/api/components/schemas/FlowPageDefinition.ts +0 -37
- package/api/components/schemas/FlowToActionDefinition.js.map +0 -1
- package/api/components/schemas/FlowToActionDefinition.ts +0 -21
- package/api/components/schemas/GoogleFontDefinition.js.map +0 -1
- package/api/components/schemas/GoogleFontDefinition.ts +0 -24
- package/api/components/schemas/Health.js.map +0 -1
- package/api/components/schemas/Health.ts +0 -14
- package/api/components/schemas/JSONPointer.js.map +0 -1
- package/api/components/schemas/JSONPointer.ts +0 -20
- package/api/components/schemas/JSONSchema.js.map +0 -1
- package/api/components/schemas/JSONSchema.ts +0 -21
- package/api/components/schemas/JSONSchemaAnyOf.js.map +0 -1
- package/api/components/schemas/JSONSchemaAnyOf.ts +0 -27
- package/api/components/schemas/JSONSchemaArray.js.map +0 -1
- package/api/components/schemas/JSONSchemaArray.ts +0 -47
- package/api/components/schemas/JSONSchemaBoolean.js.map +0 -1
- package/api/components/schemas/JSONSchemaBoolean.ts +0 -37
- package/api/components/schemas/JSONSchemaConst.js.map +0 -1
- package/api/components/schemas/JSONSchemaConst.ts +0 -16
- package/api/components/schemas/JSONSchemaEnum.js.map +0 -1
- package/api/components/schemas/JSONSchemaEnum.ts +0 -36
- package/api/components/schemas/JSONSchemaInteger.js.map +0 -1
- package/api/components/schemas/JSONSchemaInteger.ts +0 -55
- package/api/components/schemas/JSONSchemaMultiType.js.map +0 -1
- package/api/components/schemas/JSONSchemaMultiType.ts +0 -48
- package/api/components/schemas/JSONSchemaNot.js.map +0 -1
- package/api/components/schemas/JSONSchemaNot.ts +0 -23
- package/api/components/schemas/JSONSchemaNull.js.map +0 -1
- package/api/components/schemas/JSONSchemaNull.ts +0 -16
- package/api/components/schemas/JSONSchemaNumber.js.map +0 -1
- package/api/components/schemas/JSONSchemaNumber.ts +0 -66
- package/api/components/schemas/JSONSchemaObject.js.map +0 -1
- package/api/components/schemas/JSONSchemaObject.ts +0 -74
- package/api/components/schemas/JSONSchemaOneOf.js.map +0 -1
- package/api/components/schemas/JSONSchemaOneOf.ts +0 -25
- package/api/components/schemas/JSONSchemaRemapper.js.map +0 -1
- package/api/components/schemas/JSONSchemaRemapper.ts +0 -19
- package/api/components/schemas/JSONSchemaRoot.js.map +0 -1
- package/api/components/schemas/JSONSchemaRoot.ts +0 -23
- package/api/components/schemas/JSONSchemaString.js.map +0 -1
- package/api/components/schemas/JSONSchemaString.ts +0 -116
- package/api/components/schemas/LinkActionDefinition.js.map +0 -1
- package/api/components/schemas/LinkActionDefinition.ts +0 -28
- package/api/components/schemas/LinkBackActionDefinition.js.map +0 -1
- package/api/components/schemas/LinkBackActionDefinition.ts +0 -14
- package/api/components/schemas/LinkNextActionDefinition.js.map +0 -1
- package/api/components/schemas/LinkNextActionDefinition.ts +0 -14
- package/api/components/schemas/LogActionDefinition.js.map +0 -1
- package/api/components/schemas/LogActionDefinition.ts +0 -22
- package/api/components/schemas/Member.js.map +0 -1
- package/api/components/schemas/Member.ts +0 -31
- package/api/components/schemas/MessageActionDefinition.js.map +0 -1
- package/api/components/schemas/MessageActionDefinition.ts +0 -36
- package/api/components/schemas/NoopActionDefinition.js.map +0 -1
- package/api/components/schemas/NoopActionDefinition.ts +0 -17
- package/api/components/schemas/NotificationHookDataDefinition.js.map +0 -1
- package/api/components/schemas/NotificationHookDataDefinition.ts +0 -25
- package/api/components/schemas/NotificationHookDefinition.js.map +0 -1
- package/api/components/schemas/NotificationHookDefinition.ts +0 -33
- package/api/components/schemas/OAuth2AuthorizationCode.js.map +0 -1
- package/api/components/schemas/OAuth2AuthorizationCode.ts +0 -15
- package/api/components/schemas/OAuth2ClientCredentials.js.map +0 -1
- package/api/components/schemas/OAuth2ClientCredentials.ts +0 -39
- package/api/components/schemas/ObjectRemapperDefinition.js.map +0 -1
- package/api/components/schemas/ObjectRemapperDefinition.ts +0 -453
- package/api/components/schemas/Organization.js.map +0 -1
- package/api/components/schemas/Organization.ts +0 -40
- package/api/components/schemas/PageDefinition.js.map +0 -1
- package/api/components/schemas/PageDefinition.ts +0 -23
- package/api/components/schemas/Rating.js.map +0 -1
- package/api/components/schemas/Rating.ts +0 -25
- package/api/components/schemas/RemapperDefinition.js.map +0 -1
- package/api/components/schemas/RemapperDefinition.ts +0 -35
- package/api/components/schemas/RequestActionDefinition.js.map +0 -1
- package/api/components/schemas/RequestActionDefinition.ts +0 -60
- package/api/components/schemas/Resource.js.map +0 -1
- package/api/components/schemas/Resource.ts +0 -20
- package/api/components/schemas/ResourceCountActionDefinition.js.map +0 -1
- package/api/components/schemas/ResourceCountActionDefinition.ts +0 -23
- package/api/components/schemas/ResourceCreateActionDefinition.js.map +0 -1
- package/api/components/schemas/ResourceCreateActionDefinition.ts +0 -22
- package/api/components/schemas/ResourceDefinition.js.map +0 -1
- package/api/components/schemas/ResourceDefinition.ts +0 -229
- package/api/components/schemas/ResourceDeleteActionDefinition.js.map +0 -1
- package/api/components/schemas/ResourceDeleteActionDefinition.ts +0 -22
- package/api/components/schemas/ResourceGetActionDefinition.js.map +0 -1
- package/api/components/schemas/ResourceGetActionDefinition.ts +0 -26
- package/api/components/schemas/ResourceHistoryDefinition.js.map +0 -1
- package/api/components/schemas/ResourceHistoryDefinition.ts +0 -15
- package/api/components/schemas/ResourceHooksDefinition.js.map +0 -1
- package/api/components/schemas/ResourceHooksDefinition.ts +0 -11
- package/api/components/schemas/ResourceQueryActionDefinition.js.map +0 -1
- package/api/components/schemas/ResourceQueryActionDefinition.ts +0 -26
- package/api/components/schemas/ResourceSubscription.js.map +0 -1
- package/api/components/schemas/ResourceSubscription.ts +0 -42
- package/api/components/schemas/ResourceSubscriptionStatusActionDefinition.js.map +0 -1
- package/api/components/schemas/ResourceSubscriptionStatusActionDefinition.ts +0 -23
- package/api/components/schemas/ResourceSubscriptionSubscribeActionDefinition.js.map +0 -1
- package/api/components/schemas/ResourceSubscriptionSubscribeActionDefinition.ts +0 -25
- package/api/components/schemas/ResourceSubscriptionToggleActionDefinition.js.map +0 -1
- package/api/components/schemas/ResourceSubscriptionToggleActionDefinition.ts +0 -22
- package/api/components/schemas/ResourceSubscriptionUnsubscribeActionDefinition.js.map +0 -1
- package/api/components/schemas/ResourceSubscriptionUnsubscribeActionDefinition.ts +0 -25
- package/api/components/schemas/ResourceUpdateActionDefinition.js.map +0 -1
- package/api/components/schemas/ResourceUpdateActionDefinition.ts +0 -22
- package/api/components/schemas/ResourceViewDefinition.js.map +0 -1
- package/api/components/schemas/ResourceViewDefinition.ts +0 -26
- package/api/components/schemas/SSLSecret.js.map +0 -1
- package/api/components/schemas/SSLSecret.ts +0 -17
- package/api/components/schemas/SSOConfiguration.js.map +0 -1
- package/api/components/schemas/SSOConfiguration.ts +0 -22
- package/api/components/schemas/SecurityDefaultDefinition.js.map +0 -1
- package/api/components/schemas/SecurityDefaultDefinition.ts +0 -29
- package/api/components/schemas/SecurityDefinition.js.map +0 -1
- package/api/components/schemas/SecurityDefinition.ts +0 -21
- package/api/components/schemas/SecurityRoleDefinition.js.map +0 -1
- package/api/components/schemas/SecurityRoleDefinition.ts +0 -29
- package/api/components/schemas/ShareActionDefinition.js.map +0 -1
- package/api/components/schemas/ShareActionDefinition.ts +0 -30
- package/api/components/schemas/StaticActionDefinition.js.map +0 -1
- package/api/components/schemas/StaticActionDefinition.ts +0 -20
- package/api/components/schemas/StorageAppendActionDefinition.js.map +0 -1
- package/api/components/schemas/StorageAppendActionDefinition.ts +0 -43
- package/api/components/schemas/StorageDeleteActionDefinition.js.map +0 -1
- package/api/components/schemas/StorageDeleteActionDefinition.ts +0 -31
- package/api/components/schemas/StorageReadActionDefinition.js.map +0 -1
- package/api/components/schemas/StorageReadActionDefinition.ts +0 -32
- package/api/components/schemas/StorageSubtractActionDefinition.js.map +0 -1
- package/api/components/schemas/StorageSubtractActionDefinition.ts +0 -35
- package/api/components/schemas/StorageUpdateActionDefinition.js.map +0 -1
- package/api/components/schemas/StorageUpdateActionDefinition.ts +0 -46
- package/api/components/schemas/StorageWriteActionDefinition.js.map +0 -1
- package/api/components/schemas/StorageWriteActionDefinition.ts +0 -42
- package/api/components/schemas/SubPage.js.map +0 -1
- package/api/components/schemas/SubPage.ts +0 -24
- package/api/components/schemas/TabsPageDefinition.js.map +0 -1
- package/api/components/schemas/TabsPageDefinition.ts +0 -22
- package/api/components/schemas/TeamInviteActionDefinition.js.map +0 -1
- package/api/components/schemas/TeamInviteActionDefinition.ts +0 -27
- package/api/components/schemas/TeamJoinActionDefinition.js.map +0 -1
- package/api/components/schemas/TeamJoinActionDefinition.ts +0 -14
- package/api/components/schemas/TeamListActionDefinition.js.map +0 -1
- package/api/components/schemas/TeamListActionDefinition.ts +0 -14
- package/api/components/schemas/TeamsDefinition.js.map +0 -1
- package/api/components/schemas/TeamsDefinition.ts +0 -30
- package/api/components/schemas/Theme.js.map +0 -1
- package/api/components/schemas/Theme.ts +0 -82
- package/api/components/schemas/ThrowActionDefinition.js.map +0 -1
- package/api/components/schemas/ThrowActionDefinition.ts +0 -17
- package/api/components/schemas/User.js.map +0 -1
- package/api/components/schemas/User.ts +0 -30
- package/api/components/schemas/UserEmail.js.map +0 -1
- package/api/components/schemas/UserEmail.ts +0 -24
- package/api/components/schemas/UserLoginActionDefinition.js.map +0 -1
- package/api/components/schemas/UserLoginActionDefinition.ts +0 -22
- package/api/components/schemas/UserRegisterActionDefinition.js.map +0 -1
- package/api/components/schemas/UserRegisterActionDefinition.ts +0 -33
- package/api/components/schemas/UserUpdateActionDefinition.js.map +0 -1
- package/api/components/schemas/UserUpdateActionDefinition.ts +0 -33
- package/api/components/schemas/index.js.map +0 -1
- package/api/components/schemas/index.ts +0 -108
- package/api/components/schemas/utils.js.map +0 -1
- package/api/components/schemas/utils.ts +0 -43
- package/api/components/securitySchemes/app.js.map +0 -1
- package/api/components/securitySchemes/app.ts +0 -33
- package/api/components/securitySchemes/basic.js.map +0 -1
- package/api/components/securitySchemes/basic.ts +0 -7
- package/api/components/securitySchemes/cli.js.map +0 -1
- package/api/components/securitySchemes/cli.test.js.map +0 -1
- package/api/components/securitySchemes/cli.test.ts +0 -6
- package/api/components/securitySchemes/cli.ts +0 -25
- package/api/components/securitySchemes/index.js.map +0 -1
- package/api/components/securitySchemes/index.ts +0 -4
- package/api/components/securitySchemes/studio.js.map +0 -1
- package/api/components/securitySchemes/studio.ts +0 -8
- package/api/index.js.map +0 -1
- package/api/index.test.js.map +0 -1
- package/api/index.test.ts +0 -196
- package/api/index.ts +0 -44
- package/api/paths/action.js.map +0 -1
- package/api/paths/action.ts +0 -55
- package/api/paths/appMessages.js.map +0 -1
- package/api/paths/appMessages.ts +0 -104
- package/api/paths/appOAuth2Secrets.js.map +0 -1
- package/api/paths/appOAuth2Secrets.ts +0 -152
- package/api/paths/appSSLSecrets.js.map +0 -1
- package/api/paths/appSSLSecrets.ts +0 -40
- package/api/paths/appSamlSecrets.js.map +0 -1
- package/api/paths/appSamlSecrets.ts +0 -85
- package/api/paths/apps.js.map +0 -1
- package/api/paths/apps.ts +0 -1394
- package/api/paths/appsembleMessages.js.map +0 -1
- package/api/paths/appsembleMessages.ts +0 -49
- package/api/paths/assets.js.map +0 -1
- package/api/paths/assets.ts +0 -139
- package/api/paths/blocks.js.map +0 -1
- package/api/paths/blocks.ts +0 -184
- package/api/paths/emails.js.map +0 -1
- package/api/paths/emails.ts +0 -164
- package/api/paths/health.js.map +0 -1
- package/api/paths/health.ts +0 -75
- package/api/paths/index.js.map +0 -1
- package/api/paths/index.ts +0 -45
- package/api/paths/invite.js.map +0 -1
- package/api/paths/invite.ts +0 -26
- package/api/paths/oauth2ClientCredentials.js.map +0 -1
- package/api/paths/oauth2ClientCredentials.ts +0 -79
- package/api/paths/oauth2Login.js.map +0 -1
- package/api/paths/oauth2Login.ts +0 -120
- package/api/paths/oauth2Provider.js.map +0 -1
- package/api/paths/oauth2Provider.ts +0 -73
- package/api/paths/organizations.js.map +0 -1
- package/api/paths/organizations.ts +0 -471
- package/api/paths/resourceHistory.js.map +0 -1
- package/api/paths/resourceHistory.ts +0 -32
- package/api/paths/resources.js.map +0 -1
- package/api/paths/resources.ts +0 -305
- package/api/paths/saml.js.map +0 -1
- package/api/paths/saml.ts +0 -127
- package/api/paths/templates.js.map +0 -1
- package/api/paths/templates.ts +0 -85
- package/api/paths/user.js.map +0 -1
- package/api/paths/user.ts +0 -481
- package/api/schema-tests/AppDefinition/invalid/additional-property.yaml +0 -11
- package/api/schema-tests/AppDefinition/invalid/empty-pages.yaml +0 -4
- package/api/schema-tests/AppDefinition/invalid/missing-default-page.yaml +0 -7
- package/api/schema-tests/AppDefinition/invalid/missing-name.yaml +0 -7
- package/api/schema-tests/AppDefinition/invalid/missing-pages.yaml +0 -2
- package/api/schema-tests/AppDefinition/valid/all-properties.yaml +0 -114
- package/api/schema-tests/AppDefinition/valid/minimal.yaml +0 -9
- package/api/schema-tests/FlowPageDefinition/invalid/missing-subPages.yaml +0 -2
- package/api/schema-tests/FlowPageDefinition/valid/flow.yaml +0 -15
- package/api/schema-tests/PageDefinition/invalid/additional-properties.yaml +0 -5
- package/api/schema-tests/PageDefinition/invalid/missing-blocks.yaml +0 -1
- package/api/schema-tests/PageDefinition/invalid/missing-name.yaml +0 -3
- package/api/schema-tests/PageDefinition/valid/all-properties.yaml +0 -15
- package/api/schema-tests/PageDefinition/valid/minimal.yaml +0 -5
- package/api/schema-tests/TabsPageDefinition/invalid/missing-subPages.yaml +0 -2
- package/api/schema-tests/TabsPageDefinition/valid/tabs.yaml +0 -7
- package/api/tags/app.js.map +0 -1
- package/api/tags/app.ts +0 -6
- package/api/tags/appMember.js.map +0 -1
- package/api/tags/appMember.ts +0 -6
- package/api/tags/asset.js.map +0 -1
- package/api/tags/asset.ts +0 -6
- package/api/tags/auth.js.map +0 -1
- package/api/tags/auth.ts +0 -6
- package/api/tags/index.js.map +0 -1
- package/api/tags/index.ts +0 -9
- package/api/tags/language.js.map +0 -1
- package/api/tags/language.ts +0 -6
- package/api/tags/organization.js.map +0 -1
- package/api/tags/organization.ts +0 -6
- package/api/tags/resource.js.map +0 -1
- package/api/tags/resource.ts +0 -6
- package/api/tags/template.js.map +0 -1
- package/api/tags/template.ts +0 -6
- package/api/tags/user.js.map +0 -1
- package/api/tags/user.ts +0 -6
- package/appMessages.js.map +0 -1
- package/appMessages.test.js.map +0 -1
- package/appMessages.test.ts +0 -432
- package/appMessages.ts +0 -145
- package/appSecurity.js.map +0 -1
- package/appSecurity.test.js.map +0 -1
- package/appSecurity.test.ts +0 -141
- package/appSecurity.ts +0 -48
- package/blockUtils.js.map +0 -1
- package/blockUtils.test.js.map +0 -1
- package/blockUtils.test.ts +0 -94
- package/blockUtils.ts +0 -76
- package/changed/added/.gitkeep +0 -0
- package/changed/changed/.gitkeep +0 -0
- package/changed/deprecated/.gitkeep +0 -0
- package/changed/fixed/.gitkeep +0 -0
- package/changed/removed/.gitkeep +0 -0
- package/changed/security/.gitkeep +0 -0
- package/checkAppRole.js.map +0 -1
- package/checkAppRole.ts +0 -49
- package/compare.js.map +0 -1
- package/compare.ts +0 -10
- package/constants/Permission.js.map +0 -1
- package/constants/Permission.ts +0 -95
- package/constants/asciiLogo.js.map +0 -1
- package/constants/asciiLogo.ts +0 -8
- package/constants/baseTheme.js.map +0 -1
- package/constants/baseTheme.ts +0 -17
- package/constants/date.js.map +0 -1
- package/constants/date.ts +0 -20
- package/constants/fonts.js.map +0 -1
- package/constants/fonts.ts +0 -1291
- package/constants/index.js.map +0 -1
- package/constants/index.ts +0 -9
- package/constants/locale.js.map +0 -1
- package/constants/locale.ts +0 -4
- package/constants/patterns.js.map +0 -1
- package/constants/patterns.test.js.map +0 -1
- package/constants/patterns.test.ts +0 -100
- package/constants/patterns.ts +0 -48
- package/constants/roles.js.map +0 -1
- package/constants/roles.ts +0 -49
- package/constants/scopes.js.map +0 -1
- package/constants/scopes.ts +0 -13
- package/convertToCsv.js.map +0 -1
- package/convertToCsv.test.js.map +0 -1
- package/convertToCsv.test.ts +0 -73
- package/convertToCsv.ts +0 -65
- package/formatRequestAction.js.map +0 -1
- package/formatRequestAction.ts +0 -16
- package/has.js.map +0 -1
- package/has.test.js.map +0 -1
- package/has.test.ts +0 -19
- package/has.ts +0 -10
- package/i18n.js.map +0 -1
- package/i18n.test.js.map +0 -1
- package/i18n.test.ts +0 -81
- package/i18n.ts +0 -55
- package/ics.js.map +0 -1
- package/ics.ts +0 -44
- package/index.js.map +0 -1
- package/index.ts +0 -29
- package/intl-messageformat.js.map +0 -1
- package/intl-messageformat.ts +0 -6
- package/iterApp.js.map +0 -1
- package/iterApp.test.js.map +0 -1
- package/iterApp.test.ts +0 -512
- package/iterApp.ts +0 -174
- package/jest.config.js +0 -3
- package/jsonschema.js.map +0 -1
- package/jsonschema.test.js.map +0 -1
- package/jsonschema.test.ts +0 -320
- package/jsonschema.ts +0 -222
- package/langmap.js.map +0 -1
- package/langmap.ts +0 -23
- package/mapValues.js.map +0 -1
- package/mapValues.test.js.map +0 -1
- package/mapValues.test.ts +0 -15
- package/mapValues.ts +0 -10
- package/miscellaneous.js.map +0 -1
- package/miscellaneous.test.js.map +0 -1
- package/miscellaneous.test.ts +0 -82
- package/miscellaneous.ts +0 -71
- package/noop.js.map +0 -1
- package/noop.ts +0 -5
- package/normalize.js.map +0 -1
- package/normalize.test.js.map +0 -1
- package/normalize.test.ts +0 -24
- package/normalize.ts +0 -23
- package/objectCache.js.map +0 -1
- package/objectCache.test.js.map +0 -1
- package/objectCache.test.ts +0 -19
- package/objectCache.ts +0 -22
- package/pem.js.map +0 -1
- package/pem.ts +0 -11
- package/prefix.js.map +0 -1
- package/prefix.test.js.map +0 -1
- package/prefix.test.ts +0 -11
- package/prefix.ts +0 -10
- package/remap.js.map +0 -1
- package/remap.test.js.map +0 -1
- package/remap.test.ts +0 -1039
- package/remap.ts +0 -455
- package/string.js.map +0 -1
- package/string.test.js.map +0 -1
- package/string.test.ts +0 -29
- package/string.ts +0 -31
- package/theme.js.map +0 -1
- package/theme.test.js.map +0 -1
- package/theme.test.ts +0 -99
- package/theme.ts +0 -38
- package/tsconfig.json +0 -6
- package/types.js.map +0 -1
- package/types.ts +0 -6
- package/validateStyle.js.map +0 -1
- package/validateStyle.test.js.map +0 -1
- package/validateStyle.test.ts +0 -14
- package/validateStyle.ts +0 -19
- package/validation.js.map +0 -1
- package/validation.test.js.map +0 -1
- package/validation.test.ts +0 -1915
- package/validation.ts +0 -767
package/validation.test.ts
DELETED
|
@@ -1,1915 +0,0 @@
|
|
|
1
|
-
import { AppDefinition, BasicPageDefinition, FlowPageDefinition } from '@appsemble/types';
|
|
2
|
-
import { ValidationError } from 'jsonschema';
|
|
3
|
-
|
|
4
|
-
import { validateAppDefinition } from './validation.js';
|
|
5
|
-
|
|
6
|
-
function createTestApp(): AppDefinition {
|
|
7
|
-
return {
|
|
8
|
-
name: 'Test app',
|
|
9
|
-
defaultPage: 'Test Page',
|
|
10
|
-
security: {
|
|
11
|
-
default: { role: 'User' },
|
|
12
|
-
roles: { User: {} },
|
|
13
|
-
},
|
|
14
|
-
resources: {
|
|
15
|
-
person: {
|
|
16
|
-
update: {},
|
|
17
|
-
schema: {
|
|
18
|
-
type: 'object',
|
|
19
|
-
properties: {
|
|
20
|
-
name: { type: 'string' },
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
pages: [
|
|
26
|
-
{
|
|
27
|
-
name: 'Test Page',
|
|
28
|
-
blocks: [],
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
name: 'Page with parameters',
|
|
32
|
-
parameters: [],
|
|
33
|
-
blocks: [],
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
name: 'Page with tabs',
|
|
37
|
-
type: 'tabs',
|
|
38
|
-
tabs: [{ name: 'Tab A', blocks: [] }],
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
name: 'Page with steps',
|
|
42
|
-
type: 'flow',
|
|
43
|
-
steps: [
|
|
44
|
-
{ name: 'Step A', blocks: [] },
|
|
45
|
-
{ name: 'Step B', blocks: [] },
|
|
46
|
-
],
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
describe('validateAppDefinition', () => {
|
|
53
|
-
it('should report unknown block types', async () => {
|
|
54
|
-
const app = createTestApp();
|
|
55
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
56
|
-
type: 'test',
|
|
57
|
-
version: '1.2.3',
|
|
58
|
-
});
|
|
59
|
-
const result = await validateAppDefinition(app, () => []);
|
|
60
|
-
expect(result.valid).toBe(false);
|
|
61
|
-
expect(result.errors).toStrictEqual([
|
|
62
|
-
new ValidationError('is not a known block type', 'test', undefined, [
|
|
63
|
-
'pages',
|
|
64
|
-
0,
|
|
65
|
-
'blocks',
|
|
66
|
-
0,
|
|
67
|
-
'type',
|
|
68
|
-
]),
|
|
69
|
-
]);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should report unknown block versions', async () => {
|
|
73
|
-
const app = createTestApp();
|
|
74
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
75
|
-
type: 'test',
|
|
76
|
-
version: '1.2.3',
|
|
77
|
-
});
|
|
78
|
-
const result = await validateAppDefinition(app, () => [
|
|
79
|
-
{ name: '@appsemble/test', version: '0.0.0', files: [], languages: [] },
|
|
80
|
-
]);
|
|
81
|
-
expect(result.valid).toBe(false);
|
|
82
|
-
expect(result.errors).toStrictEqual([
|
|
83
|
-
new ValidationError('is not a known version for this block type', '1.2.3', undefined, [
|
|
84
|
-
'pages',
|
|
85
|
-
0,
|
|
86
|
-
'blocks',
|
|
87
|
-
0,
|
|
88
|
-
'version',
|
|
89
|
-
]),
|
|
90
|
-
]);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('should validate block parameters', async () => {
|
|
94
|
-
const app = createTestApp();
|
|
95
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
96
|
-
type: 'test',
|
|
97
|
-
version: '1.2.3',
|
|
98
|
-
parameters: {},
|
|
99
|
-
});
|
|
100
|
-
const result = await validateAppDefinition(app, () => [
|
|
101
|
-
{
|
|
102
|
-
name: '@appsemble/test',
|
|
103
|
-
version: '1.2.3',
|
|
104
|
-
files: [],
|
|
105
|
-
languages: [],
|
|
106
|
-
parameters: {
|
|
107
|
-
type: 'object',
|
|
108
|
-
required: ['foo'],
|
|
109
|
-
properties: { foo: { type: 'string' } },
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
]);
|
|
113
|
-
expect(result.valid).toBe(false);
|
|
114
|
-
expect(result.errors).toStrictEqual([
|
|
115
|
-
new ValidationError('requires property "foo"', {}, undefined, [
|
|
116
|
-
'pages',
|
|
117
|
-
0,
|
|
118
|
-
'blocks',
|
|
119
|
-
0,
|
|
120
|
-
'parameters',
|
|
121
|
-
]),
|
|
122
|
-
]);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('should validate missing block parameters', async () => {
|
|
126
|
-
const app = createTestApp();
|
|
127
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
128
|
-
type: 'test',
|
|
129
|
-
version: '1.2.3',
|
|
130
|
-
});
|
|
131
|
-
const result = await validateAppDefinition(app, () => [
|
|
132
|
-
{
|
|
133
|
-
name: '@appsemble/test',
|
|
134
|
-
version: '1.2.3',
|
|
135
|
-
files: [],
|
|
136
|
-
languages: [],
|
|
137
|
-
parameters: {
|
|
138
|
-
type: 'object',
|
|
139
|
-
required: ['foo'],
|
|
140
|
-
properties: { foo: { type: 'string' } },
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
]);
|
|
144
|
-
expect(result.valid).toBe(false);
|
|
145
|
-
expect(result.errors).toStrictEqual([
|
|
146
|
-
new ValidationError(
|
|
147
|
-
'requires property "parameters"',
|
|
148
|
-
{ type: 'test', version: '1.2.3' },
|
|
149
|
-
undefined,
|
|
150
|
-
['pages', 0, 'blocks', 0],
|
|
151
|
-
),
|
|
152
|
-
]);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it('should validate block parameters using the action format', async () => {
|
|
156
|
-
const app = createTestApp();
|
|
157
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
158
|
-
type: 'test',
|
|
159
|
-
version: '1.2.3',
|
|
160
|
-
parameters: {
|
|
161
|
-
foo: 'invalid',
|
|
162
|
-
bar: 'onClick',
|
|
163
|
-
},
|
|
164
|
-
actions: {
|
|
165
|
-
onClick: { type: 'noop' },
|
|
166
|
-
},
|
|
167
|
-
});
|
|
168
|
-
const result = await validateAppDefinition(app, () => [
|
|
169
|
-
{
|
|
170
|
-
name: '@appsemble/test',
|
|
171
|
-
version: '1.2.3',
|
|
172
|
-
files: [],
|
|
173
|
-
languages: [],
|
|
174
|
-
parameters: {
|
|
175
|
-
type: 'object',
|
|
176
|
-
properties: {
|
|
177
|
-
foo: { type: 'string', format: 'action' },
|
|
178
|
-
bar: { type: 'string', format: 'action' },
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
actions: {
|
|
182
|
-
onClick: {},
|
|
183
|
-
},
|
|
184
|
-
},
|
|
185
|
-
]);
|
|
186
|
-
expect(result.valid).toBe(false);
|
|
187
|
-
expect(result.errors).toStrictEqual([
|
|
188
|
-
new ValidationError('does not conform to the "action" format', 'invalid', undefined, [
|
|
189
|
-
'pages',
|
|
190
|
-
0,
|
|
191
|
-
'blocks',
|
|
192
|
-
0,
|
|
193
|
-
'parameters',
|
|
194
|
-
'foo',
|
|
195
|
-
]),
|
|
196
|
-
]);
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
it('should validate block parameters using the event-emitter format', async () => {
|
|
200
|
-
const app = createTestApp();
|
|
201
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
202
|
-
type: 'test',
|
|
203
|
-
version: '1.2.3',
|
|
204
|
-
parameters: {
|
|
205
|
-
foo: 'invalid',
|
|
206
|
-
bar: 'myEvent',
|
|
207
|
-
},
|
|
208
|
-
events: {
|
|
209
|
-
emit: { myEvent: 'handleEvent' },
|
|
210
|
-
listen: { myEvent: 'handleEvent' },
|
|
211
|
-
},
|
|
212
|
-
});
|
|
213
|
-
const result = await validateAppDefinition(app, () => [
|
|
214
|
-
{
|
|
215
|
-
name: '@appsemble/test',
|
|
216
|
-
version: '1.2.3',
|
|
217
|
-
files: [],
|
|
218
|
-
languages: [],
|
|
219
|
-
parameters: {
|
|
220
|
-
type: 'object',
|
|
221
|
-
properties: {
|
|
222
|
-
foo: { type: 'string', format: 'event-emitter' },
|
|
223
|
-
bar: { type: 'string', format: 'event-emitter' },
|
|
224
|
-
},
|
|
225
|
-
},
|
|
226
|
-
events: {
|
|
227
|
-
emit: { myEvent: {} },
|
|
228
|
-
listen: { myEvent: {} },
|
|
229
|
-
},
|
|
230
|
-
},
|
|
231
|
-
]);
|
|
232
|
-
expect(result.valid).toBe(false);
|
|
233
|
-
expect(result.errors).toStrictEqual([
|
|
234
|
-
new ValidationError('does not conform to the "event-emitter" format', 'invalid', undefined, [
|
|
235
|
-
'pages',
|
|
236
|
-
0,
|
|
237
|
-
'blocks',
|
|
238
|
-
0,
|
|
239
|
-
'parameters',
|
|
240
|
-
'foo',
|
|
241
|
-
]),
|
|
242
|
-
]);
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
it('should validate block parameters using the event-listener format', async () => {
|
|
246
|
-
const app = createTestApp();
|
|
247
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
248
|
-
type: 'test',
|
|
249
|
-
version: '1.2.3',
|
|
250
|
-
parameters: {
|
|
251
|
-
foo: 'invalid',
|
|
252
|
-
bar: 'myEvent',
|
|
253
|
-
},
|
|
254
|
-
events: {
|
|
255
|
-
emit: { myEvent: 'handleEvent' },
|
|
256
|
-
listen: { myEvent: 'handleEvent' },
|
|
257
|
-
},
|
|
258
|
-
});
|
|
259
|
-
const result = await validateAppDefinition(app, () => [
|
|
260
|
-
{
|
|
261
|
-
name: '@appsemble/test',
|
|
262
|
-
version: '1.2.3',
|
|
263
|
-
files: [],
|
|
264
|
-
languages: [],
|
|
265
|
-
parameters: {
|
|
266
|
-
type: 'object',
|
|
267
|
-
properties: {
|
|
268
|
-
foo: { type: 'string', format: 'event-listener' },
|
|
269
|
-
bar: { type: 'string', format: 'event-listener' },
|
|
270
|
-
},
|
|
271
|
-
},
|
|
272
|
-
events: {
|
|
273
|
-
emit: { myEvent: {} },
|
|
274
|
-
listen: { myEvent: {} },
|
|
275
|
-
},
|
|
276
|
-
},
|
|
277
|
-
]);
|
|
278
|
-
expect(result.valid).toBe(false);
|
|
279
|
-
expect(result.errors).toStrictEqual([
|
|
280
|
-
new ValidationError('does not conform to the "event-listener" format', 'invalid', undefined, [
|
|
281
|
-
'pages',
|
|
282
|
-
0,
|
|
283
|
-
'blocks',
|
|
284
|
-
0,
|
|
285
|
-
'parameters',
|
|
286
|
-
'foo',
|
|
287
|
-
]),
|
|
288
|
-
]);
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
it('should not allow block parameters if the block manifest doesn’t specify them', async () => {
|
|
292
|
-
const app = createTestApp();
|
|
293
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
294
|
-
type: 'test',
|
|
295
|
-
version: '1.2.3',
|
|
296
|
-
parameters: {},
|
|
297
|
-
});
|
|
298
|
-
const result = await validateAppDefinition(app, () => [
|
|
299
|
-
{
|
|
300
|
-
name: '@appsemble/test',
|
|
301
|
-
version: '1.2.3',
|
|
302
|
-
files: [],
|
|
303
|
-
languages: [],
|
|
304
|
-
},
|
|
305
|
-
]);
|
|
306
|
-
expect(result.valid).toBe(false);
|
|
307
|
-
expect(result.errors).toStrictEqual([
|
|
308
|
-
new ValidationError('is not allowed on this block type', {}, undefined, [
|
|
309
|
-
'pages',
|
|
310
|
-
0,
|
|
311
|
-
'blocks',
|
|
312
|
-
0,
|
|
313
|
-
'parameters',
|
|
314
|
-
]),
|
|
315
|
-
]);
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
it('should validate block actions', async () => {
|
|
319
|
-
const app = createTestApp();
|
|
320
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
321
|
-
type: 'test',
|
|
322
|
-
version: '1.2.3',
|
|
323
|
-
actions: {
|
|
324
|
-
onClick: { type: 'noop' },
|
|
325
|
-
onSubmit: { type: 'noop' },
|
|
326
|
-
},
|
|
327
|
-
});
|
|
328
|
-
const result = await validateAppDefinition(app, () => [
|
|
329
|
-
{
|
|
330
|
-
name: '@appsemble/test',
|
|
331
|
-
version: '1.2.3',
|
|
332
|
-
files: [],
|
|
333
|
-
languages: [],
|
|
334
|
-
actions: {
|
|
335
|
-
onClick: {},
|
|
336
|
-
},
|
|
337
|
-
},
|
|
338
|
-
]);
|
|
339
|
-
expect(result.valid).toBe(false);
|
|
340
|
-
expect(result.errors).toStrictEqual([
|
|
341
|
-
new ValidationError('is an unknown action for this block', { type: 'noop' }, undefined, [
|
|
342
|
-
'pages',
|
|
343
|
-
0,
|
|
344
|
-
'blocks',
|
|
345
|
-
0,
|
|
346
|
-
'actions',
|
|
347
|
-
'onSubmit',
|
|
348
|
-
]),
|
|
349
|
-
]);
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
it('should report if a block doesn’t support actions', async () => {
|
|
353
|
-
const app = createTestApp();
|
|
354
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
355
|
-
type: 'test',
|
|
356
|
-
version: '1.2.3',
|
|
357
|
-
actions: {},
|
|
358
|
-
});
|
|
359
|
-
const result = await validateAppDefinition(app, () => [
|
|
360
|
-
{
|
|
361
|
-
name: '@appsemble/test',
|
|
362
|
-
version: '1.2.3',
|
|
363
|
-
files: [],
|
|
364
|
-
languages: [],
|
|
365
|
-
},
|
|
366
|
-
]);
|
|
367
|
-
expect(result.valid).toBe(false);
|
|
368
|
-
expect(result.errors).toStrictEqual([
|
|
369
|
-
new ValidationError('is not allowed on this block', {}, undefined, [
|
|
370
|
-
'pages',
|
|
371
|
-
0,
|
|
372
|
-
'blocks',
|
|
373
|
-
0,
|
|
374
|
-
'actions',
|
|
375
|
-
]),
|
|
376
|
-
]);
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
it('should report unused block actions based on parameters', async () => {
|
|
380
|
-
const app = createTestApp();
|
|
381
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
382
|
-
type: 'test',
|
|
383
|
-
version: '1.2.3',
|
|
384
|
-
actions: {
|
|
385
|
-
foo: { type: 'noop' },
|
|
386
|
-
bar: { type: 'noop' },
|
|
387
|
-
},
|
|
388
|
-
parameters: {
|
|
389
|
-
onClick: 'foo',
|
|
390
|
-
},
|
|
391
|
-
});
|
|
392
|
-
const result = await validateAppDefinition(app, () => [
|
|
393
|
-
{
|
|
394
|
-
name: '@appsemble/test',
|
|
395
|
-
version: '1.2.3',
|
|
396
|
-
files: [],
|
|
397
|
-
languages: [],
|
|
398
|
-
actions: {
|
|
399
|
-
$any: {},
|
|
400
|
-
},
|
|
401
|
-
parameters: {
|
|
402
|
-
type: 'object',
|
|
403
|
-
properties: {
|
|
404
|
-
onClick: {
|
|
405
|
-
type: 'string',
|
|
406
|
-
format: 'action',
|
|
407
|
-
},
|
|
408
|
-
},
|
|
409
|
-
},
|
|
410
|
-
},
|
|
411
|
-
]);
|
|
412
|
-
expect(result.valid).toBe(false);
|
|
413
|
-
expect(result.errors).toStrictEqual([
|
|
414
|
-
new ValidationError('is unused', { type: 'noop' }, undefined, [
|
|
415
|
-
'pages',
|
|
416
|
-
0,
|
|
417
|
-
'blocks',
|
|
418
|
-
0,
|
|
419
|
-
'actions',
|
|
420
|
-
'bar',
|
|
421
|
-
]),
|
|
422
|
-
]);
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
it('should allow wildcard actions on blocks', async () => {
|
|
426
|
-
const app = createTestApp();
|
|
427
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
428
|
-
type: 'test',
|
|
429
|
-
version: '1.2.3',
|
|
430
|
-
actions: {
|
|
431
|
-
foo: { type: 'noop' },
|
|
432
|
-
bar: { type: 'noop' },
|
|
433
|
-
},
|
|
434
|
-
parameters: {
|
|
435
|
-
onClick: 'foo',
|
|
436
|
-
},
|
|
437
|
-
});
|
|
438
|
-
const result = await validateAppDefinition(app, () => [
|
|
439
|
-
{
|
|
440
|
-
name: '@appsemble/test',
|
|
441
|
-
version: '1.2.3',
|
|
442
|
-
files: [],
|
|
443
|
-
languages: [],
|
|
444
|
-
wildcardActions: true,
|
|
445
|
-
actions: {
|
|
446
|
-
$any: {},
|
|
447
|
-
},
|
|
448
|
-
parameters: {
|
|
449
|
-
type: 'object',
|
|
450
|
-
properties: {
|
|
451
|
-
onClick: {
|
|
452
|
-
type: 'string',
|
|
453
|
-
format: 'action',
|
|
454
|
-
},
|
|
455
|
-
},
|
|
456
|
-
},
|
|
457
|
-
},
|
|
458
|
-
]);
|
|
459
|
-
expect(result.valid).toBe(true);
|
|
460
|
-
});
|
|
461
|
-
|
|
462
|
-
it('should report unknown event emitters', async () => {
|
|
463
|
-
const app = createTestApp();
|
|
464
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
465
|
-
type: 'test',
|
|
466
|
-
version: '1.2.3',
|
|
467
|
-
events: {
|
|
468
|
-
emit: {
|
|
469
|
-
foo: 'bar',
|
|
470
|
-
},
|
|
471
|
-
listen: {
|
|
472
|
-
foo: 'bar',
|
|
473
|
-
},
|
|
474
|
-
},
|
|
475
|
-
});
|
|
476
|
-
const result = await validateAppDefinition(app, () => [
|
|
477
|
-
{
|
|
478
|
-
name: '@appsemble/test',
|
|
479
|
-
version: '1.2.3',
|
|
480
|
-
files: [],
|
|
481
|
-
languages: [],
|
|
482
|
-
wildcardActions: true,
|
|
483
|
-
events: {
|
|
484
|
-
emit: {},
|
|
485
|
-
listen: { $any: {} },
|
|
486
|
-
},
|
|
487
|
-
},
|
|
488
|
-
]);
|
|
489
|
-
expect(result.valid).toBe(false);
|
|
490
|
-
expect(result.errors).toStrictEqual([
|
|
491
|
-
new ValidationError('is an unknown event emitter', 'bar', undefined, [
|
|
492
|
-
'pages',
|
|
493
|
-
0,
|
|
494
|
-
'blocks',
|
|
495
|
-
0,
|
|
496
|
-
'events',
|
|
497
|
-
'emit',
|
|
498
|
-
'foo',
|
|
499
|
-
]),
|
|
500
|
-
]);
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
it('should allow $any matching unknown event emitters', async () => {
|
|
504
|
-
const app = createTestApp();
|
|
505
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
506
|
-
type: 'test',
|
|
507
|
-
version: '1.2.3',
|
|
508
|
-
events: {
|
|
509
|
-
emit: {
|
|
510
|
-
foo: 'bar',
|
|
511
|
-
},
|
|
512
|
-
listen: {
|
|
513
|
-
foo: 'bar',
|
|
514
|
-
},
|
|
515
|
-
},
|
|
516
|
-
});
|
|
517
|
-
const result = await validateAppDefinition(app, () => [
|
|
518
|
-
{
|
|
519
|
-
name: '@appsemble/test',
|
|
520
|
-
version: '1.2.3',
|
|
521
|
-
files: [],
|
|
522
|
-
languages: [],
|
|
523
|
-
wildcardActions: true,
|
|
524
|
-
events: {
|
|
525
|
-
emit: { $any: {} },
|
|
526
|
-
listen: { $any: {} },
|
|
527
|
-
},
|
|
528
|
-
},
|
|
529
|
-
]);
|
|
530
|
-
expect(result.valid).toBe(true);
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
it('should report unknown event listeners', async () => {
|
|
534
|
-
const app = createTestApp();
|
|
535
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
536
|
-
type: 'test',
|
|
537
|
-
version: '1.2.3',
|
|
538
|
-
events: {
|
|
539
|
-
listen: {
|
|
540
|
-
foo: 'bar',
|
|
541
|
-
},
|
|
542
|
-
emit: {
|
|
543
|
-
foo: 'bar',
|
|
544
|
-
},
|
|
545
|
-
},
|
|
546
|
-
});
|
|
547
|
-
const result = await validateAppDefinition(app, () => [
|
|
548
|
-
{
|
|
549
|
-
name: '@appsemble/test',
|
|
550
|
-
version: '1.2.3',
|
|
551
|
-
files: [],
|
|
552
|
-
languages: [],
|
|
553
|
-
wildcardActions: true,
|
|
554
|
-
events: {
|
|
555
|
-
listen: {},
|
|
556
|
-
emit: { $any: {} },
|
|
557
|
-
},
|
|
558
|
-
},
|
|
559
|
-
]);
|
|
560
|
-
expect(result.valid).toBe(false);
|
|
561
|
-
expect(result.errors).toStrictEqual([
|
|
562
|
-
new ValidationError('is an unknown event listener', 'bar', undefined, [
|
|
563
|
-
'pages',
|
|
564
|
-
0,
|
|
565
|
-
'blocks',
|
|
566
|
-
0,
|
|
567
|
-
'events',
|
|
568
|
-
'listen',
|
|
569
|
-
'foo',
|
|
570
|
-
]),
|
|
571
|
-
]);
|
|
572
|
-
});
|
|
573
|
-
|
|
574
|
-
it('should allow $any matching unknown event listener', async () => {
|
|
575
|
-
const app = createTestApp();
|
|
576
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
577
|
-
type: 'test',
|
|
578
|
-
version: '1.2.3',
|
|
579
|
-
events: {
|
|
580
|
-
emit: {
|
|
581
|
-
foo: 'bar',
|
|
582
|
-
},
|
|
583
|
-
listen: {
|
|
584
|
-
foo: 'bar',
|
|
585
|
-
},
|
|
586
|
-
},
|
|
587
|
-
});
|
|
588
|
-
const result = await validateAppDefinition(app, () => [
|
|
589
|
-
{
|
|
590
|
-
name: '@appsemble/test',
|
|
591
|
-
version: '1.2.3',
|
|
592
|
-
files: [],
|
|
593
|
-
languages: [],
|
|
594
|
-
wildcardActions: true,
|
|
595
|
-
events: {
|
|
596
|
-
emit: { foo: {} },
|
|
597
|
-
listen: { $any: {} },
|
|
598
|
-
},
|
|
599
|
-
},
|
|
600
|
-
]);
|
|
601
|
-
expect(result.valid).toBe(true);
|
|
602
|
-
});
|
|
603
|
-
|
|
604
|
-
it('should report unmatched event listeners', async () => {
|
|
605
|
-
const app = createTestApp();
|
|
606
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
607
|
-
type: 'test',
|
|
608
|
-
version: '1.2.3',
|
|
609
|
-
events: {
|
|
610
|
-
listen: {
|
|
611
|
-
foo: 'bar',
|
|
612
|
-
},
|
|
613
|
-
},
|
|
614
|
-
});
|
|
615
|
-
const result = await validateAppDefinition(app, () => [
|
|
616
|
-
{
|
|
617
|
-
name: '@appsemble/test',
|
|
618
|
-
version: '1.2.3',
|
|
619
|
-
files: [],
|
|
620
|
-
languages: [],
|
|
621
|
-
wildcardActions: true,
|
|
622
|
-
events: {
|
|
623
|
-
listen: { $any: {} },
|
|
624
|
-
},
|
|
625
|
-
},
|
|
626
|
-
]);
|
|
627
|
-
expect(result.valid).toBe(false);
|
|
628
|
-
expect(result.errors).toStrictEqual([
|
|
629
|
-
new ValidationError('does not match any event emitters', 'bar', undefined, [
|
|
630
|
-
'pages',
|
|
631
|
-
0,
|
|
632
|
-
'blocks',
|
|
633
|
-
0,
|
|
634
|
-
'events',
|
|
635
|
-
'listen',
|
|
636
|
-
'foo',
|
|
637
|
-
]),
|
|
638
|
-
]);
|
|
639
|
-
});
|
|
640
|
-
|
|
641
|
-
it('should report unmatched event emitters', async () => {
|
|
642
|
-
const app = createTestApp();
|
|
643
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
644
|
-
type: 'test',
|
|
645
|
-
version: '1.2.3',
|
|
646
|
-
events: {
|
|
647
|
-
emit: {
|
|
648
|
-
foo: 'bar',
|
|
649
|
-
},
|
|
650
|
-
},
|
|
651
|
-
});
|
|
652
|
-
const result = await validateAppDefinition(app, () => [
|
|
653
|
-
{
|
|
654
|
-
name: '@appsemble/test',
|
|
655
|
-
version: '1.2.3',
|
|
656
|
-
files: [],
|
|
657
|
-
languages: [],
|
|
658
|
-
wildcardActions: true,
|
|
659
|
-
events: {
|
|
660
|
-
emit: { $any: {} },
|
|
661
|
-
},
|
|
662
|
-
},
|
|
663
|
-
]);
|
|
664
|
-
expect(result.valid).toBe(false);
|
|
665
|
-
expect(result.errors).toStrictEqual([
|
|
666
|
-
new ValidationError('does not match any event listeners', 'bar', undefined, [
|
|
667
|
-
'pages',
|
|
668
|
-
0,
|
|
669
|
-
'blocks',
|
|
670
|
-
0,
|
|
671
|
-
'events',
|
|
672
|
-
'emit',
|
|
673
|
-
'foo',
|
|
674
|
-
]),
|
|
675
|
-
]);
|
|
676
|
-
});
|
|
677
|
-
|
|
678
|
-
it('should report unmatched event from event actions', async () => {
|
|
679
|
-
const app = createTestApp();
|
|
680
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
681
|
-
type: 'test',
|
|
682
|
-
version: '1.2.3',
|
|
683
|
-
actions: {
|
|
684
|
-
onClick: {
|
|
685
|
-
type: 'event',
|
|
686
|
-
event: 'sent',
|
|
687
|
-
waitFor: 'reply',
|
|
688
|
-
},
|
|
689
|
-
},
|
|
690
|
-
});
|
|
691
|
-
const result = await validateAppDefinition(app, () => [
|
|
692
|
-
{
|
|
693
|
-
name: '@appsemble/test',
|
|
694
|
-
version: '1.2.3',
|
|
695
|
-
files: [],
|
|
696
|
-
languages: [],
|
|
697
|
-
wildcardActions: true,
|
|
698
|
-
actions: {
|
|
699
|
-
onClick: {},
|
|
700
|
-
},
|
|
701
|
-
},
|
|
702
|
-
]);
|
|
703
|
-
expect(result.valid).toBe(false);
|
|
704
|
-
expect(result.errors).toStrictEqual([
|
|
705
|
-
new ValidationError('does not match any event emitters', 'reply', undefined, [
|
|
706
|
-
'pages',
|
|
707
|
-
0,
|
|
708
|
-
'blocks',
|
|
709
|
-
0,
|
|
710
|
-
'actions',
|
|
711
|
-
'onClick',
|
|
712
|
-
'waitFor',
|
|
713
|
-
]),
|
|
714
|
-
new ValidationError('does not match any event listeners', 'sent', undefined, [
|
|
715
|
-
'pages',
|
|
716
|
-
0,
|
|
717
|
-
'blocks',
|
|
718
|
-
0,
|
|
719
|
-
'actions',
|
|
720
|
-
'onClick',
|
|
721
|
-
'event',
|
|
722
|
-
]),
|
|
723
|
-
]);
|
|
724
|
-
});
|
|
725
|
-
|
|
726
|
-
it('should not crash if security is undefined', async () => {
|
|
727
|
-
const app = createTestApp();
|
|
728
|
-
delete app.security;
|
|
729
|
-
const result = await validateAppDefinition(app, () => []);
|
|
730
|
-
expect(result.valid).toBe(true);
|
|
731
|
-
});
|
|
732
|
-
|
|
733
|
-
it('should validate the default role exists', async () => {
|
|
734
|
-
const app = createTestApp();
|
|
735
|
-
app.security.default.role = 'Unknown';
|
|
736
|
-
const result = await validateAppDefinition(app, () => []);
|
|
737
|
-
expect(result.valid).toBe(false);
|
|
738
|
-
expect(result.errors).toStrictEqual([
|
|
739
|
-
new ValidationError('does not exist in this app’s roles', 'Unknown', undefined, [
|
|
740
|
-
'security',
|
|
741
|
-
'default',
|
|
742
|
-
'role',
|
|
743
|
-
]),
|
|
744
|
-
]);
|
|
745
|
-
});
|
|
746
|
-
|
|
747
|
-
it('should validate the top level default roles exist', async () => {
|
|
748
|
-
const app = createTestApp();
|
|
749
|
-
app.roles = ['Unknown'];
|
|
750
|
-
const result = await validateAppDefinition(app, () => []);
|
|
751
|
-
expect(result.valid).toBe(false);
|
|
752
|
-
expect(result.errors).toStrictEqual([
|
|
753
|
-
new ValidationError('does not exist in this app’s roles', 'Unknown', undefined, ['roles', 0]),
|
|
754
|
-
]);
|
|
755
|
-
});
|
|
756
|
-
|
|
757
|
-
it('should validate the resource roles exist', async () => {
|
|
758
|
-
const app = createTestApp();
|
|
759
|
-
app.resources.person.roles = ['Unknown'];
|
|
760
|
-
const result = await validateAppDefinition(app, () => []);
|
|
761
|
-
expect(result.valid).toBe(false);
|
|
762
|
-
expect(result.errors).toStrictEqual([
|
|
763
|
-
new ValidationError('does not exist in this app’s roles', 'Unknown', undefined, [
|
|
764
|
-
'resources',
|
|
765
|
-
'person',
|
|
766
|
-
'roles',
|
|
767
|
-
0,
|
|
768
|
-
]),
|
|
769
|
-
]);
|
|
770
|
-
});
|
|
771
|
-
|
|
772
|
-
it('should validate the resource action roles', async () => {
|
|
773
|
-
const app = createTestApp();
|
|
774
|
-
app.resources.person.count = { roles: ['Unknown'] };
|
|
775
|
-
app.resources.person.create = { roles: ['Unknown'] };
|
|
776
|
-
app.resources.person.delete = { roles: ['Unknown'] };
|
|
777
|
-
app.resources.person.get = { roles: ['Unknown'] };
|
|
778
|
-
app.resources.person.query = { roles: ['Unknown'] };
|
|
779
|
-
app.resources.person.update = { roles: ['Unknown'] };
|
|
780
|
-
const result = await validateAppDefinition(app, () => []);
|
|
781
|
-
expect(result.valid).toBe(false);
|
|
782
|
-
expect(result.errors).toStrictEqual([
|
|
783
|
-
new ValidationError('does not exist in this app’s roles', 'Unknown', undefined, [
|
|
784
|
-
'resources',
|
|
785
|
-
'person',
|
|
786
|
-
'count',
|
|
787
|
-
'roles',
|
|
788
|
-
0,
|
|
789
|
-
]),
|
|
790
|
-
new ValidationError('does not exist in this app’s roles', 'Unknown', undefined, [
|
|
791
|
-
'resources',
|
|
792
|
-
'person',
|
|
793
|
-
'create',
|
|
794
|
-
'roles',
|
|
795
|
-
0,
|
|
796
|
-
]),
|
|
797
|
-
new ValidationError('does not exist in this app’s roles', 'Unknown', undefined, [
|
|
798
|
-
'resources',
|
|
799
|
-
'person',
|
|
800
|
-
'delete',
|
|
801
|
-
'roles',
|
|
802
|
-
0,
|
|
803
|
-
]),
|
|
804
|
-
new ValidationError('does not exist in this app’s roles', 'Unknown', undefined, [
|
|
805
|
-
'resources',
|
|
806
|
-
'person',
|
|
807
|
-
'get',
|
|
808
|
-
'roles',
|
|
809
|
-
0,
|
|
810
|
-
]),
|
|
811
|
-
new ValidationError('does not exist in this app’s roles', 'Unknown', undefined, [
|
|
812
|
-
'resources',
|
|
813
|
-
'person',
|
|
814
|
-
'query',
|
|
815
|
-
'roles',
|
|
816
|
-
0,
|
|
817
|
-
]),
|
|
818
|
-
new ValidationError('does not exist in this app’s roles', 'Unknown', undefined, [
|
|
819
|
-
'resources',
|
|
820
|
-
'person',
|
|
821
|
-
'update',
|
|
822
|
-
'roles',
|
|
823
|
-
0,
|
|
824
|
-
]),
|
|
825
|
-
]);
|
|
826
|
-
});
|
|
827
|
-
|
|
828
|
-
it('should validate resources use schemas define a type', async () => {
|
|
829
|
-
const app = createTestApp();
|
|
830
|
-
app.resources.person.schema = { properties: {} };
|
|
831
|
-
const result = await validateAppDefinition(app, () => []);
|
|
832
|
-
expect(result.valid).toBe(false);
|
|
833
|
-
expect(result.errors).toStrictEqual([
|
|
834
|
-
new ValidationError('must define type object', { properties: {} }, undefined, [
|
|
835
|
-
'resources',
|
|
836
|
-
'person',
|
|
837
|
-
'schema',
|
|
838
|
-
]),
|
|
839
|
-
]);
|
|
840
|
-
});
|
|
841
|
-
|
|
842
|
-
it('should validate resources use schemas define a type of object', async () => {
|
|
843
|
-
const app = createTestApp();
|
|
844
|
-
app.resources.person.schema = { type: 'string', properties: {} };
|
|
845
|
-
const result = await validateAppDefinition(app, () => []);
|
|
846
|
-
expect(result.valid).toBe(false);
|
|
847
|
-
expect(result.errors).toStrictEqual([
|
|
848
|
-
new ValidationError('must define type object', 'string', undefined, [
|
|
849
|
-
'resources',
|
|
850
|
-
'person',
|
|
851
|
-
'schema',
|
|
852
|
-
'type',
|
|
853
|
-
]),
|
|
854
|
-
]);
|
|
855
|
-
});
|
|
856
|
-
|
|
857
|
-
it('should validate the resource id schema is correct', async () => {
|
|
858
|
-
const app = createTestApp();
|
|
859
|
-
app.resources.person.schema = {
|
|
860
|
-
type: 'object',
|
|
861
|
-
properties: { id: { type: 'string', description: '', title: '', format: 'email' } },
|
|
862
|
-
};
|
|
863
|
-
const result = await validateAppDefinition(app, () => []);
|
|
864
|
-
expect(result.valid).toBe(false);
|
|
865
|
-
expect(result.errors).toStrictEqual([
|
|
866
|
-
new ValidationError('must be integer', 'string', undefined, [
|
|
867
|
-
'resources',
|
|
868
|
-
'person',
|
|
869
|
-
'schema',
|
|
870
|
-
'properties',
|
|
871
|
-
'id',
|
|
872
|
-
'type',
|
|
873
|
-
]),
|
|
874
|
-
new ValidationError('does not support custom validators', 'email', undefined, [
|
|
875
|
-
'resources',
|
|
876
|
-
'person',
|
|
877
|
-
'schema',
|
|
878
|
-
'properties',
|
|
879
|
-
'id',
|
|
880
|
-
'format',
|
|
881
|
-
]),
|
|
882
|
-
]);
|
|
883
|
-
});
|
|
884
|
-
|
|
885
|
-
it('should validate the resource $created and $updated schemas are correct', async () => {
|
|
886
|
-
const app = createTestApp();
|
|
887
|
-
app.resources.person.schema = {
|
|
888
|
-
type: 'object',
|
|
889
|
-
properties: {
|
|
890
|
-
$created: { type: 'number', description: '', title: '', format: 'email' },
|
|
891
|
-
$updated: { type: 'boolean', description: '', title: '', format: 'uuid' },
|
|
892
|
-
},
|
|
893
|
-
};
|
|
894
|
-
const result = await validateAppDefinition(app, () => []);
|
|
895
|
-
expect(result.valid).toBe(false);
|
|
896
|
-
expect(result.errors).toStrictEqual([
|
|
897
|
-
new ValidationError('must be string', 'number', undefined, [
|
|
898
|
-
'resources',
|
|
899
|
-
'person',
|
|
900
|
-
'schema',
|
|
901
|
-
'properties',
|
|
902
|
-
'$created',
|
|
903
|
-
'type',
|
|
904
|
-
]),
|
|
905
|
-
new ValidationError('must be date-time', 'email', undefined, [
|
|
906
|
-
'resources',
|
|
907
|
-
'person',
|
|
908
|
-
'schema',
|
|
909
|
-
'properties',
|
|
910
|
-
'$created',
|
|
911
|
-
'format',
|
|
912
|
-
]),
|
|
913
|
-
new ValidationError('must be string', 'boolean', undefined, [
|
|
914
|
-
'resources',
|
|
915
|
-
'person',
|
|
916
|
-
'schema',
|
|
917
|
-
'properties',
|
|
918
|
-
'$updated',
|
|
919
|
-
'type',
|
|
920
|
-
]),
|
|
921
|
-
new ValidationError('must be date-time', 'uuid', undefined, [
|
|
922
|
-
'resources',
|
|
923
|
-
'person',
|
|
924
|
-
'schema',
|
|
925
|
-
'properties',
|
|
926
|
-
'$updated',
|
|
927
|
-
'format',
|
|
928
|
-
]),
|
|
929
|
-
]);
|
|
930
|
-
});
|
|
931
|
-
|
|
932
|
-
it('should report resource properties starting with $', async () => {
|
|
933
|
-
const app = createTestApp();
|
|
934
|
-
app.resources.person.schema = {
|
|
935
|
-
type: 'object',
|
|
936
|
-
properties: { $invalid: { type: 'string' } },
|
|
937
|
-
};
|
|
938
|
-
const result = await validateAppDefinition(app, () => []);
|
|
939
|
-
expect(result.valid).toBe(false);
|
|
940
|
-
expect(result.errors).toStrictEqual([
|
|
941
|
-
new ValidationError('may not start with $', { type: 'string' }, undefined, [
|
|
942
|
-
'resources',
|
|
943
|
-
'person',
|
|
944
|
-
'schema',
|
|
945
|
-
'properties',
|
|
946
|
-
'$invalid',
|
|
947
|
-
]),
|
|
948
|
-
]);
|
|
949
|
-
});
|
|
950
|
-
|
|
951
|
-
it('should report missing properties in JSON schemas', async () => {
|
|
952
|
-
const app = createTestApp();
|
|
953
|
-
app.resources.person.schema = { type: 'object' };
|
|
954
|
-
const result = await validateAppDefinition(app, () => []);
|
|
955
|
-
expect(result.valid).toBe(false);
|
|
956
|
-
expect(result.errors).toStrictEqual([
|
|
957
|
-
new ValidationError('is missing properties', { type: 'object' }, undefined, [
|
|
958
|
-
'resources',
|
|
959
|
-
'person',
|
|
960
|
-
'schema',
|
|
961
|
-
]),
|
|
962
|
-
]);
|
|
963
|
-
});
|
|
964
|
-
|
|
965
|
-
it('should report missing properties in JSON schemas resursively', async () => {
|
|
966
|
-
const app = createTestApp();
|
|
967
|
-
app.resources.person.schema = {
|
|
968
|
-
type: 'object',
|
|
969
|
-
properties: { foo: { type: 'object' } },
|
|
970
|
-
};
|
|
971
|
-
const result = await validateAppDefinition(app, () => []);
|
|
972
|
-
expect(result.valid).toBe(false);
|
|
973
|
-
expect(result.errors).toStrictEqual([
|
|
974
|
-
new ValidationError('is missing properties', { type: 'object' }, undefined, [
|
|
975
|
-
'resources',
|
|
976
|
-
'person',
|
|
977
|
-
'schema',
|
|
978
|
-
'properties',
|
|
979
|
-
'foo',
|
|
980
|
-
]),
|
|
981
|
-
]);
|
|
982
|
-
});
|
|
983
|
-
|
|
984
|
-
it('should report unknown required properties in JSON schemas', async () => {
|
|
985
|
-
const app = createTestApp();
|
|
986
|
-
app.resources.person.schema = {
|
|
987
|
-
type: 'object',
|
|
988
|
-
required: ['bar'],
|
|
989
|
-
properties: { foo: { type: 'object', properties: {}, required: ['baz'] } },
|
|
990
|
-
};
|
|
991
|
-
const result = await validateAppDefinition(app, () => []);
|
|
992
|
-
expect(result.valid).toBe(false);
|
|
993
|
-
expect(result.errors).toStrictEqual([
|
|
994
|
-
new ValidationError('is not defined in properties', 'bar', undefined, [
|
|
995
|
-
'resources',
|
|
996
|
-
'person',
|
|
997
|
-
'schema',
|
|
998
|
-
'required',
|
|
999
|
-
0,
|
|
1000
|
-
]),
|
|
1001
|
-
new ValidationError('is not defined in properties', 'baz', undefined, [
|
|
1002
|
-
'resources',
|
|
1003
|
-
'person',
|
|
1004
|
-
'schema',
|
|
1005
|
-
'properties',
|
|
1006
|
-
'foo',
|
|
1007
|
-
'required',
|
|
1008
|
-
0,
|
|
1009
|
-
]),
|
|
1010
|
-
]);
|
|
1011
|
-
});
|
|
1012
|
-
|
|
1013
|
-
it('should allow the $author role for resource actions', async () => {
|
|
1014
|
-
const app = createTestApp();
|
|
1015
|
-
app.resources.person.roles = ['$author'];
|
|
1016
|
-
app.resources.person.count = { roles: ['$author'] };
|
|
1017
|
-
app.resources.person.create = { roles: ['$author'] };
|
|
1018
|
-
app.resources.person.delete = { roles: ['$author'] };
|
|
1019
|
-
app.resources.person.get = { roles: ['$author'] };
|
|
1020
|
-
app.resources.person.query = { roles: ['$author'] };
|
|
1021
|
-
app.resources.person.update = { roles: ['$author'] };
|
|
1022
|
-
const result = await validateAppDefinition(app, () => []);
|
|
1023
|
-
expect(result.valid).toBe(false);
|
|
1024
|
-
expect(result.errors).toStrictEqual([
|
|
1025
|
-
new ValidationError('does not exist in this app’s roles', '$author', undefined, [
|
|
1026
|
-
'resources',
|
|
1027
|
-
'person',
|
|
1028
|
-
'create',
|
|
1029
|
-
'roles',
|
|
1030
|
-
0,
|
|
1031
|
-
]),
|
|
1032
|
-
]);
|
|
1033
|
-
});
|
|
1034
|
-
|
|
1035
|
-
it('should validate page roles', async () => {
|
|
1036
|
-
const app = createTestApp();
|
|
1037
|
-
app.pages[0].roles = ['Unknown'];
|
|
1038
|
-
const result = await validateAppDefinition(app, () => []);
|
|
1039
|
-
expect(result.valid).toBe(false);
|
|
1040
|
-
expect(result.errors).toStrictEqual([
|
|
1041
|
-
new ValidationError('does not exist in this app’s roles', 'Unknown', undefined, [
|
|
1042
|
-
'pages',
|
|
1043
|
-
0,
|
|
1044
|
-
'roles',
|
|
1045
|
-
0,
|
|
1046
|
-
]),
|
|
1047
|
-
]);
|
|
1048
|
-
});
|
|
1049
|
-
|
|
1050
|
-
it('should validate block roles', async () => {
|
|
1051
|
-
const app = createTestApp();
|
|
1052
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
1053
|
-
type: 'test',
|
|
1054
|
-
version: '1.2.3',
|
|
1055
|
-
roles: ['Unknown'],
|
|
1056
|
-
});
|
|
1057
|
-
const result = await validateAppDefinition(app, () => [
|
|
1058
|
-
{ name: '@appsemble/test', version: '1.2.3', files: [], languages: [] },
|
|
1059
|
-
]);
|
|
1060
|
-
expect(result.valid).toBe(false);
|
|
1061
|
-
expect(result.errors).toStrictEqual([
|
|
1062
|
-
new ValidationError('does not exist in this app’s roles', 'Unknown', undefined, [
|
|
1063
|
-
'pages',
|
|
1064
|
-
0,
|
|
1065
|
-
'blocks',
|
|
1066
|
-
0,
|
|
1067
|
-
'roles',
|
|
1068
|
-
0,
|
|
1069
|
-
]),
|
|
1070
|
-
]);
|
|
1071
|
-
});
|
|
1072
|
-
|
|
1073
|
-
it('should validate inherited roles', async () => {
|
|
1074
|
-
const app = createTestApp();
|
|
1075
|
-
app.security.roles.User.inherits = ['Unknown'];
|
|
1076
|
-
const result = await validateAppDefinition(app, () => []);
|
|
1077
|
-
expect(result.valid).toBe(false);
|
|
1078
|
-
expect(result.errors).toStrictEqual([
|
|
1079
|
-
new ValidationError('does not exist in this app’s roles', 'Unknown', undefined, [
|
|
1080
|
-
'security',
|
|
1081
|
-
'roles',
|
|
1082
|
-
'User',
|
|
1083
|
-
'inherits',
|
|
1084
|
-
0,
|
|
1085
|
-
]),
|
|
1086
|
-
]);
|
|
1087
|
-
});
|
|
1088
|
-
|
|
1089
|
-
it('should report cyclic role inheritance', async () => {
|
|
1090
|
-
const app = createTestApp();
|
|
1091
|
-
app.security.roles.A = { inherits: ['B'] };
|
|
1092
|
-
app.security.roles.B = { inherits: ['C'] };
|
|
1093
|
-
app.security.roles.C = { inherits: ['E', 'A'] };
|
|
1094
|
-
app.security.roles.D = { inherits: ['A'] };
|
|
1095
|
-
app.security.roles.E = {};
|
|
1096
|
-
const result = await validateAppDefinition(app, () => []);
|
|
1097
|
-
expect(result.valid).toBe(false);
|
|
1098
|
-
expect(result.errors).toStrictEqual([
|
|
1099
|
-
new ValidationError('cyclicly inherits itself', { inherits: ['B'] }, undefined, [
|
|
1100
|
-
'security',
|
|
1101
|
-
'roles',
|
|
1102
|
-
'A',
|
|
1103
|
-
]),
|
|
1104
|
-
new ValidationError('cyclicly inherits itself', { inherits: ['C'] }, undefined, [
|
|
1105
|
-
'security',
|
|
1106
|
-
'roles',
|
|
1107
|
-
'B',
|
|
1108
|
-
]),
|
|
1109
|
-
new ValidationError('cyclicly inherits itself', { inherits: ['E', 'A'] }, undefined, [
|
|
1110
|
-
'security',
|
|
1111
|
-
'roles',
|
|
1112
|
-
'C',
|
|
1113
|
-
]),
|
|
1114
|
-
]);
|
|
1115
|
-
});
|
|
1116
|
-
|
|
1117
|
-
it('should report unknown roles in resource notification hooks', async () => {
|
|
1118
|
-
const app = createTestApp();
|
|
1119
|
-
app.resources.person.update.hooks = {
|
|
1120
|
-
notification: {
|
|
1121
|
-
to: ['Unknown'],
|
|
1122
|
-
},
|
|
1123
|
-
};
|
|
1124
|
-
const result = await validateAppDefinition(app, () => []);
|
|
1125
|
-
expect(result.valid).toBe(false);
|
|
1126
|
-
expect(result.errors).toStrictEqual([
|
|
1127
|
-
new ValidationError('is an unknown role', 'Unknown', undefined, [
|
|
1128
|
-
'resources',
|
|
1129
|
-
'person',
|
|
1130
|
-
'update',
|
|
1131
|
-
'hooks',
|
|
1132
|
-
'notifications',
|
|
1133
|
-
'to',
|
|
1134
|
-
0,
|
|
1135
|
-
]),
|
|
1136
|
-
]);
|
|
1137
|
-
});
|
|
1138
|
-
|
|
1139
|
-
it('should allow $author in resource notification hooks', async () => {
|
|
1140
|
-
const app = createTestApp();
|
|
1141
|
-
app.resources.person.update.hooks = {
|
|
1142
|
-
notification: {
|
|
1143
|
-
to: ['$author'],
|
|
1144
|
-
},
|
|
1145
|
-
};
|
|
1146
|
-
const result = await validateAppDefinition(app, () => []);
|
|
1147
|
-
expect(result.valid).toBe(true);
|
|
1148
|
-
});
|
|
1149
|
-
|
|
1150
|
-
it('should report invalid resource references', async () => {
|
|
1151
|
-
const app = createTestApp();
|
|
1152
|
-
app.resources.person.references = {
|
|
1153
|
-
name: {
|
|
1154
|
-
resource: 'non-existent',
|
|
1155
|
-
},
|
|
1156
|
-
};
|
|
1157
|
-
const result = await validateAppDefinition(app, () => []);
|
|
1158
|
-
expect(result.valid).toBe(false);
|
|
1159
|
-
expect(result.errors).toStrictEqual([
|
|
1160
|
-
new ValidationError('is not an existing resource', 'non-existent', undefined, [
|
|
1161
|
-
'resources',
|
|
1162
|
-
'person',
|
|
1163
|
-
'references',
|
|
1164
|
-
'name',
|
|
1165
|
-
'resource',
|
|
1166
|
-
]),
|
|
1167
|
-
]);
|
|
1168
|
-
});
|
|
1169
|
-
|
|
1170
|
-
it('should report invalid resource reference fields', async () => {
|
|
1171
|
-
const app = createTestApp();
|
|
1172
|
-
app.resources.person.references = {
|
|
1173
|
-
invalid: {
|
|
1174
|
-
resource: 'person',
|
|
1175
|
-
},
|
|
1176
|
-
};
|
|
1177
|
-
const result = await validateAppDefinition(app, () => []);
|
|
1178
|
-
expect(result.valid).toBe(false);
|
|
1179
|
-
expect(result.errors).toStrictEqual([
|
|
1180
|
-
new ValidationError('does not exist on this resource', 'invalid', undefined, [
|
|
1181
|
-
'resources',
|
|
1182
|
-
'person',
|
|
1183
|
-
'references',
|
|
1184
|
-
'invalid',
|
|
1185
|
-
]),
|
|
1186
|
-
]);
|
|
1187
|
-
});
|
|
1188
|
-
|
|
1189
|
-
it('should not report valid resource references', async () => {
|
|
1190
|
-
const app = createTestApp();
|
|
1191
|
-
app.resources.person.references = {
|
|
1192
|
-
name: {
|
|
1193
|
-
resource: 'person',
|
|
1194
|
-
},
|
|
1195
|
-
};
|
|
1196
|
-
const result = await validateAppDefinition(app, () => []);
|
|
1197
|
-
expect(result.valid).toBe(true);
|
|
1198
|
-
});
|
|
1199
|
-
|
|
1200
|
-
it('should not crash if not resources exist', async () => {
|
|
1201
|
-
const result = await validateAppDefinition(
|
|
1202
|
-
{ ...createTestApp(), resources: undefined },
|
|
1203
|
-
() => [],
|
|
1204
|
-
);
|
|
1205
|
-
expect(result.valid).toBe(true);
|
|
1206
|
-
});
|
|
1207
|
-
|
|
1208
|
-
it('should report an invalid default language', async () => {
|
|
1209
|
-
const result = await validateAppDefinition(
|
|
1210
|
-
{ ...createTestApp(), defaultLanguage: 'Klingon' },
|
|
1211
|
-
() => [],
|
|
1212
|
-
);
|
|
1213
|
-
expect(result.valid).toBe(false);
|
|
1214
|
-
expect(result.errors).toStrictEqual([
|
|
1215
|
-
new ValidationError('is not a valid language code', 'Klingon', undefined, [
|
|
1216
|
-
'defaultLanguage',
|
|
1217
|
-
]),
|
|
1218
|
-
]);
|
|
1219
|
-
});
|
|
1220
|
-
|
|
1221
|
-
it('should allow a valid default language', async () => {
|
|
1222
|
-
const result = await validateAppDefinition(
|
|
1223
|
-
{ ...createTestApp(), defaultLanguage: 'kln' },
|
|
1224
|
-
() => [],
|
|
1225
|
-
);
|
|
1226
|
-
expect(result.valid).toBe(true);
|
|
1227
|
-
expect(result.errors).toStrictEqual([]);
|
|
1228
|
-
});
|
|
1229
|
-
|
|
1230
|
-
it('should validate the default page exists', async () => {
|
|
1231
|
-
const result = await validateAppDefinition(
|
|
1232
|
-
{ ...createTestApp(), defaultPage: 'Does not exist' },
|
|
1233
|
-
() => [],
|
|
1234
|
-
);
|
|
1235
|
-
expect(result.valid).toBe(false);
|
|
1236
|
-
expect(result.errors).toStrictEqual([
|
|
1237
|
-
new ValidationError('does not refer to an existing page', 'Does not exist', undefined, [
|
|
1238
|
-
'defaultPage',
|
|
1239
|
-
]),
|
|
1240
|
-
]);
|
|
1241
|
-
});
|
|
1242
|
-
|
|
1243
|
-
it('should validate the default page doesn’t specify parameters', async () => {
|
|
1244
|
-
const result = await validateAppDefinition(
|
|
1245
|
-
{ ...createTestApp(), defaultPage: 'Page with parameters' },
|
|
1246
|
-
() => [],
|
|
1247
|
-
);
|
|
1248
|
-
expect(result.valid).toBe(false);
|
|
1249
|
-
expect(result.errors).toStrictEqual([
|
|
1250
|
-
new ValidationError('may not specify parameters', 'Page with parameters', undefined, [
|
|
1251
|
-
'defaultPage',
|
|
1252
|
-
]),
|
|
1253
|
-
]);
|
|
1254
|
-
});
|
|
1255
|
-
|
|
1256
|
-
it('should report invalid cronjob schedule syntax', async () => {
|
|
1257
|
-
const result = await validateAppDefinition(
|
|
1258
|
-
{
|
|
1259
|
-
...createTestApp(),
|
|
1260
|
-
cron: { foo: { schedule: 'invalid cronjob test', action: { type: 'noop' } } },
|
|
1261
|
-
},
|
|
1262
|
-
() => [],
|
|
1263
|
-
);
|
|
1264
|
-
expect(result.valid).toBe(false);
|
|
1265
|
-
expect(result.errors).toStrictEqual([
|
|
1266
|
-
new ValidationError('contains an invalid expression', 'invalid cronjob test', undefined, [
|
|
1267
|
-
'cron',
|
|
1268
|
-
'foo',
|
|
1269
|
-
'schedule',
|
|
1270
|
-
]),
|
|
1271
|
-
]);
|
|
1272
|
-
});
|
|
1273
|
-
|
|
1274
|
-
it('should allow valid cronjob schedule syntax', async () => {
|
|
1275
|
-
const result = await validateAppDefinition(
|
|
1276
|
-
{ ...createTestApp(), cron: { foo: { schedule: '5 4 * * *', action: { type: 'noop' } } } },
|
|
1277
|
-
() => [],
|
|
1278
|
-
);
|
|
1279
|
-
expect(result.valid).toBe(true);
|
|
1280
|
-
expect(result.errors).toStrictEqual([]);
|
|
1281
|
-
});
|
|
1282
|
-
|
|
1283
|
-
it('should not crash if cron is not a valid object', async () => {
|
|
1284
|
-
const result = await validateAppDefinition(
|
|
1285
|
-
// @ts-expect-error This tests invalid user input.
|
|
1286
|
-
{ ...createTestApp(), cron: { foo: null, bar: { schedule: 12 } } },
|
|
1287
|
-
() => [],
|
|
1288
|
-
);
|
|
1289
|
-
expect(result.valid).toBe(true);
|
|
1290
|
-
expect(result.errors).toStrictEqual([]);
|
|
1291
|
-
});
|
|
1292
|
-
|
|
1293
|
-
it('should report an error if a link action contains a link to a page that doesn’t exist', async () => {
|
|
1294
|
-
const app = createTestApp();
|
|
1295
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
1296
|
-
type: 'test',
|
|
1297
|
-
version: '1.2.3',
|
|
1298
|
-
actions: {
|
|
1299
|
-
onWhatever: {
|
|
1300
|
-
type: 'link',
|
|
1301
|
-
to: 'Doesn’t exist',
|
|
1302
|
-
},
|
|
1303
|
-
},
|
|
1304
|
-
});
|
|
1305
|
-
const result = await validateAppDefinition(app, () => [
|
|
1306
|
-
{
|
|
1307
|
-
name: '@appsemble/test',
|
|
1308
|
-
version: '1.2.3',
|
|
1309
|
-
files: [],
|
|
1310
|
-
languages: [],
|
|
1311
|
-
actions: {
|
|
1312
|
-
onWhatever: {},
|
|
1313
|
-
},
|
|
1314
|
-
},
|
|
1315
|
-
]);
|
|
1316
|
-
expect(result.valid).toBe(false);
|
|
1317
|
-
expect(result.errors).toStrictEqual([
|
|
1318
|
-
new ValidationError('refers to a page that doesn’t exist', 'Doesn’t exist', undefined, [
|
|
1319
|
-
'pages',
|
|
1320
|
-
0,
|
|
1321
|
-
'blocks',
|
|
1322
|
-
0,
|
|
1323
|
-
'actions',
|
|
1324
|
-
'onWhatever',
|
|
1325
|
-
'to',
|
|
1326
|
-
]),
|
|
1327
|
-
]);
|
|
1328
|
-
});
|
|
1329
|
-
|
|
1330
|
-
it('should report an error if a link action contains a link to a sub page for a page without sub pages', async () => {
|
|
1331
|
-
const app = createTestApp();
|
|
1332
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
1333
|
-
type: 'test',
|
|
1334
|
-
version: '1.2.3',
|
|
1335
|
-
actions: {
|
|
1336
|
-
onWhatever: {
|
|
1337
|
-
type: 'link',
|
|
1338
|
-
to: ['Test Page', 'Bla'],
|
|
1339
|
-
},
|
|
1340
|
-
},
|
|
1341
|
-
});
|
|
1342
|
-
const result = await validateAppDefinition(app, () => [
|
|
1343
|
-
{
|
|
1344
|
-
name: '@appsemble/test',
|
|
1345
|
-
version: '1.2.3',
|
|
1346
|
-
files: [],
|
|
1347
|
-
languages: [],
|
|
1348
|
-
actions: {
|
|
1349
|
-
onWhatever: {},
|
|
1350
|
-
},
|
|
1351
|
-
},
|
|
1352
|
-
]);
|
|
1353
|
-
expect(result.valid).toBe(false);
|
|
1354
|
-
expect(result.errors).toStrictEqual([
|
|
1355
|
-
new ValidationError(
|
|
1356
|
-
'refers to a sub page on a page that isn’t of type ‘tabs’ or ‘flow’',
|
|
1357
|
-
'Bla',
|
|
1358
|
-
undefined,
|
|
1359
|
-
['pages', 0, 'blocks', 0, 'actions', 'onWhatever', 'to', 1],
|
|
1360
|
-
),
|
|
1361
|
-
]);
|
|
1362
|
-
});
|
|
1363
|
-
|
|
1364
|
-
it('should report an error if a link action contains a link to a tab that doesn’t exist', async () => {
|
|
1365
|
-
const app = createTestApp();
|
|
1366
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
1367
|
-
type: 'test',
|
|
1368
|
-
version: '1.2.3',
|
|
1369
|
-
actions: {
|
|
1370
|
-
onWhatever: {
|
|
1371
|
-
type: 'link',
|
|
1372
|
-
to: ['Page with tabs', 'Bla'],
|
|
1373
|
-
},
|
|
1374
|
-
},
|
|
1375
|
-
});
|
|
1376
|
-
const result = await validateAppDefinition(app, () => [
|
|
1377
|
-
{
|
|
1378
|
-
name: '@appsemble/test',
|
|
1379
|
-
version: '1.2.3',
|
|
1380
|
-
files: [],
|
|
1381
|
-
languages: [],
|
|
1382
|
-
actions: {
|
|
1383
|
-
onWhatever: {},
|
|
1384
|
-
},
|
|
1385
|
-
},
|
|
1386
|
-
]);
|
|
1387
|
-
expect(result.valid).toBe(false);
|
|
1388
|
-
expect(result.errors).toStrictEqual([
|
|
1389
|
-
new ValidationError('refers to a tab that doesn’t exist', 'Bla', undefined, [
|
|
1390
|
-
'pages',
|
|
1391
|
-
0,
|
|
1392
|
-
'blocks',
|
|
1393
|
-
0,
|
|
1394
|
-
'actions',
|
|
1395
|
-
'onWhatever',
|
|
1396
|
-
'to',
|
|
1397
|
-
1,
|
|
1398
|
-
]),
|
|
1399
|
-
]);
|
|
1400
|
-
});
|
|
1401
|
-
|
|
1402
|
-
it('should report an error if user actions are used without a security definition', async () => {
|
|
1403
|
-
const { security, ...app } = createTestApp();
|
|
1404
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
1405
|
-
type: 'test',
|
|
1406
|
-
version: '1.2.3',
|
|
1407
|
-
actions: {
|
|
1408
|
-
onWhatever: {
|
|
1409
|
-
type: 'user.login',
|
|
1410
|
-
email: 'example@example.com',
|
|
1411
|
-
password: 'password',
|
|
1412
|
-
},
|
|
1413
|
-
},
|
|
1414
|
-
});
|
|
1415
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
1416
|
-
type: 'test',
|
|
1417
|
-
version: '1.2.3',
|
|
1418
|
-
actions: {
|
|
1419
|
-
onWhatever: {
|
|
1420
|
-
type: 'user.register',
|
|
1421
|
-
email: 'example@example.com',
|
|
1422
|
-
password: 'password',
|
|
1423
|
-
displayName: 'Test User',
|
|
1424
|
-
},
|
|
1425
|
-
},
|
|
1426
|
-
});
|
|
1427
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
1428
|
-
type: 'test',
|
|
1429
|
-
version: '1.2.3',
|
|
1430
|
-
actions: {
|
|
1431
|
-
onWhatever: {
|
|
1432
|
-
type: 'user.update',
|
|
1433
|
-
email: 'example@example.com',
|
|
1434
|
-
password: 'password',
|
|
1435
|
-
},
|
|
1436
|
-
},
|
|
1437
|
-
});
|
|
1438
|
-
|
|
1439
|
-
const result = await validateAppDefinition(app, () => [
|
|
1440
|
-
{
|
|
1441
|
-
name: '@appsemble/test',
|
|
1442
|
-
version: '1.2.3',
|
|
1443
|
-
files: [],
|
|
1444
|
-
languages: [],
|
|
1445
|
-
actions: {
|
|
1446
|
-
onWhatever: {},
|
|
1447
|
-
},
|
|
1448
|
-
},
|
|
1449
|
-
]);
|
|
1450
|
-
expect(result.valid).toBe(false);
|
|
1451
|
-
expect(result.errors).toStrictEqual([
|
|
1452
|
-
new ValidationError(
|
|
1453
|
-
'refers to a user action but the app doesn’t have a security definition',
|
|
1454
|
-
'user.login',
|
|
1455
|
-
undefined,
|
|
1456
|
-
['pages', 0, 'blocks', 0, 'actions', 'onWhatever', 'type'],
|
|
1457
|
-
),
|
|
1458
|
-
new ValidationError(
|
|
1459
|
-
'refers to a user action but the app doesn’t have a security definition',
|
|
1460
|
-
'user.register',
|
|
1461
|
-
undefined,
|
|
1462
|
-
['pages', 0, 'blocks', 1, 'actions', 'onWhatever', 'type'],
|
|
1463
|
-
),
|
|
1464
|
-
new ValidationError(
|
|
1465
|
-
'refers to a user action but the app doesn’t have a security definition',
|
|
1466
|
-
'user.update',
|
|
1467
|
-
undefined,
|
|
1468
|
-
['pages', 0, 'blocks', 2, 'actions', 'onWhatever', 'type'],
|
|
1469
|
-
),
|
|
1470
|
-
]);
|
|
1471
|
-
});
|
|
1472
|
-
|
|
1473
|
-
it('should report an error if flow actions are used on a non-flow page', async () => {
|
|
1474
|
-
const app = createTestApp();
|
|
1475
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
1476
|
-
type: 'test',
|
|
1477
|
-
version: '1.2.3',
|
|
1478
|
-
actions: {
|
|
1479
|
-
onWhatever: {
|
|
1480
|
-
type: 'flow.next',
|
|
1481
|
-
},
|
|
1482
|
-
},
|
|
1483
|
-
});
|
|
1484
|
-
|
|
1485
|
-
const result = await validateAppDefinition(app, () => [
|
|
1486
|
-
{
|
|
1487
|
-
name: '@appsemble/test',
|
|
1488
|
-
version: '1.2.3',
|
|
1489
|
-
files: [],
|
|
1490
|
-
languages: [],
|
|
1491
|
-
actions: {
|
|
1492
|
-
onWhatever: {},
|
|
1493
|
-
},
|
|
1494
|
-
},
|
|
1495
|
-
]);
|
|
1496
|
-
expect(result.valid).toBe(false);
|
|
1497
|
-
expect(result.errors).toStrictEqual([
|
|
1498
|
-
new ValidationError(
|
|
1499
|
-
'flow actions can only be used on pages with the type ‘flow’',
|
|
1500
|
-
'flow.next',
|
|
1501
|
-
undefined,
|
|
1502
|
-
['pages', 0, 'blocks', 0, 'actions', 'onWhatever', 'type'],
|
|
1503
|
-
),
|
|
1504
|
-
]);
|
|
1505
|
-
});
|
|
1506
|
-
|
|
1507
|
-
it('should report an error if flow.back is used on the first step', async () => {
|
|
1508
|
-
const app = createTestApp();
|
|
1509
|
-
(app.pages[3] as FlowPageDefinition).steps[0].blocks.push({
|
|
1510
|
-
type: 'test',
|
|
1511
|
-
version: '1.2.3',
|
|
1512
|
-
actions: {
|
|
1513
|
-
onWhatever: {
|
|
1514
|
-
type: 'flow.back',
|
|
1515
|
-
},
|
|
1516
|
-
},
|
|
1517
|
-
});
|
|
1518
|
-
|
|
1519
|
-
const result = await validateAppDefinition(app, () => [
|
|
1520
|
-
{
|
|
1521
|
-
name: '@appsemble/test',
|
|
1522
|
-
version: '1.2.3',
|
|
1523
|
-
files: [],
|
|
1524
|
-
languages: [],
|
|
1525
|
-
actions: {
|
|
1526
|
-
onWhatever: {},
|
|
1527
|
-
},
|
|
1528
|
-
},
|
|
1529
|
-
]);
|
|
1530
|
-
expect(result.valid).toBe(false);
|
|
1531
|
-
expect(result.errors).toStrictEqual([
|
|
1532
|
-
new ValidationError('is not allowed on the first step in the flow', 'flow.back', undefined, [
|
|
1533
|
-
'pages',
|
|
1534
|
-
3,
|
|
1535
|
-
'steps',
|
|
1536
|
-
0,
|
|
1537
|
-
'blocks',
|
|
1538
|
-
0,
|
|
1539
|
-
'actions',
|
|
1540
|
-
'onWhatever',
|
|
1541
|
-
'type',
|
|
1542
|
-
]),
|
|
1543
|
-
]);
|
|
1544
|
-
});
|
|
1545
|
-
|
|
1546
|
-
it('should report an error if flow.to refers to a step that doesn’t exist', async () => {
|
|
1547
|
-
const app = createTestApp();
|
|
1548
|
-
(app.pages[3] as FlowPageDefinition).steps[0].blocks.push({
|
|
1549
|
-
type: 'test',
|
|
1550
|
-
version: '1.2.3',
|
|
1551
|
-
actions: {
|
|
1552
|
-
onWhatever: {
|
|
1553
|
-
type: 'flow.to',
|
|
1554
|
-
step: 'Some Step',
|
|
1555
|
-
},
|
|
1556
|
-
},
|
|
1557
|
-
});
|
|
1558
|
-
|
|
1559
|
-
const result = await validateAppDefinition(app, () => [
|
|
1560
|
-
{
|
|
1561
|
-
name: '@appsemble/test',
|
|
1562
|
-
version: '1.2.3',
|
|
1563
|
-
files: [],
|
|
1564
|
-
languages: [],
|
|
1565
|
-
actions: {
|
|
1566
|
-
onWhatever: {},
|
|
1567
|
-
},
|
|
1568
|
-
},
|
|
1569
|
-
]);
|
|
1570
|
-
expect(result.valid).toBe(false);
|
|
1571
|
-
expect(result.errors).toStrictEqual([
|
|
1572
|
-
new ValidationError('refers to a step that doesn’t exist', 'flow.to', undefined, [
|
|
1573
|
-
'pages',
|
|
1574
|
-
3,
|
|
1575
|
-
'steps',
|
|
1576
|
-
0,
|
|
1577
|
-
'blocks',
|
|
1578
|
-
0,
|
|
1579
|
-
'actions',
|
|
1580
|
-
'onWhatever',
|
|
1581
|
-
'step',
|
|
1582
|
-
]),
|
|
1583
|
-
]);
|
|
1584
|
-
});
|
|
1585
|
-
|
|
1586
|
-
it('should report an error if flow.next is called on the last step without onFlowFinish', async () => {
|
|
1587
|
-
const app = createTestApp();
|
|
1588
|
-
(app.pages[3] as FlowPageDefinition).steps[1].blocks.push({
|
|
1589
|
-
type: 'test',
|
|
1590
|
-
version: '1.2.3',
|
|
1591
|
-
actions: {
|
|
1592
|
-
onWhatever: {
|
|
1593
|
-
type: 'flow.next',
|
|
1594
|
-
},
|
|
1595
|
-
},
|
|
1596
|
-
});
|
|
1597
|
-
|
|
1598
|
-
const result = await validateAppDefinition(app, () => [
|
|
1599
|
-
{
|
|
1600
|
-
name: '@appsemble/test',
|
|
1601
|
-
version: '1.2.3',
|
|
1602
|
-
files: [],
|
|
1603
|
-
languages: [],
|
|
1604
|
-
actions: {
|
|
1605
|
-
onWhatever: {},
|
|
1606
|
-
},
|
|
1607
|
-
},
|
|
1608
|
-
]);
|
|
1609
|
-
expect(result.valid).toBe(false);
|
|
1610
|
-
expect(result.errors).toStrictEqual([
|
|
1611
|
-
new ValidationError(
|
|
1612
|
-
'was defined on the last step but ‘onFlowFinish’ page action wasn’t defined',
|
|
1613
|
-
'flow.next',
|
|
1614
|
-
undefined,
|
|
1615
|
-
['pages', 3, 'steps', 1, 'blocks', 0, 'actions', 'onWhatever', 'type'],
|
|
1616
|
-
),
|
|
1617
|
-
]);
|
|
1618
|
-
});
|
|
1619
|
-
|
|
1620
|
-
it('should report an error if flow.finish is called without onFlowFinish', async () => {
|
|
1621
|
-
const app = createTestApp();
|
|
1622
|
-
(app.pages[3] as FlowPageDefinition).steps[1].blocks.push({
|
|
1623
|
-
type: 'test',
|
|
1624
|
-
version: '1.2.3',
|
|
1625
|
-
actions: {
|
|
1626
|
-
onWhatever: {
|
|
1627
|
-
type: 'flow.finish',
|
|
1628
|
-
},
|
|
1629
|
-
},
|
|
1630
|
-
});
|
|
1631
|
-
|
|
1632
|
-
const result = await validateAppDefinition(app, () => [
|
|
1633
|
-
{
|
|
1634
|
-
name: '@appsemble/test',
|
|
1635
|
-
version: '1.2.3',
|
|
1636
|
-
files: [],
|
|
1637
|
-
languages: [],
|
|
1638
|
-
actions: {
|
|
1639
|
-
onWhatever: {},
|
|
1640
|
-
},
|
|
1641
|
-
},
|
|
1642
|
-
]);
|
|
1643
|
-
expect(result.valid).toBe(false);
|
|
1644
|
-
expect(result.errors).toStrictEqual([
|
|
1645
|
-
new ValidationError(
|
|
1646
|
-
'was defined but ‘onFlowFinish’ page action wasn’t defined',
|
|
1647
|
-
'flow.finish',
|
|
1648
|
-
undefined,
|
|
1649
|
-
['pages', 3, 'steps', 1, 'blocks', 0, 'actions', 'onWhatever', 'type'],
|
|
1650
|
-
),
|
|
1651
|
-
]);
|
|
1652
|
-
});
|
|
1653
|
-
|
|
1654
|
-
it('should report an error if flow.cancel is called without onFlowCancel', async () => {
|
|
1655
|
-
const app = createTestApp();
|
|
1656
|
-
(app.pages[3] as FlowPageDefinition).steps[1].blocks.push({
|
|
1657
|
-
type: 'test',
|
|
1658
|
-
version: '1.2.3',
|
|
1659
|
-
actions: {
|
|
1660
|
-
onWhatever: {
|
|
1661
|
-
type: 'flow.cancel',
|
|
1662
|
-
},
|
|
1663
|
-
},
|
|
1664
|
-
});
|
|
1665
|
-
|
|
1666
|
-
const result = await validateAppDefinition(app, () => [
|
|
1667
|
-
{
|
|
1668
|
-
name: '@appsemble/test',
|
|
1669
|
-
version: '1.2.3',
|
|
1670
|
-
files: [],
|
|
1671
|
-
languages: [],
|
|
1672
|
-
actions: {
|
|
1673
|
-
onWhatever: {},
|
|
1674
|
-
},
|
|
1675
|
-
},
|
|
1676
|
-
]);
|
|
1677
|
-
expect(result.valid).toBe(false);
|
|
1678
|
-
expect(result.errors).toStrictEqual([
|
|
1679
|
-
new ValidationError(
|
|
1680
|
-
'was defined but ‘onFlowCancel’ page action wasn’t defined',
|
|
1681
|
-
'flow.cancel',
|
|
1682
|
-
undefined,
|
|
1683
|
-
['pages', 3, 'steps', 1, 'blocks', 0, 'actions', 'onWhatever', 'type'],
|
|
1684
|
-
),
|
|
1685
|
-
]);
|
|
1686
|
-
});
|
|
1687
|
-
|
|
1688
|
-
it('should report an error if a resource action refers to a non-existent resource', async () => {
|
|
1689
|
-
const app = createTestApp();
|
|
1690
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
1691
|
-
type: 'test',
|
|
1692
|
-
version: '1.2.3',
|
|
1693
|
-
actions: {
|
|
1694
|
-
onWhatever: {
|
|
1695
|
-
type: 'resource.get',
|
|
1696
|
-
resource: 'Nonexistent',
|
|
1697
|
-
},
|
|
1698
|
-
},
|
|
1699
|
-
});
|
|
1700
|
-
|
|
1701
|
-
const result = await validateAppDefinition(app, () => [
|
|
1702
|
-
{
|
|
1703
|
-
name: '@appsemble/test',
|
|
1704
|
-
version: '1.2.3',
|
|
1705
|
-
files: [],
|
|
1706
|
-
languages: [],
|
|
1707
|
-
actions: {
|
|
1708
|
-
onWhatever: {},
|
|
1709
|
-
},
|
|
1710
|
-
},
|
|
1711
|
-
]);
|
|
1712
|
-
expect(result.valid).toBe(false);
|
|
1713
|
-
expect(result.errors).toStrictEqual([
|
|
1714
|
-
new ValidationError('refers to a resource that doesn’t exist', 'resource.get', undefined, [
|
|
1715
|
-
'pages',
|
|
1716
|
-
0,
|
|
1717
|
-
'blocks',
|
|
1718
|
-
0,
|
|
1719
|
-
'actions',
|
|
1720
|
-
'onWhatever',
|
|
1721
|
-
'resource',
|
|
1722
|
-
]),
|
|
1723
|
-
]);
|
|
1724
|
-
});
|
|
1725
|
-
|
|
1726
|
-
it('should report an error if a resource action refers to a private resource action', async () => {
|
|
1727
|
-
const app = createTestApp();
|
|
1728
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
1729
|
-
type: 'test',
|
|
1730
|
-
version: '1.2.3',
|
|
1731
|
-
actions: {
|
|
1732
|
-
onWhatever: {
|
|
1733
|
-
type: 'resource.get',
|
|
1734
|
-
resource: 'person',
|
|
1735
|
-
},
|
|
1736
|
-
},
|
|
1737
|
-
});
|
|
1738
|
-
|
|
1739
|
-
const result = await validateAppDefinition(app, () => [
|
|
1740
|
-
{
|
|
1741
|
-
name: '@appsemble/test',
|
|
1742
|
-
version: '1.2.3',
|
|
1743
|
-
files: [],
|
|
1744
|
-
languages: [],
|
|
1745
|
-
actions: {
|
|
1746
|
-
onWhatever: {},
|
|
1747
|
-
},
|
|
1748
|
-
},
|
|
1749
|
-
]);
|
|
1750
|
-
expect(result.valid).toBe(false);
|
|
1751
|
-
expect(result.errors).toStrictEqual([
|
|
1752
|
-
new ValidationError(
|
|
1753
|
-
'refers to a resource action that is currently set to private',
|
|
1754
|
-
'resource.get',
|
|
1755
|
-
undefined,
|
|
1756
|
-
['pages', 0, 'blocks', 0, 'actions', 'onWhatever', 'resource'],
|
|
1757
|
-
),
|
|
1758
|
-
]);
|
|
1759
|
-
});
|
|
1760
|
-
|
|
1761
|
-
it('should report an error if a resource action refers is private action without a security definition', async () => {
|
|
1762
|
-
const { security, ...app } = createTestApp();
|
|
1763
|
-
app.resources.person.roles = [];
|
|
1764
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
1765
|
-
type: 'test',
|
|
1766
|
-
version: '1.2.3',
|
|
1767
|
-
actions: {
|
|
1768
|
-
onWhatever: {
|
|
1769
|
-
type: 'resource.get',
|
|
1770
|
-
resource: 'person',
|
|
1771
|
-
},
|
|
1772
|
-
},
|
|
1773
|
-
});
|
|
1774
|
-
|
|
1775
|
-
const result = await validateAppDefinition(app, () => [
|
|
1776
|
-
{
|
|
1777
|
-
name: '@appsemble/test',
|
|
1778
|
-
version: '1.2.3',
|
|
1779
|
-
files: [],
|
|
1780
|
-
languages: [],
|
|
1781
|
-
actions: {
|
|
1782
|
-
onWhatever: {},
|
|
1783
|
-
},
|
|
1784
|
-
},
|
|
1785
|
-
]);
|
|
1786
|
-
expect(result.valid).toBe(false);
|
|
1787
|
-
expect(result.errors).toStrictEqual([
|
|
1788
|
-
new ValidationError(
|
|
1789
|
-
'refers to a resource action that is accessible when logged in, but the app has no security definitions',
|
|
1790
|
-
'resource.get',
|
|
1791
|
-
undefined,
|
|
1792
|
-
['pages', 0, 'blocks', 0, 'actions', 'onWhatever', 'resource'],
|
|
1793
|
-
),
|
|
1794
|
-
]);
|
|
1795
|
-
});
|
|
1796
|
-
|
|
1797
|
-
it('should ignore if an app is null', async () => {
|
|
1798
|
-
const result = await validateAppDefinition(null, () => []);
|
|
1799
|
-
expect(result.valid).toBe(true);
|
|
1800
|
-
expect(result.errors).toStrictEqual([]);
|
|
1801
|
-
});
|
|
1802
|
-
|
|
1803
|
-
it('should if app pages are not an array', async () => {
|
|
1804
|
-
const result = await validateAppDefinition(null, () => []);
|
|
1805
|
-
expect(result.valid).toBe(true);
|
|
1806
|
-
expect(result.errors).toStrictEqual([]);
|
|
1807
|
-
});
|
|
1808
|
-
|
|
1809
|
-
it('should report an error if app validation fails for an unexpected reason', async () => {
|
|
1810
|
-
const result = await validateAppDefinition(null, () => []);
|
|
1811
|
-
expect(result.valid).toBe(true);
|
|
1812
|
-
expect(result.errors).toStrictEqual([]);
|
|
1813
|
-
});
|
|
1814
|
-
|
|
1815
|
-
it('should handle if an unexpected error occurs', async () => {
|
|
1816
|
-
const result = await validateAppDefinition(
|
|
1817
|
-
{
|
|
1818
|
-
get defaultPage(): string {
|
|
1819
|
-
throw new Error('Boom!');
|
|
1820
|
-
},
|
|
1821
|
-
pages: [],
|
|
1822
|
-
},
|
|
1823
|
-
() => [],
|
|
1824
|
-
);
|
|
1825
|
-
expect(result.valid).toBe(false);
|
|
1826
|
-
expect(result.errors).toStrictEqual([
|
|
1827
|
-
new ValidationError('Unexpected error: Boom!', null, undefined, []),
|
|
1828
|
-
]);
|
|
1829
|
-
});
|
|
1830
|
-
|
|
1831
|
-
it('should prevent block with layout float to be used in a dialog action', async () => {
|
|
1832
|
-
const app = createTestApp();
|
|
1833
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
1834
|
-
type: 'test',
|
|
1835
|
-
version: '1.2.3',
|
|
1836
|
-
actions: {
|
|
1837
|
-
onClick: {
|
|
1838
|
-
type: 'dialog',
|
|
1839
|
-
blocks: [
|
|
1840
|
-
{
|
|
1841
|
-
type: 'test',
|
|
1842
|
-
version: '1.2.3',
|
|
1843
|
-
},
|
|
1844
|
-
],
|
|
1845
|
-
},
|
|
1846
|
-
},
|
|
1847
|
-
});
|
|
1848
|
-
const result = await validateAppDefinition(app, () => [
|
|
1849
|
-
{
|
|
1850
|
-
name: '@appsemble/test',
|
|
1851
|
-
version: '1.2.3',
|
|
1852
|
-
files: [],
|
|
1853
|
-
languages: [],
|
|
1854
|
-
layout: 'float',
|
|
1855
|
-
actions: {
|
|
1856
|
-
onClick: {},
|
|
1857
|
-
},
|
|
1858
|
-
},
|
|
1859
|
-
]);
|
|
1860
|
-
expect(result.valid).toBe(false);
|
|
1861
|
-
expect(result.errors).toStrictEqual([
|
|
1862
|
-
new ValidationError(
|
|
1863
|
-
'block with layout type: "float" is not allowed in a dialog action',
|
|
1864
|
-
'1.2.3',
|
|
1865
|
-
undefined,
|
|
1866
|
-
['pages', 0, 'blocks', 0, 'actions', 'onClick', 'type'],
|
|
1867
|
-
),
|
|
1868
|
-
]);
|
|
1869
|
-
});
|
|
1870
|
-
|
|
1871
|
-
it('should check app definition for blocks that have their layout manually set to float', async () => {
|
|
1872
|
-
const app = createTestApp();
|
|
1873
|
-
(app.pages[0] as BasicPageDefinition).blocks.push({
|
|
1874
|
-
type: 'test',
|
|
1875
|
-
version: '1.2.3',
|
|
1876
|
-
actions: {
|
|
1877
|
-
onClick: {
|
|
1878
|
-
type: 'dialog',
|
|
1879
|
-
blocks: [
|
|
1880
|
-
{
|
|
1881
|
-
type: 'test',
|
|
1882
|
-
version: '1.2.3',
|
|
1883
|
-
layout: 'float',
|
|
1884
|
-
},
|
|
1885
|
-
],
|
|
1886
|
-
},
|
|
1887
|
-
},
|
|
1888
|
-
});
|
|
1889
|
-
const result = await validateAppDefinition(app, () => [
|
|
1890
|
-
{
|
|
1891
|
-
name: '@appsemble/test',
|
|
1892
|
-
version: '1.2.3',
|
|
1893
|
-
files: [],
|
|
1894
|
-
languages: [],
|
|
1895
|
-
layout: 'hidden',
|
|
1896
|
-
actions: {
|
|
1897
|
-
onClick: {},
|
|
1898
|
-
},
|
|
1899
|
-
},
|
|
1900
|
-
]);
|
|
1901
|
-
expect(result.valid).toBe(false);
|
|
1902
|
-
expect(result.errors).toStrictEqual([
|
|
1903
|
-
new ValidationError(
|
|
1904
|
-
'block with layout type: "float" is not allowed in a dialog action',
|
|
1905
|
-
{
|
|
1906
|
-
layout: 'float',
|
|
1907
|
-
type: 'test',
|
|
1908
|
-
version: '1.2.3',
|
|
1909
|
-
},
|
|
1910
|
-
undefined,
|
|
1911
|
-
['pages', 0, 'blocks', 0, 'actions', 'onClick', 'type'],
|
|
1912
|
-
),
|
|
1913
|
-
]);
|
|
1914
|
-
});
|
|
1915
|
-
});
|