From 231e766cf884889a32c16f67838e28f388fe71e8 Mon Sep 17 00:00:00 2001 From: Jaakko Heusala Date: Sat, 16 Dec 2023 19:11:18 +0200 Subject: [PATCH] Refactored entities to better locations. Implemented better support for EntityFactory (e.g. test functions and explain functions). --- components/HyperComponentCollection.ts | 4 +- .../actionButton/ActionButtonComponent.ts | 4 +- components/actionButton/ActionButtonEntity.ts | 4 +- components/article/ArticleComponent.test.ts | 2 +- components/article/ArticleComponent.ts | 4 +- components/article/ArticleEntity.ts | 2 +- components/button/ButtonComponent.test.ts | 2 +- components/button/ButtonComponent.ts | 4 +- components/button/ButtonEntity.ts | 2 +- components/div/DivComponent.ts | 4 +- components/div/DivEntity.ts | 2 +- components/form/FormComponent.ts | 4 +- components/form/FormEntity.ts | 4 +- components/heading/HeadingComponent.ts | 4 +- components/heading/HeadingEntity.ts | 2 +- components/image/ImageComponent.ts | 4 +- components/image/ImageEntity.ts | 2 +- .../linkButton/LinkButtonComponent.test.ts | 2 +- components/linkButton/LinkButtonComponent.ts | 10 +- components/linkButton/LinkButtonEntity.ts | 2 +- components/paragraph/ParagraphComponent.ts | 4 +- components/paragraph/ParagraphEntity.ts | 2 +- components/span/SpanComponent.ts | 4 +- components/span/SpanEntity.ts | 2 +- components/subTitle/SubTitleComponent.ts | 4 +- components/subTitle/SubTitleEntity.ts | 2 +- components/table/TableComponent.ts | 4 +- components/table/TableEntity.ts | 4 +- .../table/column/TableColumnComponent.ts | 4 +- components/table/column/TableColumnEntity.ts | 2 +- components/table/row/TableRowComponent.ts | 4 +- components/table/row/TableRowEntity.ts | 2 +- components/title/TitleComponent.test.ts | 2 +- components/title/TitleComponent.ts | 4 +- components/title/TitleEntity.ts | 2 +- dto/ColorDTO.ts | 59 - entities/BackgroundImageEntity.ts | 103 -- entities/BorderEntity.ts | 200 --- entities/FontEntity.ts | 227 --- entities/StyleEntity.ts | 1398 ----------------- entities/TextDecorationEntity.ts | 210 --- {dto => entities/action}/ActionDTO.ts | 14 +- entities/{types => app}/App.ts | 16 +- {dto => entities/app}/AppDTO.ts | 28 +- entities/{ => app}/AppEntity.ts | 26 +- entities/{types => background}/Background.ts | 30 +- {dto => entities/background}/BackgroundDTO.ts | 28 +- entities/{ => background}/BackgroundEntity.ts | 65 +- .../BackgroundImage.ts | 4 +- .../backgroundImage}/BackgroundImageDTO.ts | 12 +- .../backgroundImage/BackgroundImageEntity.ts | 87 + .../BackgroundPositionDTO.ts | 14 + .../BackgroundPositionEntity.ts | 0 .../BackgroundRepeat.ts | 6 +- .../backgroundRepeat}/BackgroundRepeatDTO.ts | 12 +- .../BackgroundRepeatEntity.ts | 116 +- .../backgroundSize}/BackgroundSize.ts | 0 entities/{types => border}/Border.ts | 18 +- {dto => entities/border}/BorderDTO.ts | 18 +- entities/border/BorderEntity.ts | 153 ++ entities/borderBox/BorderBox.ts | 145 ++ entities/borderBox/BorderBoxDTO.ts | 84 + entities/borderBox/BorderBoxEntity.ts | 183 +++ entities/{types => color}/Color.ts | 4 +- entities/color/ColorDTO.ts | 7 + entities/{ => color}/ColorEntity.ts | 102 +- entities/{types => component}/Component.ts | 12 +- {dto => entities/component}/ComponentDTO.ts | 36 +- entities/{ => component}/ComponentEntity.ts | 26 +- entities/{types => font}/Font.ts | 94 +- {dto => entities/font}/FontDTO.ts | 20 +- entities/font/FontEntity.ts | 152 ++ entities/{ => font}/types/FontStyle.ts | 6 +- entities/{ => font}/types/FontVariant.ts | 6 +- entities/{ => font}/types/FontWeight.ts | 6 +- {dto => entities/route}/RouteDTO.ts | 22 +- entities/{ => route}/RouteEntity.ts | 8 +- {dto => entities/seo}/SeoDTO.ts | 12 +- entities/{types => size}/Size.ts | 25 +- {dto => entities/size}/SizeDTO.ts | 33 +- entities/size/SizeEntity.test.ts | 32 + entities/{ => size}/SizeEntity.ts | 180 ++- entities/sizeBox/SizeBox.ts | 190 +++ entities/sizeBox/SizeBoxDTO.ts | 84 + entities/sizeBox/SizeBoxEntity.ts | 183 +++ entities/sizeDimensions/SizeDimensions.ts | 122 ++ entities/sizeDimensions/SizeDimensionsDTO.ts | 70 + .../sizeDimensions/SizeDimensionsEntity.ts | 155 ++ entities/{types => style}/Style.ts | 110 +- {dto => entities/style}/StyleDTO.ts | 51 +- entities/{ => style}/StyleEntity.test.ts | 2 +- entities/style/StyleEntity.ts | 509 ++++++ .../TextDecoration.ts | 20 +- .../textDecoration}/TextDecorationDTO.ts | 18 +- .../textDecoration/TextDecorationEntity.ts | 132 ++ .../types/BackgroundAttachment.ts | 0 .../types/BackgroundBlendMode.ts | 0 {dto => entities}/types/BackgroundClip.ts | 0 {dto => entities}/types/BackgroundOrigin.ts | 0 {dto => entities}/types/BackgroundPosition.ts | 0 .../types/BackgroundPositionOptions.ts | 4 +- .../types/BackgroundRepeatType.ts | 0 .../types/BackgroundSizeOptions.ts | 6 +- entities/types/BaseEntity.ts | 2 +- {dto => entities}/types/BorderStyle.ts | 0 {dto => entities}/types/BoxSizing.ts | 0 entities/types/ComponentType.ts | 2 +- {dto => entities}/types/DTO.ts | 0 {dto => entities}/types/DTOWithContent.ts | 0 {dto => entities}/types/DTOWithName.ts | 0 .../types/DTOWithOptionalExtend.ts | 0 .../types/DTOWithOptionalLanguage.ts | 0 .../types/DTOWithOptionalPublicUrl.ts | 0 entities/types/Entity.ts | 2 +- entities/types/EntityFactory.ts | 11 +- entities/types/EntityFactoryImpl.test.ts | 557 ++++++- entities/types/EntityFactoryImpl.ts | 217 ++- entities/types/EntityProperty.ts | 12 +- entities/types/EntityPropertyImpl.test.ts | 2 +- entities/types/EntityPropertyImpl.ts | 51 +- entities/types/EntityType.ts | 14 +- {dto => entities}/types/ExtendableDTO.ts | 0 entities/types/ExtendableEntity.ts | 2 +- {dto => entities}/types/HyperComponent.ts | 0 entities/types/IsDTO.ts | 11 - entities/types/IsDTOTestFunction.ts | 29 + {dto => entities}/types/TextAlign.ts | 0 entities/{types => view}/View.ts | 14 +- {dto => entities/view}/ViewDTO.ts | 26 +- entities/{ => view}/ViewEntity.ts | 38 +- samples/loading/LoadingAppDefinition.ts | 2 +- samples/loading/components/Text.ts | 2 +- samples/loading/components/TextComponent.ts | 4 +- samples/loading/routes/AnyRoute.ts | 2 +- samples/loading/routes/LoadingRoute.ts | 2 +- samples/loading/views/DefaultView.ts | 4 +- samples/loading/views/LoadingView.ts | 2 +- samples/order/OrderAppDefinition.ts | 2 +- samples/order/components/Text.ts | 2 +- samples/order/components/TextComponent.ts | 4 +- samples/order/routes/AnyRoute.ts | 2 +- samples/order/routes/LoginRoute.ts | 2 +- samples/order/views/DefaultView.ts | 4 +- samples/order/views/LoginView.ts | 2 +- services/ComponentFactory.ts | 2 +- services/ComponentFactoryImpl.ts | 2 +- services/ComponentFactoryService.ts | 2 +- types/Enum.ts | 69 +- types/String.ts | 33 +- utils/components/mergeComponentContent.ts | 2 +- utils/components/populateComponentDTO.ts | 4 +- utils/populateAppDTO.ts | 8 +- utils/views/findAndPopulateViewDTO.test.ts | 2 +- utils/views/findAndPopulateViewDTO.ts | 2 +- utils/views/findViewDTO.test.ts | 2 +- utils/views/findViewDTO.ts | 2 +- utils/views/populateViewDTO.test.ts | 2 +- utils/views/populateViewDTO.ts | 4 +- views/extend/ExtendViewDTO.ts | 2 +- views/redirect/RedirectViewDTO.ts | 2 +- 160 files changed, 4037 insertions(+), 2938 deletions(-) delete mode 100644 dto/ColorDTO.ts delete mode 100644 entities/BackgroundImageEntity.ts delete mode 100644 entities/BorderEntity.ts delete mode 100644 entities/FontEntity.ts delete mode 100644 entities/StyleEntity.ts delete mode 100644 entities/TextDecorationEntity.ts rename {dto => entities/action}/ActionDTO.ts (94%) rename entities/{types => app}/App.ts (79%) rename {dto => entities/app}/AppDTO.ts (81%) rename entities/{ => app}/AppEntity.ts (85%) rename entities/{types => background}/Background.ts (71%) rename {dto => entities/background}/BackgroundDTO.ts (85%) rename entities/{ => background}/BackgroundEntity.ts (78%) rename entities/{types => backgroundImage}/BackgroundImage.ts (92%) rename {dto => entities/backgroundImage}/BackgroundImageDTO.ts (84%) create mode 100644 entities/backgroundImage/BackgroundImageEntity.ts create mode 100644 entities/backgroundPosition/BackgroundPositionDTO.ts create mode 100644 entities/backgroundPosition/BackgroundPositionEntity.ts rename entities/{types => backgroundRepeat}/BackgroundRepeat.ts (89%) rename {dto => entities/backgroundRepeat}/BackgroundRepeatDTO.ts (86%) rename entities/{ => backgroundRepeat}/BackgroundRepeatEntity.ts (63%) rename {dto/types => entities/backgroundSize}/BackgroundSize.ts (100%) rename entities/{types => border}/Border.ts (79%) rename {dto => entities/border}/BorderDTO.ts (92%) create mode 100644 entities/border/BorderEntity.ts create mode 100644 entities/borderBox/BorderBox.ts create mode 100644 entities/borderBox/BorderBoxDTO.ts create mode 100644 entities/borderBox/BorderBoxEntity.ts rename entities/{types => color}/Color.ts (92%) create mode 100644 entities/color/ColorDTO.ts rename entities/{ => color}/ColorEntity.ts (54%) rename entities/{types => component}/Component.ts (94%) rename {dto => entities/component}/ComponentDTO.ts (84%) rename entities/{ => component}/ComponentEntity.ts (92%) rename entities/{types => font}/Font.ts (59%) rename {dto => entities/font}/FontDTO.ts (88%) create mode 100644 entities/font/FontEntity.ts rename entities/{ => font}/types/FontStyle.ts (89%) rename entities/{ => font}/types/FontVariant.ts (87%) rename entities/{ => font}/types/FontWeight.ts (87%) rename {dto => entities/route}/RouteDTO.ts (84%) rename entities/{ => route}/RouteEntity.ts (91%) rename {dto => entities/seo}/SeoDTO.ts (89%) rename entities/{types => size}/Size.ts (77%) rename {dto => entities/size}/SizeDTO.ts (81%) create mode 100644 entities/size/SizeEntity.test.ts rename entities/{ => size}/SizeEntity.ts (58%) create mode 100644 entities/sizeBox/SizeBox.ts create mode 100644 entities/sizeBox/SizeBoxDTO.ts create mode 100644 entities/sizeBox/SizeBoxEntity.ts create mode 100644 entities/sizeDimensions/SizeDimensions.ts create mode 100644 entities/sizeDimensions/SizeDimensionsDTO.ts create mode 100644 entities/sizeDimensions/SizeDimensionsEntity.ts rename entities/{types => style}/Style.ts (64%) rename {dto => entities/style}/StyleDTO.ts (83%) rename entities/{ => style}/StyleEntity.test.ts (97%) create mode 100644 entities/style/StyleEntity.ts rename entities/{types => textDecoration}/TextDecoration.ts (83%) rename {dto => entities/textDecoration}/TextDecorationDTO.ts (90%) create mode 100644 entities/textDecoration/TextDecorationEntity.ts rename {dto => entities}/types/BackgroundAttachment.ts (100%) rename {dto => entities}/types/BackgroundBlendMode.ts (100%) rename {dto => entities}/types/BackgroundClip.ts (100%) rename {dto => entities}/types/BackgroundOrigin.ts (100%) rename {dto => entities}/types/BackgroundPosition.ts (100%) rename {dto => entities}/types/BackgroundPositionOptions.ts (98%) rename {dto => entities}/types/BackgroundRepeatType.ts (100%) rename {dto => entities}/types/BackgroundSizeOptions.ts (94%) rename {dto => entities}/types/BorderStyle.ts (100%) rename {dto => entities}/types/BoxSizing.ts (100%) rename {dto => entities}/types/DTO.ts (100%) rename {dto => entities}/types/DTOWithContent.ts (100%) rename {dto => entities}/types/DTOWithName.ts (100%) rename {dto => entities}/types/DTOWithOptionalExtend.ts (100%) rename {dto => entities}/types/DTOWithOptionalLanguage.ts (100%) rename {dto => entities}/types/DTOWithOptionalPublicUrl.ts (100%) rename {dto => entities}/types/ExtendableDTO.ts (100%) rename {dto => entities}/types/HyperComponent.ts (100%) delete mode 100644 entities/types/IsDTO.ts create mode 100644 entities/types/IsDTOTestFunction.ts rename {dto => entities}/types/TextAlign.ts (100%) rename entities/{types => view}/View.ts (86%) rename {dto => entities/view}/ViewDTO.ts (86%) rename entities/{ => view}/ViewEntity.ts (77%) diff --git a/components/HyperComponentCollection.ts b/components/HyperComponentCollection.ts index 02c4956..9a0f810 100644 --- a/components/HyperComponentCollection.ts +++ b/components/HyperComponentCollection.ts @@ -3,10 +3,10 @@ import { reduce } from "../functions/reduce"; import { uniq } from "../functions/uniq"; import { LogService } from "../LogService"; -import { ComponentDTO } from "../dto/ComponentDTO"; +import { ComponentDTO } from "../entities/component/ComponentDTO"; import { ComponentFactory } from "../services/ComponentFactory"; import { ComponentFactoryService } from "../services/ComponentFactoryService"; -import { ComponentEntity } from "../entities/ComponentEntity"; +import { ComponentEntity } from "../entities/component/ComponentEntity"; import { ComponentType } from "../entities/types/ComponentType"; import { registerActionButtonComponent } from "./actionButton/ActionButtonComponent"; import { registerArticleComponent } from "./article/ArticleComponent"; diff --git a/components/actionButton/ActionButtonComponent.ts b/components/actionButton/ActionButtonComponent.ts index 9d3ac1e..bd9330c 100644 --- a/components/actionButton/ActionButtonComponent.ts +++ b/components/actionButton/ActionButtonComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../dto/ComponentDTO"; -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import { ComponentFactory } from "../../services/ComponentFactory"; export const ACTION_BUTTON_COMPONENT_NAME: string = 'ActionButtonComponent'; diff --git a/components/actionButton/ActionButtonEntity.ts b/components/actionButton/ActionButtonEntity.ts index 03aa4dd..54e86c0 100644 --- a/components/actionButton/ActionButtonEntity.ts +++ b/components/actionButton/ActionButtonEntity.ts @@ -2,8 +2,8 @@ import { ReadonlyJsonAny } from "../../Json"; import { isString } from "../../types/String"; -import { ComponentEntity } from "../../entities/ComponentEntity"; -import { createActionDTO, ActionDTO } from "../../dto/ActionDTO"; +import { ComponentEntity } from "../../entities/component/ComponentEntity"; +import { createActionDTO, ActionDTO } from "../../entities/action/ActionDTO"; import { ACTION_BUTTON_COMPONENT_NAME } from "./ActionButtonComponent"; export class ActionButtonEntity extends ComponentEntity { diff --git a/components/article/ArticleComponent.test.ts b/components/article/ArticleComponent.test.ts index 65e20ad..ae179ea 100644 --- a/components/article/ArticleComponent.test.ts +++ b/components/article/ArticleComponent.test.ts @@ -1,4 +1,4 @@ -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import {ARTICLE_COMPONENT_NAME, ArticleComponent, createArticleComponent} from "./ArticleComponent"; describe('createArticleComponent', () => { diff --git a/components/article/ArticleComponent.ts b/components/article/ArticleComponent.ts index b4094a8..4170be3 100644 --- a/components/article/ArticleComponent.ts +++ b/components/article/ArticleComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../dto/ComponentDTO"; -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import { ComponentFactory } from "../../services/ComponentFactory"; export const ARTICLE_COMPONENT_NAME: string = 'ArticleComponent'; diff --git a/components/article/ArticleEntity.ts b/components/article/ArticleEntity.ts index d5bb3a6..751160d 100644 --- a/components/article/ArticleEntity.ts +++ b/components/article/ArticleEntity.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentEntity } from "../../entities/ComponentEntity"; +import { ComponentEntity } from "../../entities/component/ComponentEntity"; import { ARTICLE_COMPONENT_NAME } from "./ArticleComponent"; export class ArticleEntity extends ComponentEntity { diff --git a/components/button/ButtonComponent.test.ts b/components/button/ButtonComponent.test.ts index 9442be3..ad15bb7 100644 --- a/components/button/ButtonComponent.test.ts +++ b/components/button/ButtonComponent.test.ts @@ -1,4 +1,4 @@ -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import {BUTTON_COMPONENT_NAME, ButtonComponent, createButtonComponent} from "./ButtonComponent"; describe('createButtonComponent', () => { diff --git a/components/button/ButtonComponent.ts b/components/button/ButtonComponent.ts index 2b4d3f5..9201f70 100644 --- a/components/button/ButtonComponent.ts +++ b/components/button/ButtonComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../dto/ComponentDTO"; -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import { ComponentFactory } from "../../services/ComponentFactory"; export const BUTTON_COMPONENT_NAME: string = 'ButtonComponent'; diff --git a/components/button/ButtonEntity.ts b/components/button/ButtonEntity.ts index 74a7127..d52a46a 100644 --- a/components/button/ButtonEntity.ts +++ b/components/button/ButtonEntity.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentEntity } from "../../entities/ComponentEntity"; +import { ComponentEntity } from "../../entities/component/ComponentEntity"; import { BUTTON_COMPONENT_NAME } from "./ButtonComponent"; export class ButtonEntity extends ComponentEntity { diff --git a/components/div/DivComponent.ts b/components/div/DivComponent.ts index 8e540f2..49bc35c 100644 --- a/components/div/DivComponent.ts +++ b/components/div/DivComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../dto/ComponentDTO"; -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import { ComponentFactory } from "../../services/ComponentFactory"; export const DIV_COMPONENT_NAME: string = 'DivComponent'; diff --git a/components/div/DivEntity.ts b/components/div/DivEntity.ts index bbf1490..22324aa 100644 --- a/components/div/DivEntity.ts +++ b/components/div/DivEntity.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentEntity } from "../../entities/ComponentEntity"; +import { ComponentEntity } from "../../entities/component/ComponentEntity"; import { DIV_COMPONENT_NAME } from "./DivComponent"; export class DivEntity extends ComponentEntity { diff --git a/components/form/FormComponent.ts b/components/form/FormComponent.ts index 8c3a852..348564a 100644 --- a/components/form/FormComponent.ts +++ b/components/form/FormComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../dto/ComponentDTO"; -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import { ComponentFactory } from "../../services/ComponentFactory"; export const FORM_COMPONENT_NAME: string = 'FormComponent'; diff --git a/components/form/FormEntity.ts b/components/form/FormEntity.ts index e78eda7..21d768b 100644 --- a/components/form/FormEntity.ts +++ b/components/form/FormEntity.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentContent } from "../../dto/ComponentDTO"; -import { ComponentEntity } from "../../entities/ComponentEntity"; +import { ComponentContent } from "../../entities/component/ComponentDTO"; +import { ComponentEntity } from "../../entities/component/ComponentEntity"; import { FORM_COMPONENT_NAME } from "./FormComponent"; export class FormEntity extends ComponentEntity { diff --git a/components/heading/HeadingComponent.ts b/components/heading/HeadingComponent.ts index a56fcec..2d9affe 100644 --- a/components/heading/HeadingComponent.ts +++ b/components/heading/HeadingComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../dto/ComponentDTO"; -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import { ComponentFactory } from "../../services/ComponentFactory"; export const HEADING_COMPONENT_NAME: string = 'HeadingComponent'; diff --git a/components/heading/HeadingEntity.ts b/components/heading/HeadingEntity.ts index b33fc88..9e82a31 100644 --- a/components/heading/HeadingEntity.ts +++ b/components/heading/HeadingEntity.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentEntity } from "../../entities/ComponentEntity"; +import { ComponentEntity } from "../../entities/component/ComponentEntity"; import { HEADING_COMPONENT_NAME } from "./HeadingComponent"; export class HeadingEntity extends ComponentEntity { diff --git a/components/image/ImageComponent.ts b/components/image/ImageComponent.ts index f14d618..e8b269d 100644 --- a/components/image/ImageComponent.ts +++ b/components/image/ImageComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../dto/ComponentDTO"; -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import { ComponentFactory } from "../../services/ComponentFactory"; export const IMAGE_COMPONENT_NAME: string = 'ImageComponent'; diff --git a/components/image/ImageEntity.ts b/components/image/ImageEntity.ts index f0535d4..2c6b8f5 100644 --- a/components/image/ImageEntity.ts +++ b/components/image/ImageEntity.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentEntity } from "../../entities/ComponentEntity"; +import { ComponentEntity } from "../../entities/component/ComponentEntity"; import { IMAGE_COMPONENT_NAME } from "./ImageComponent"; const IMAGE_SOURCE_META_KEY : string = "source"; diff --git a/components/linkButton/LinkButtonComponent.test.ts b/components/linkButton/LinkButtonComponent.test.ts index 6556428..3842a72 100644 --- a/components/linkButton/LinkButtonComponent.test.ts +++ b/components/linkButton/LinkButtonComponent.test.ts @@ -1,4 +1,4 @@ -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import {createLinkButtonComponent, LinkButtonComponent, LINK_BUTTON_COMPONENT_NAME} from "./LinkButtonComponent"; describe('createLinkButtonComponent', () => { diff --git a/components/linkButton/LinkButtonComponent.ts b/components/linkButton/LinkButtonComponent.ts index 0e6c177..96f5a85 100644 --- a/components/linkButton/LinkButtonComponent.ts +++ b/components/linkButton/LinkButtonComponent.ts @@ -1,10 +1,10 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentDTO, createComponentDTO } from "../../dto/ComponentDTO"; -import { BorderStyle } from "../../dto/types/BorderStyle"; -import { HyperComponent } from "../../dto/types/HyperComponent"; -import { BorderEntity } from "../../entities/BorderEntity"; -import { StyleEntity } from "../../entities/StyleEntity"; +import { ComponentDTO, createComponentDTO } from "../../entities/component/ComponentDTO"; +import { BorderStyle } from "../../entities/types/BorderStyle"; +import { HyperComponent } from "../../entities/types/HyperComponent"; +import { BorderEntity } from "../../entities/border/BorderEntity"; +import { StyleEntity } from "../../entities/style/StyleEntity"; import { ComponentFactory } from "../../services/ComponentFactory"; export const LINK_BUTTON_COMPONENT_NAME: string = 'LinkButtonComponent'; diff --git a/components/linkButton/LinkButtonEntity.ts b/components/linkButton/LinkButtonEntity.ts index 6b4270e..6f438df 100644 --- a/components/linkButton/LinkButtonEntity.ts +++ b/components/linkButton/LinkButtonEntity.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentEntity } from "../../entities/ComponentEntity"; +import { ComponentEntity } from "../../entities/component/ComponentEntity"; import { LINK_BUTTON_COMPONENT_NAME } from "./LinkButtonComponent"; export class LinkButtonEntity extends ComponentEntity { diff --git a/components/paragraph/ParagraphComponent.ts b/components/paragraph/ParagraphComponent.ts index 1e7a834..55342c9 100644 --- a/components/paragraph/ParagraphComponent.ts +++ b/components/paragraph/ParagraphComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../dto/ComponentDTO"; -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import { ComponentFactory } from "../../services/ComponentFactory"; export const PARAGRAPH_COMPONENT_NAME: string = 'ParagraphComponent'; diff --git a/components/paragraph/ParagraphEntity.ts b/components/paragraph/ParagraphEntity.ts index bc47d4e..c8f36e2 100644 --- a/components/paragraph/ParagraphEntity.ts +++ b/components/paragraph/ParagraphEntity.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentEntity } from "../../entities/ComponentEntity"; +import { ComponentEntity } from "../../entities/component/ComponentEntity"; import { PARAGRAPH_COMPONENT_NAME } from "./ParagraphComponent"; export class ParagraphEntity extends ComponentEntity { diff --git a/components/span/SpanComponent.ts b/components/span/SpanComponent.ts index 97ebb46..81602bc 100644 --- a/components/span/SpanComponent.ts +++ b/components/span/SpanComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../dto/ComponentDTO"; -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import { ComponentFactory } from "../../services/ComponentFactory"; export const SPAN_COMPONENT_NAME: string = 'SpanComponent'; diff --git a/components/span/SpanEntity.ts b/components/span/SpanEntity.ts index f7c3c9e..caa87b9 100644 --- a/components/span/SpanEntity.ts +++ b/components/span/SpanEntity.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentEntity } from "../../entities/ComponentEntity"; +import { ComponentEntity } from "../../entities/component/ComponentEntity"; import { SPAN_COMPONENT_NAME } from "./SpanComponent"; export class SpanEntity extends ComponentEntity { diff --git a/components/subTitle/SubTitleComponent.ts b/components/subTitle/SubTitleComponent.ts index 965d563..622449f 100644 --- a/components/subTitle/SubTitleComponent.ts +++ b/components/subTitle/SubTitleComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../dto/ComponentDTO"; -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import { ComponentFactory } from "../../services/ComponentFactory"; export const SUB_TITLE_COMPONENT_NAME: string = 'SubTitleComponent'; diff --git a/components/subTitle/SubTitleEntity.ts b/components/subTitle/SubTitleEntity.ts index 05471a7..fd724e3 100644 --- a/components/subTitle/SubTitleEntity.ts +++ b/components/subTitle/SubTitleEntity.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentEntity } from "../../entities/ComponentEntity"; +import { ComponentEntity } from "../../entities/component/ComponentEntity"; import { SUB_TITLE_COMPONENT_NAME } from "./SubTitleComponent"; export class SubTitleEntity extends ComponentEntity { diff --git a/components/table/TableComponent.ts b/components/table/TableComponent.ts index 7d39409..a6857d4 100644 --- a/components/table/TableComponent.ts +++ b/components/table/TableComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../dto/ComponentDTO"; -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import { ComponentFactory } from "../../services/ComponentFactory"; export const TABLE_COMPONENT_NAME: string = 'TableComponent'; diff --git a/components/table/TableEntity.ts b/components/table/TableEntity.ts index 22700b8..d6e9944 100644 --- a/components/table/TableEntity.ts +++ b/components/table/TableEntity.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentContent } from "../../dto/ComponentDTO"; -import { ComponentEntity } from "../../entities/ComponentEntity"; +import { ComponentContent } from "../../entities/component/ComponentDTO"; +import { ComponentEntity } from "../../entities/component/ComponentEntity"; import { TABLE_COMPONENT_NAME } from "./TableComponent"; import { TableRowEntity } from "./row/TableRowEntity"; diff --git a/components/table/column/TableColumnComponent.ts b/components/table/column/TableColumnComponent.ts index 0af36a2..b66f5f2 100644 --- a/components/table/column/TableColumnComponent.ts +++ b/components/table/column/TableColumnComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../../dto/ComponentDTO"; -import { HyperComponent } from "../../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../../entities/types/HyperComponent"; import { ComponentFactory } from "../../../services/ComponentFactory"; export const TABLE_COLUMN_COMPONENT_NAME: string = 'TableColumnComponent'; diff --git a/components/table/column/TableColumnEntity.ts b/components/table/column/TableColumnEntity.ts index 87f1828..fd75cfd 100644 --- a/components/table/column/TableColumnEntity.ts +++ b/components/table/column/TableColumnEntity.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentEntity, ComponentEntityContent } from "../../../entities/ComponentEntity"; +import { ComponentEntity, ComponentEntityContent } from "../../../entities/component/ComponentEntity"; import { TABLE_COLUMN_COMPONENT_NAME } from "./TableColumnComponent"; export class TableColumnEntity extends ComponentEntity { diff --git a/components/table/row/TableRowComponent.ts b/components/table/row/TableRowComponent.ts index 6df09bc..06fb6e0 100644 --- a/components/table/row/TableRowComponent.ts +++ b/components/table/row/TableRowComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../../dto/ComponentDTO"; -import { HyperComponent } from "../../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../../entities/types/HyperComponent"; import { ComponentFactory } from "../../../services/ComponentFactory"; export const TABLE_ROW_COMPONENT_NAME: string = 'TableRowComponent'; diff --git a/components/table/row/TableRowEntity.ts b/components/table/row/TableRowEntity.ts index 114da20..3e53bd5 100644 --- a/components/table/row/TableRowEntity.ts +++ b/components/table/row/TableRowEntity.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentEntity, ComponentEntityContent } from "../../../entities/ComponentEntity"; +import { ComponentEntity, ComponentEntityContent } from "../../../entities/component/ComponentEntity"; import { TableColumnEntity } from "../column/TableColumnEntity"; import { TABLE_ROW_COMPONENT_NAME } from "./TableRowComponent"; diff --git a/components/title/TitleComponent.test.ts b/components/title/TitleComponent.test.ts index baf6f1a..7123830 100644 --- a/components/title/TitleComponent.test.ts +++ b/components/title/TitleComponent.test.ts @@ -1,4 +1,4 @@ -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import {createTitleComponent, TITLE_COMPONENT_NAME, TitleComponent} from "./TitleComponent"; describe('createTitleTextComponent', () => { diff --git a/components/title/TitleComponent.ts b/components/title/TitleComponent.ts index 03560af..3053509 100644 --- a/components/title/TitleComponent.ts +++ b/components/title/TitleComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../dto/ComponentDTO"; -import { HyperComponent } from "../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../entities/types/HyperComponent"; import { ComponentFactory } from "../../services/ComponentFactory"; export const TITLE_COMPONENT_NAME: string = 'TitleComponent'; diff --git a/components/title/TitleEntity.ts b/components/title/TitleEntity.ts index 6442344..ac7d087 100644 --- a/components/title/TitleEntity.ts +++ b/components/title/TitleEntity.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentEntity } from "../../entities/ComponentEntity"; +import { ComponentEntity } from "../../entities/component/ComponentEntity"; import { TITLE_COMPONENT_NAME } from "./TitleComponent"; export class TitleEntity extends ComponentEntity { diff --git a/dto/ColorDTO.ts b/dto/ColorDTO.ts deleted file mode 100644 index 6f7524c..0000000 --- a/dto/ColorDTO.ts +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2023. Heusala Group Oy . All rights reserved. - -import { explain, explainNot, explainOk, explainOr, explainProperty } from "../types/explain"; -import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../types/OtherKeys"; -import { explainRegularObject, isRegularObject } from "../types/RegularObject"; -import { explainString, isString } from "../types/String"; -import { isUndefined } from "../types/undefined"; -import { DTO } from "./types/DTO"; - -export interface ColorDTO extends DTO { - readonly value: string; -} - -export function createColorDTO ( - value : string -) : ColorDTO { - return { - value - }; -} - -export function isColorDTO (value: unknown) : value is ColorDTO { - return ( - isRegularObject(value) - && hasNoOtherKeysInDevelopment(value, [ - 'value', - ]) - && isString(value?.value) - ); -} - -export function explainColorDTO (value: any) : string { - return explain( - [ - explainRegularObject(value), - explainNoOtherKeysInDevelopment(value, [ - 'value', - ]) - , explainProperty("value", explainString(value?.value)) - ] - ); -} - -export function stringifyColorDTO (value : ColorDTO) : string { - return `ColorDTO(${value})`; -} - -export function parseColorDTO (value: unknown) : ColorDTO | undefined { - if (isColorDTO(value)) return value; - return undefined; -} - -export function isColorDTOOrUndefined (value: unknown): value is ColorDTO | undefined { - return isUndefined(value) || isColorDTO(value); -} - -export function explainColorDTOOrUndefined (value: unknown): string { - return isColorDTOOrUndefined(value) ? explainOk() : explainNot(explainOr(['ColorDTO', 'undefined'])); -} diff --git a/entities/BackgroundImageEntity.ts b/entities/BackgroundImageEntity.ts deleted file mode 100644 index 3a47936..0000000 --- a/entities/BackgroundImageEntity.ts +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 2023. Sendanor . All rights reserved. - -import { ReadonlyJsonObject } from "../Json"; -import { BackgroundImageDTO, createBackgroundImageDTO } from "../dto/BackgroundImageDTO"; -import { BackgroundImage } from "./types/BackgroundImage"; - -/** - * Background image entity. - */ -export class BackgroundImageEntity - implements BackgroundImage -{ - - /** - * Creates a background image entity. - * - * @param url - */ - public static create ( - url : string, - ) : BackgroundImageEntity { - return new BackgroundImageEntity( - url, - ); - } - - /** - * Creates a background image entity from DTO. - * - * @param value - */ - public static createFromDTO ( - value : BackgroundImageDTO, - ) : BackgroundImageEntity { - return BackgroundImageEntity.create( - value?.url, - ); - } - - public static url ( - url : string, - ) : BackgroundImageEntity { - return BackgroundImageEntity.create(url); - } - - private _url : string; - - protected constructor ( - url : string, - ) { - this._url = url; - } - - /** - * Returns the DTO object. - */ - public getDTO () : BackgroundImageDTO { - return createBackgroundImageDTO( - this._url, - ); - } - - /** - * @inheritDoc - */ - public valueOf() : ReadonlyJsonObject { - return this.toJSON(); - } - - /** - * @inheritDoc - */ - public toJSON () : ReadonlyJsonObject { - return this.getDTO() as unknown as ReadonlyJsonObject; - } - - /** - * @inheritDoc - */ - public getCssStyles (): string { - return `url(${this._url})`; - } - - /** - * @inheritDoc - */ - public getUrl () : string { - return this._url; - } - - /** - * @inheritDoc - */ - public url (value: string) : this { - this._url = value; - return this; - } - -} - -export function isBackgroundImageEntity (value: unknown): value is BackgroundImageEntity { - return value instanceof BackgroundImageEntity; -} diff --git a/entities/BorderEntity.ts b/entities/BorderEntity.ts deleted file mode 100644 index 6bfca97..0000000 --- a/entities/BorderEntity.ts +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (c) 2023. Sendanor . All rights reserved. - -import { ReadonlyJsonObject } from "../Json"; -import { isNumber } from "../types/Number"; -import { isString } from "../types/String"; -import { BorderDTO, createBorderDTO } from "../dto/BorderDTO"; -import { ColorDTO, createColorDTO } from "../dto/ColorDTO"; -import { createSizeDTO, SizeDTO } from "../dto/SizeDTO"; -import { BorderStyle } from "../dto/types/BorderStyle"; -import { ColorEntity, isColorEntity } from "./ColorEntity"; -import { - isSizeEntity, - SizeEntity, -} from "./SizeEntity"; -import { Border } from "./types/Border"; -import { Color, isColor } from "./types/Color"; -import { - isSize, - Size, -} from "./types/Size"; - -/** - * Border entity. - */ -export class BorderEntity - implements Border -{ - - /** - * Creates a border entity. - * - * @param style - * @param width - * @param color - */ - public static create ( - style ?: BorderStyle | undefined, - width ?: SizeDTO | undefined, - color ?: ColorDTO | undefined, - radius ?: SizeDTO | undefined, - ) : BorderEntity { - return new BorderEntity( - style ?? BorderStyle.NONE, - width, - color, - radius, - ); - } - - public static createEmptyBorder () : BorderEntity { - return this.create( - undefined, - undefined, - undefined, - undefined, - ); - } - - /** - * Creates a border entity from a DTO. - * - * @param dto - */ - public static createFromDTO ( - dto : BorderDTO, - ) : BorderEntity { - return BorderEntity.create( - dto?.style, - dto?.width, - dto?.color, - dto?.radius, - ); - } - - private _style : BorderStyle; - private _width : SizeDTO | undefined; - private _radius : SizeDTO | undefined; - private _color : ColorDTO | undefined; - - protected constructor ( - style : BorderStyle, - width : SizeDTO | undefined, - color : ColorDTO | undefined, - radius : SizeDTO | undefined, - ) { - this._style = style; - this._width = width; - this._color = color; - this._radius = radius; - } - - /** - * Returns the DTO object. - */ - public getDTO () : BorderDTO { - return createBorderDTO( - this._width, - this._style, - this._color, - this._radius, - ); - } - - /** - * @inheritDoc - */ - public valueOf() : ReadonlyJsonObject { - return this.toJSON(); - } - - /** - * @inheritDoc - */ - public toJSON () : ReadonlyJsonObject { - return this.getDTO() as unknown as ReadonlyJsonObject; - } - - public getCssStyles (): string { - return `${ this._width ? SizeEntity.createFromDTO(this._width).getCssStyles() : '0' } ${ - this._style - }${ this._color ? ' ' + ColorEntity.createFromDTO(this._color).getCssStyles() : '' }`; - } - - public setStyle (value : BorderStyle) : this { - this._style = value; - return this; - } - - public getStyle () : BorderStyle | undefined { - return this._style; - } - - public setWidth (value : Size | SizeEntity | SizeDTO | number | undefined) : this { - if (isSizeEntity(value)) { - this._width = value.getDTO(); - } else if (isSize(value)) { - this._width = value.getDTO(); - } else if (isNumber(value)) { - this._width = createSizeDTO(value); - } else { - this._width = value; - } - return this; - } - - public getWidth () : Size | undefined { - return this._width ? SizeEntity.createFromDTO(this._width) : undefined; - } - - public getWidthDTO () : SizeDTO | undefined { - return this._width; - } - - public setRadius (value : Size | SizeEntity | SizeDTO | number | undefined) : this { - if (isSizeEntity(value)) { - this._radius = value.getDTO(); - } else if (isSize(value)) { - this._radius = value.getDTO(); - } else if (isNumber(value)) { - this._radius = createSizeDTO(value); - } else { - this._radius = value; - } - return this; - } - - public getRadius () : Size | undefined { - return this._radius ? SizeEntity.createFromDTO(this._radius) : undefined; - } - - public getRadiusDTO () : SizeDTO | undefined { - return this._radius; - } - - public setColor (value : Color | ColorEntity | ColorDTO | string) : this { - if (isString(value)) { - this._color = createColorDTO( value ); - } else if (isColorEntity(value)) { - this._color = value.getDTO(); - } else if (isColor(value)) { - this._color = value.getDTO(); - } else { - this._color = value; - } - return this; - } - - public getColor () : Color | undefined { - return this._color ? ColorEntity.createFromDTO( this._color ) : undefined; - } - - public getColorDTO () : ColorDTO | undefined { - return this._color; - } - -} - -export function isBorderEntity (value: unknown): value is BorderEntity { - return value instanceof BorderEntity; -} diff --git a/entities/FontEntity.ts b/entities/FontEntity.ts deleted file mode 100644 index 3ec4336..0000000 --- a/entities/FontEntity.ts +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright (c) 2023. Sendanor . All rights reserved. - -import { ReadonlyJsonObject } from "../Json"; -import { FontDTO, createFontDTO } from "../dto/FontDTO"; -import { SizeDTO } from "../dto/SizeDTO"; -import { isSizeEntity, SizeEntity } from "./SizeEntity"; -import { Font } from "./types/Font"; -import { FontStyle } from "./types/FontStyle"; -import { FontVariant } from "./types/FontVariant"; -import { FontWeight } from "./types/FontWeight"; -import { Size, isSize } from "./types/Size"; - -/** - * Font entity. - */ -export class FontEntity - implements Font -{ - - /** - * Creates a font entity. - * - * @param value - */ - public static create ( - value ?: string | undefined, - ) : FontEntity { - return new FontEntity( - undefined, - undefined, - undefined, - undefined, - undefined, - value, - ); - } - - /** - * Creates a font entity from DTO. - * - * @param value - */ - public static createFromDTO ( - value : FontDTO, - ) : FontEntity { - return new FontEntity( - value?.style, - value?.variant, - value?.weight, - value?.size, - value?.lineHeight, - value?.family, - ); - } - - private _style : FontStyle | undefined; - private _variant : FontVariant | undefined; - private _weight : FontWeight | undefined; - private _size : SizeDTO | undefined; - private _lineHeight : SizeDTO | undefined; - private _family : string | undefined; - - protected constructor ( - style : FontStyle | undefined, - variant : FontVariant | undefined, - weight : FontWeight | undefined, - size : SizeDTO | undefined, - lineHeight : SizeDTO | undefined, - family : string | undefined, - ) { - this._style = style; - this._variant = variant; - this._weight = weight; - this._size = size; - this._lineHeight = lineHeight; - this._family = family; - } - - /** - * Returns the DTO object. - */ - public getDTO () : FontDTO { - return createFontDTO( - this._style, - this._variant, - this._weight, - this._size, - this._lineHeight, - this._family, - ); - } - - /** - * @inheritDoc - */ - public valueOf() : ReadonlyJsonObject { - return this.toJSON(); - } - - /** - * @inheritDoc - */ - public toJSON () : ReadonlyJsonObject { - return this.getDTO() as unknown as ReadonlyJsonObject; - } - - /** - * @inheritDoc - */ - public getCssStyles (): ReadonlyJsonObject { - return { - ...(this._style ? { fontStyle: this._style } : {}), - ...(this._variant ? { fontVariant: this._variant } : {}), - ...(this._weight ? { fontWeight: this._weight } : {}), - ...(this._size ? { fontSize: SizeEntity.createFromDTO(this._size).getCssStyles() } : {}), - ...(this._lineHeight ? { lineHeight: SizeEntity.createFromDTO(this._lineHeight).getCssStyles() } : {}), - ...(this._family ? { fontFamily: this._family } : {}), - }; - } - - - /** - * @inheritDoc - */ - public setFontStyle (value : FontStyle | undefined) : this { - this._style = value; - return this; - } - - /** - * @inheritDoc - */ - public getFontStyle () : FontStyle | undefined { - return this._style; - } - - - /** - * @inheritDoc - */ - public setFontVariant (value : FontVariant | undefined) : this { - this._variant = value; - return this; - } - - /** - * @inheritDoc - */ - public getFontVariant () : FontVariant | undefined { - return this._variant; - } - - - /** - * @inheritDoc - */ - public setFontWeight (value : FontWeight | undefined) : this { - this._weight = value; - return this; - } - - /** - * @inheritDoc - */ - public getFontWeight () : FontWeight | undefined { - return this._weight; - } - - - /** - * @inheritDoc - */ - public setFontSize (value : SizeEntity | Size | SizeDTO | undefined) : this { - if (isSizeEntity(value)) { - this._size = value.getDTO(); - } else if (isSize(value)) { - this._size = value.getDTO(); - } else { - this._size = value; - } - return this; - } - - /** - * @inheritDoc - */ - public getFontSize () : SizeDTO | undefined { - return this._size; - } - - - /** - * @inheritDoc - */ - public setLineHeight (value : SizeDTO | undefined) : this { - this._lineHeight = value; - return this; - } - - /** - * @inheritDoc - */ - public getLineHeight () : SizeDTO | undefined { - return this._lineHeight; - } - - - /** - * @inheritDoc - */ - public setFontFamily (value : string | undefined) : this { - this._family = value; - return this; - } - - /** - * @inheritDoc - */ - public getFontFamily () : string | undefined { - return this._family; - } - -} - -export function isFontEntity (value: unknown): value is FontEntity { - return value instanceof FontEntity; -} diff --git a/entities/StyleEntity.ts b/entities/StyleEntity.ts deleted file mode 100644 index b9c99dc..0000000 --- a/entities/StyleEntity.ts +++ /dev/null @@ -1,1398 +0,0 @@ -// Copyright (c) 2023. Heusala Group Oy . All rights reserved. - -import { map } from "../functions/map"; -import { reduce } from "../functions/reduce"; -import { ReadonlyJsonObject } from "../Json"; -import { isArray } from "../types/Array"; -import { isNumber } from "../types/Number"; -import { isString } from "../types/String"; -import { BackgroundDTO } from "../dto/BackgroundDTO"; -import { - BorderDTO, - createBorderDTO, - isBorderDTO, -} from "../dto/BorderDTO"; -import { - ColorDTO, - createColorDTO, -} from "../dto/ColorDTO"; -import { - createFontDTO, - FontDTO, -} from "../dto/FontDTO"; -import { - createSizeDTO, - isSizeDTO, - SizeDTO, -} from "../dto/SizeDTO"; -import { - createStyleDTO, - StyleDTO, -} from "../dto/StyleDTO"; -import { - TextDecorationDTO, -} from "../dto/TextDecorationDTO"; -import { BorderStyle } from "../dto/types/BorderStyle"; -import { BoxSizing } from "../dto/types/BoxSizing"; -import { TextAlign } from "../dto/types/TextAlign"; -import { BackgroundEntity, isBackgroundEntity } from "./BackgroundEntity"; -import { - BorderEntity, - isBorderEntity, -} from "./BorderEntity"; -import { - ColorEntity, - isColorEntity, -} from "./ColorEntity"; -import { - FontEntity, - isFontEntity, -} from "./FontEntity"; -import { - isSizeEntity, - SizeEntity, -} from "./SizeEntity"; -import { - isTextDecorationEntity, - TextDecorationEntity, -} from "./TextDecorationEntity"; -import { Background, isBackground } from "./types/Background"; -import { - Border, - isBorder, -} from "./types/Border"; -import { - Font, - isFont, -} from "./types/Font"; -import { isSize, Size } from "./types/Size"; -import { isStyle, Style } from "./types/Style"; -import { - isTextDecoration, - TextDecoration, -} from "./types/TextDecoration"; -import { UnitType } from "./types/UnitType"; - -const TOP_AND_BOTTOM_MARGIN_INDEX = 0; -const LEFT_AND_RIGHT_MARGIN_INDEX = 1; -const TOP_MARGIN_INDEX = 0; -const RIGHT_MARGIN_INDEX = 1; -const BOTTOM_MARGIN_INDEX = 2; -const LEFT_MARGIN_INDEX = 3; - -/** - * Style entity. - */ -export class StyleEntity - implements Style -{ - - /** - * Width of the element. - * - * @protected - */ - protected _width : SizeDTO | undefined; - - /** - * Height of the element. - * - * @protected - */ - protected _height : SizeDTO | undefined; - - /** - * Minimum width of the element. - * - * @protected - */ - protected _minWidth : SizeDTO | undefined; - - /** - * Maximum height of the element. - * - * @protected - */ - protected _maxHeight : SizeDTO | undefined; - - /** - * Maximum width of the element. - * - * @protected - */ - protected _maxWidth : SizeDTO | undefined; - - /** - * Minimum height of the element. - * - * @protected - */ - protected _minHeight : SizeDTO | undefined; - - /** - * Padding of the element. - * - * @protected - */ - protected _padding : SizeDTO | [SizeDTO, SizeDTO, SizeDTO, SizeDTO] | undefined; - - /** - * Margin of the element. - * - * @protected - */ - protected _margin : SizeDTO | [SizeDTO, SizeDTO, SizeDTO, SizeDTO] | undefined; - - /** - * Border element(s). - * - * @protected - */ - protected _border : BorderDTO | [BorderDTO, BorderDTO, BorderDTO, BorderDTO] | undefined; - - /** - * Text color. - * - * @protected - */ - protected _textColor : ColorDTO | undefined; - - /** - * Text alignment. - * - * @protected - */ - protected _textAlign : TextAlign | undefined; - - /** - * Box sizing. - * - * @protected - */ - protected _boxSizing : BoxSizing | undefined; - - /** - * Background options. - * - * @protected - */ - protected _background : BackgroundDTO | undefined; - - /** - * Font settings. - * - * @protected - */ - protected _font : FontDTO | undefined; - - /** - * Text decorations. - * - * @protected - */ - protected _textDecoration : TextDecorationDTO | undefined; - - public static create ( - ) : StyleEntity { - return new this( - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - } - - /** - * Construct a style entity. - * - * @param style - */ - public static createFromDTO ( - style ?: StyleDTO | undefined, - ) : StyleEntity { - return new this( - StyleEntity.prepareColorDTO(style?.textColor), - StyleEntity.prepareBackgroundDTO(style?.background), - StyleEntity.prepareSizeDTO(style?.width), - StyleEntity.prepareSizeDTO(style?.height), - StyleEntity.prepareSizeListDTO(style?.margin), - StyleEntity.prepareSizeListDTO(style?.padding), - StyleEntity.prepareBorderListDTO(style?.border), - StyleEntity.prepareFontDTO(style?.font), - style?.textDecoration, - StyleEntity.prepareSizeDTO(style?.minWidth), - StyleEntity.prepareSizeDTO(style?.minHeight), - StyleEntity.prepareSizeDTO(style?.maxWidth), - StyleEntity.prepareSizeDTO(style?.maxHeight), - style?.textAlign, - style?.boxSizing, - ); - } - - /** - * Construct a style entity. - * - * @param textColor - * @param background - * @param width - * @param height - * @param margin - * @param padding - * @param border - * @param font - * @param textDecoration - * @param minWidth - * @param minHeight - * @param maxWidth - * @param maxHeight - * @param textAlign - * @param boxSizing - * @protected - */ - protected constructor ( - textColor : ColorDTO | undefined, - background : BackgroundDTO | undefined, - width : SizeDTO | undefined, - height : SizeDTO | undefined, - margin : SizeDTO | [SizeDTO, SizeDTO, SizeDTO, SizeDTO] | undefined, - padding : SizeDTO | [SizeDTO, SizeDTO, SizeDTO, SizeDTO] | undefined, - border : BorderDTO | [BorderDTO, BorderDTO, BorderDTO, BorderDTO] | undefined, - font : FontDTO | undefined, - textDecoration : TextDecorationDTO | undefined, - minWidth : SizeDTO | undefined, - minHeight : SizeDTO | undefined, - maxWidth : SizeDTO | undefined, - maxHeight : SizeDTO | undefined, - textAlign : TextAlign | undefined, - boxSizing : BoxSizing | undefined, - ) { - this._textColor = textColor; - this._background = background; - this._width = width; - this._height = height; - this._margin = margin; - this._padding = padding; - this._border = border; - this._font = font; - this._textDecoration = textDecoration; - this._minWidth = minWidth; - this._minHeight = minHeight; - this._maxWidth = maxWidth; - this._maxHeight = maxHeight; - this._textAlign = textAlign; - this._boxSizing = boxSizing; - } - - public static prepareBackgroundDTO ( - value : BackgroundEntity | BackgroundDTO | undefined - ) : BackgroundDTO | undefined { - if (value === undefined) return undefined; - if (isBackgroundEntity(value)) return value.getDTO(); - if (isBackground(value)) return value.getDTO(); - return value; - } - - public static prepareColorDTO ( - value : ColorEntity | ColorDTO | string | undefined - ) : ColorDTO | undefined { - if (value === undefined) return undefined; - if (isString(value)) return createColorDTO(value); - if (isColorEntity(value)) return value.getDTO(); - return value; - } - - public static prepareSizeDTO ( - value : SizeEntity | Size | SizeDTO | number | undefined - ) : SizeDTO | undefined { - if (value === undefined) return undefined; - if (isNumber(value)) return createSizeDTO(value, UnitType.PX); - if (isSizeEntity(value)) return value.getDTO(); - if (isSize(value)) return value.getDTO(); - return value; - } - - public static prepareFontDTO ( - value : Font | FontEntity | FontDTO | number | string | undefined - ) : FontDTO | undefined { - if (value === undefined) return undefined; - if (isNumber(value)) { - return createFontDTO( - undefined, - undefined, - undefined, - SizeEntity.create(value).getDTO(), - undefined, - undefined, - ); - } - if (isString(value)) { - return createFontDTO( - undefined, - undefined, - undefined, - undefined, - undefined, - value, - ); - } - if (isFontEntity(value)) return value.getDTO(); - if (isFont(value)) return value.getDTO(); - return value; - } - - public static prepareBorderDTO ( - value : Border | BorderDTO | number | undefined - ) : BorderDTO | undefined { - if (value === undefined) return undefined; - if (isNumber(value)) { - return createBorderDTO( - createSizeDTO(value), - undefined, - undefined, - undefined, - ); - } - if (isBorderEntity(value)) return value.getDTO(); - if (isBorder(value)) return value.getDTO(); - return value; - } - - public static prepareSizeListDTO ( - value : ( - SizeEntity - | [ - SizeEntity | SizeDTO | number | undefined, - SizeEntity | SizeDTO | number | undefined, - ] - | [ - SizeEntity | SizeDTO | number | undefined, - SizeEntity | SizeDTO | number | undefined, - SizeEntity | SizeDTO | number | undefined, - SizeEntity | SizeDTO | number | undefined, - ] - | SizeDTO - | number - | undefined - ) - ) : SizeDTO | [SizeDTO, SizeDTO, SizeDTO, SizeDTO] | undefined { - if (value === undefined) return undefined; - if (isNumber(value)) return createSizeDTO(value, UnitType.PX); - if (isSizeEntity(value)) return value.getDTO(); - if (isArray(value)) { - - if (value.length === 2) { - const top_and_bottom : SizeDTO | undefined = StyleEntity.prepareSizeDTO(value[TOP_AND_BOTTOM_MARGIN_INDEX]); - if (!top_and_bottom) throw new TypeError(`prepareSizeListDTO: Invalid [undefined, *] array provided`); - const right_and_left: SizeDTO | undefined = StyleEntity.prepareSizeDTO(value[LEFT_AND_RIGHT_MARGIN_INDEX]); - if (!right_and_left) throw new TypeError(`prepareSizeListDTO: Invalid [SizeDTO, undefined] array provided`); - return [ - top_and_bottom, // top - right_and_left, // right - top_and_bottom, // bottom - right_and_left, // left - ]; - } - - if (value.length === 4) { - const top : SizeDTO | undefined = StyleEntity.prepareSizeDTO( value[TOP_MARGIN_INDEX] ); - if (!top) throw new TypeError(`prepareSizeListDTO: Invalid [undefined, *, *, *] array provided`); - const right : SizeDTO | undefined = StyleEntity.prepareSizeDTO( value[RIGHT_MARGIN_INDEX] ); - if (!right) throw new TypeError(`prepareSizeListDTO: Invalid [SizeDTO, undefined, *, *] array provided`); - const bottom : SizeDTO | undefined = StyleEntity.prepareSizeDTO( value[BOTTOM_MARGIN_INDEX] ); - if (!bottom) throw new TypeError(`prepareSizeListDTO: Invalid [SizeDTO, SizeDTO, undefined, *] array provided`); - const left : SizeDTO | undefined = StyleEntity.prepareSizeDTO( value[LEFT_MARGIN_INDEX] ); - if (!left) throw new TypeError(`prepareSizeListDTO: Invalid [SizeDTO, SizeDTO, SizeDTO, undefined] array provided`); - return [ - top, - right, - bottom, - left, - ]; - } - - // Runtime assert, should not happen. - // @ts-ignore - throw new TypeError(`prepareSizeListDTO: Incorrect array length: ${value.length}`); - - } - return value; - } - - public static prepareBorderListDTO ( - value : ( - Border - | [ - Border | BorderDTO | number | undefined, - Border | BorderDTO | number | undefined, - ] - | [ - Border | BorderDTO | number | undefined, - Border | BorderDTO | number | undefined, - Border | BorderDTO | number | undefined, - Border | BorderDTO | number | undefined, - ] - | BorderDTO - | number - | undefined - ) - ) : BorderDTO | [BorderDTO, BorderDTO, BorderDTO, BorderDTO] | undefined { - if (value === undefined) return undefined; - if (isNumber(value)) { - return createBorderDTO( - createSizeDTO( value ), - undefined, - undefined, - undefined, - ); - } - if (isBorderEntity(value)) return value.getDTO(); - if (isBorder(value)) return value.getDTO(); - if (isArray(value)) { - - if (value.length === 2) { - const top_and_bottom : BorderDTO | undefined = StyleEntity.prepareBorderDTO(value[TOP_AND_BOTTOM_MARGIN_INDEX]); - if (!top_and_bottom) throw new TypeError(`prepareBorderListDTO: Invalid [undefined, *] array provided`); - const right_and_left: BorderDTO | undefined = StyleEntity.prepareBorderDTO(value[LEFT_AND_RIGHT_MARGIN_INDEX]); - if (!right_and_left) throw new TypeError(`prepareBorderListDTO: Invalid [BorderDTO, undefined] array provided`); - return [ - top_and_bottom, // top - right_and_left, // right - top_and_bottom, // bottom - right_and_left, // left - ]; - } - - if (value.length === 4) { - const top : BorderDTO | undefined = StyleEntity.prepareBorderDTO( value[0] ); - if (!top) throw new TypeError(`prepareBorderListDTO: Invalid [undefined, *, *, *] array provided`); - const right : BorderDTO | undefined = StyleEntity.prepareBorderDTO( value[1] ); - if (!right) throw new TypeError(`prepareBorderListDTO: Invalid [BorderDTO, undefined, *, *] array provided`); - const bottom : BorderDTO | undefined = StyleEntity.prepareBorderDTO( value[2] ); - if (!bottom) throw new TypeError(`prepareBorderListDTO: Invalid [BorderDTO, BorderDTO, undefined, *] array provided`); - const left : BorderDTO | undefined = StyleEntity.prepareBorderDTO( value[3] ); - if (!left) throw new TypeError(`prepareBorderListDTO: Invalid [BorderDTO, BorderDTO, BorderDTO, undefined] array provided`); - return [ - top, - right, - bottom, - left, - ]; - } - - // Runtime assert, should not happen. - // @ts-ignore - throw new TypeError(`prepareBorderListDTO: Incorrect array length: ${value.length}`); - - } - return value; - } - - public static prepareSizeListCssStyles ( - key : string, - value : SizeDTO | [SizeDTO, SizeDTO, SizeDTO, SizeDTO] | undefined - ) : ReadonlyJsonObject { - - if (isSizeDTO(value)) { - return { - [key]: SizeEntity.createFromDTO(value).getCssStyles() - }; - } - - if (isArray(value)) { - return { - [key]: map( - value, - (item: SizeDTO) : string => SizeEntity.createFromDTO(item).getCssStyles() - ).join(' ') - }; - } - - return {}; - - } - - public static prepareBorderListCssStyles ( - value : BorderDTO | [BorderDTO, BorderDTO, BorderDTO, BorderDTO] | undefined - ) : ReadonlyJsonObject { - - if (isBorderDTO(value)) { - return { - border: BorderEntity.createFromDTO(value).getCssStyles() - }; - } - - if (isArray(value)) { - return { - borderStyle: map( - value, - (item: BorderDTO) : string => (BorderEntity.createFromDTO(item).getStyle() ?? BorderStyle.NONE), - ).join(' '), - borderWidth: map( - value, - (item: BorderDTO) : string => (BorderEntity.createFromDTO(item).getWidth() ?? SizeEntity.createZero()).getCssStyles(), - ).join(' '), - borderColor: map( - value, - (item: BorderDTO) : string => (BorderEntity.createFromDTO(item).getColor() ?? ColorEntity.createTransparent()).getCssStyles(), - ).join(' '), - }; - } - - return {}; - - } - - /** - * - * @param style - */ - public static getCssStyles ( - style: Style, - ) : ReadonlyJsonObject { - return style.getCssStyles(); - } - - public static merge ( - ...values: readonly (StyleDTO | Style | StyleEntity)[] - ) : StyleEntity { - return StyleEntity.createFromDTO( - reduce( - values, - ( - prev: StyleDTO, - item: StyleDTO | Style | StyleEntity, - ) : StyleDTO => { - const dto : StyleDTO = this.toDTO(item); - return { - ...prev, - ...dto, - }; - }, - createStyleDTO( - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ), - ) - ); - } - - public static toDTO ( - value: StyleDTO | Style | StyleEntity, - ) : StyleDTO { - if (isStyleEntity(value)) { - return value.getDTO(); - } else if (isStyle(value)) { - return value.getDTO(); - } else { - return value; - } - } - - - - /** - * @inheritDoc - */ - public getDTO () : StyleDTO { - return createStyleDTO( - this._textColor, - this._background, - this._width, - this._height, - this._margin, - this._padding, - this._border, - this._font, - this._textDecoration, - this._minWidth, - this._minHeight, - this._maxWidth, - this._maxHeight, - this._textAlign, - this._boxSizing, - ); - } - - /** - * @inheritDoc - */ - public valueOf() : ReadonlyJsonObject { - return this.toJSON(); - } - - /** - * @inheritDoc - */ - public toJSON () : ReadonlyJsonObject { - return this.getDTO() as unknown as ReadonlyJsonObject; - } - - /** - * @inheritDoc - */ - public getWidth () : SizeEntity | undefined { - return this._width ? SizeEntity.createFromDTO(this._width) : undefined; - } - - /** - * @inheritDoc - */ - public getWidthDTO () : SizeDTO | undefined { - return this._width; - } - - /** - * @inheritDoc - */ - public setWidth (value: Size | SizeEntity | number | undefined) : this { - this._width = StyleEntity.prepareSizeDTO(value); - return this; - } - - - /** - * @inheritDoc - */ - public getHeight () : SizeEntity | undefined { - return this._height ? SizeEntity.createFromDTO(this._height) : undefined; - } - - /** - * @inheritDoc - */ - public getHeightDTO () : SizeDTO | undefined { - return this._height; - } - - /** - * @inheritDoc - */ - public setHeight (value: Size | SizeEntity | number | undefined) : this { - this._height = StyleEntity.prepareSizeDTO(value); - return this; - } - - - /** - * @inheritDoc - */ - public getMinWidth () : SizeEntity | undefined { - return this._minWidth ? SizeEntity.createFromDTO(this._minWidth) : undefined; - } - - /** - * @inheritDoc - */ - public getMinWidthDTO () : SizeDTO | undefined { - return this._minWidth; - } - - /** - * @inheritDoc - */ - public setMinWidth (value: Size | SizeEntity | number | undefined) : this { - this._minWidth = StyleEntity.prepareSizeDTO(value); - return this; - } - - - /** - * @inheritDoc - */ - public getMinHeight () : SizeEntity | undefined { - return this._minHeight ? SizeEntity.createFromDTO(this._minHeight) : undefined; - } - - /** - * @inheritDoc - */ - public getMinHeightDTO () : SizeDTO | undefined { - return this._minHeight; - } - - /** - * @inheritDoc - */ - public setMinHeight (value: Size | SizeEntity | number | undefined) : this { - this._minHeight = StyleEntity.prepareSizeDTO(value); - return this; - } - - - /** - * @inheritDoc - */ - public getMaxWidth () : SizeEntity | undefined { - return this._maxWidth ? SizeEntity.createFromDTO(this._maxWidth) : undefined; - } - - /** - * @inheritDoc - */ - public getMaxWidthDTO () : SizeDTO | undefined { - return this._maxWidth; - } - - /** - * @inheritDoc - */ - public setMaxWidth (value: Size | SizeEntity | number | undefined) : this { - this._maxWidth = StyleEntity.prepareSizeDTO(value); - return this; - } - - - /** - * @inheritDoc - */ - public getMaxHeight () : SizeEntity | undefined { - return this._maxHeight ? SizeEntity.createFromDTO(this._maxHeight) : undefined; - } - - /** - * @inheritDoc - */ - public getMaxHeightDTO () : SizeDTO | undefined { - return this._maxHeight; - } - - /** - * @inheritDoc - */ - public setMaxHeight (value: Size | SizeEntity | number | undefined) : this { - this._maxHeight = StyleEntity.prepareSizeDTO(value); - return this; - } - - - /** - * @inheritDoc - */ - public getTextColor () : ColorEntity | undefined { - return this._textColor ? ColorEntity.create(this._textColor.value) : undefined; - } - - /** - * @inheritDoc - */ - public setTextColor (value: ColorEntity | string | undefined) : this { - this._textColor = StyleEntity.prepareColorDTO(value); - return this; - } - - /** - * @inheritDoc - */ - public getTextAlign () : TextAlign | undefined { - return this._textAlign; - } - - /** - * @inheritDoc - */ - public setTextAlign (value: TextAlign | undefined) : this { - this._textAlign = value; - return this; - } - - /** - * @inheritDoc - */ - public getBoxSizing () : BoxSizing | undefined { - return this._boxSizing; - } - - /** - * @inheritDoc - */ - public setBoxSizing (value: BoxSizing | undefined) : this { - this._boxSizing = value; - return this; - } - - /** - * @inheritDoc - */ - public getTextDecoration () : TextDecorationEntity | undefined { - return this._textDecoration ? TextDecorationEntity.createFromDTO(this._textDecoration) : undefined; - } - - /** - * @inheritDoc - */ - public getTextDecorationDTO () : TextDecorationDTO | undefined { - return this._textDecoration; - } - - /** - * @inheritDoc - */ - public setTextDecoration (value: TextDecoration | TextDecorationEntity | TextDecorationDTO | undefined) : this { - if (isTextDecorationEntity(value)) { - this._textDecoration = value.getDTO(); - } else if (isTextDecoration(value)) { - this._textDecoration = value.getDTO(); - } else { - this._textDecoration = value; - } - return this; - } - - /** - * @inheritDoc - */ - public getBackgroundColor () : ColorEntity | undefined { - const color = this._background?.color; - return color ? ColorEntity.createFromDTO(color) : undefined; - } - - /** - * @inheritDoc - */ - public getBackgroundColorDTO () : ColorDTO | undefined { - const color = this._background?.color; - return color ? color : undefined; - } - - /** - * @inheritDoc - */ - public setBackgroundColor (value: ColorEntity | string | undefined) : this { - if (this._background === undefined) { - this._background = BackgroundEntity.color(value).getDTO(); - } else { - this._background = BackgroundEntity.createFromDTO(this._background).color(value).getDTO(); - } - return this; - } - - /** - * @inheritDoc - */ - public getFontDTO () : FontDTO | undefined { - return this._font ? this._font : undefined; - } - - /** - * @inheritDoc - */ - public getFont () : Font | undefined { - return this._font ? FontEntity.createFromDTO(this._font) : undefined; - } - - /** - * @inheritDoc - */ - public setFont (value: FontEntity | Font | string | number | undefined) : this { - this._font = StyleEntity.prepareFontDTO(value); - return this; - } - - - /** - * @inheritDoc - */ - public getMargin () : SizeDTO | [SizeDTO, SizeDTO] | [SizeDTO, SizeDTO, SizeDTO, SizeDTO] | undefined { - return this._margin; - } - - public getTopMargin () : SizeDTO | undefined { - if (isArray(this._margin)) { - return this._margin[0]; - } - return this._margin; - } - - public getBottomMargin () : SizeDTO | undefined { - if (isArray(this._margin)) { - return this._margin[2]; - } - return this._margin; - } - - public getRightMargin () : SizeDTO | undefined { - if (isArray(this._margin)) { - return this._margin[1]; - } - return this._margin; - } - - public getLeftMargin () : SizeDTO | undefined { - if (isArray(this._margin)) { - return this._margin[3]; - } - return this._margin; - } - - /** - * @inheritDoc - */ - public setMargin (value: SizeEntity | SizeDTO | number | undefined) : this { - this._margin = StyleEntity.prepareSizeDTO(value); - return this; - } - - /** - * @inheritDoc - */ - public setTopMargin (value: SizeEntity | SizeDTO | number | undefined) : this { - if (this._margin === undefined) { - const empty = SizeEntity.createZero().getDTO(); - this._margin = [ - StyleEntity.prepareSizeDTO(value) ?? empty, // top - empty, // right - empty, // bottom - empty, // left - ]; - } else if (isArray(this._margin)) { - this._margin[TOP_MARGIN_INDEX] = StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(); - } else { - this._margin = [ - StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(), // top - this._margin, // right - this._margin, // bottom - this._margin, // left - ]; - } - return this; - } - - /** - * @inheritDoc - */ - public setBottomMargin (value: SizeEntity | SizeDTO | number | undefined) : this { - if (this._margin === undefined) { - const empty = SizeEntity.createZero().getDTO(); - this._margin = [ - empty, // top - empty, // right - StyleEntity.prepareSizeDTO(value) ?? empty, // bottom - empty, // left - ]; - } else if (isArray(this._margin)) { - this._margin[BOTTOM_MARGIN_INDEX] = StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(); - } else { - this._margin = [ - this._margin, // top - this._margin, // right - StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(), // bottom - this._margin, // left - ]; - } - return this; - } - - /** - * @inheritDoc - */ - public setRightMargin (value: SizeEntity | SizeDTO | number | undefined) : this { - if (this._margin === undefined) { - const empty = SizeEntity.createZero().getDTO(); - this._margin = [ - empty, // top - StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(), // right - empty, // bottom - empty, // left - ]; - } else if (isArray(this._margin)) { - this._margin[RIGHT_MARGIN_INDEX] = StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(); - } else { - this._margin = [ - this._margin, // top - StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(), // right - this._margin, // bottom - this._margin, // left - ]; - } - return this; - } - - /** - * @inheritDoc - */ - public setLeftMargin (value: SizeEntity | SizeDTO | number | undefined) : this { - if (this._margin === undefined) { - const empty = SizeEntity.createZero().getDTO(); - this._margin = [ - empty, // top - empty, // right - empty, // bottom - StyleEntity.prepareSizeDTO(value) ?? empty, // left - ]; - } else if (isArray(this._margin)) { - this._margin[LEFT_MARGIN_INDEX] = StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(); - } else { - this._margin = [ - this._margin, // top - this._margin, // right - this._margin, // bottom - StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(), // left - ]; - } - return this; - } - - - - /** - * @inheritDoc - */ - public getPadding () : SizeDTO | [SizeDTO, SizeDTO] | [SizeDTO, SizeDTO, SizeDTO, SizeDTO] | undefined { - return this._padding; - } - - public getTopPadding () : SizeDTO | undefined { - if (isArray(this._padding)) { - return this._padding[0]; - } - return this._padding; - } - - public getBottomPadding () : SizeDTO | undefined { - if (isArray(this._padding)) { - return this._padding[2]; - } - return this._padding; - } - - public getRightPadding () : SizeDTO | undefined { - if (isArray(this._padding)) { - return this._padding[1]; - } - return this._padding; - } - - public getLeftPadding () : SizeDTO | undefined { - if (isArray(this._padding)) { - return this._padding[3]; - } - return this._padding; - } - - /** - * @inheritDoc - */ - public setPadding (value: SizeEntity | SizeDTO | number | undefined) : this { - this._padding = StyleEntity.prepareSizeDTO(value); - return this; - } - - /** - * @inheritDoc - */ - public setTopPadding (value: SizeEntity | SizeDTO | number | undefined) : this { - if (this._padding === undefined) { - const empty = SizeEntity.createZero().getDTO(); - this._padding = [ - StyleEntity.prepareSizeDTO(value) ?? empty, // top - empty, // right - empty, // bottom - empty, // left - ]; - } else if (isArray(this._padding)) { - this._padding[TOP_MARGIN_INDEX] = StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(); - } else { - this._padding = [ - StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(), // top - this._padding, // right - this._padding, // bottom - this._padding, // left - ]; - } - return this; - } - - /** - * @inheritDoc - */ - public setBottomPadding (value: SizeEntity | SizeDTO | number | undefined) : this { - if (this._padding === undefined) { - const empty = SizeEntity.createZero().getDTO(); - this._padding = [ - empty, // top - empty, // right - StyleEntity.prepareSizeDTO(value) ?? empty, // bottom - empty, // left - ]; - } else if (isArray(this._padding)) { - this._padding[BOTTOM_MARGIN_INDEX] = StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(); - } else { - this._padding = [ - this._padding, // top - this._padding, // right - StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(), // bottom - this._padding, // left - ]; - } - return this; - } - - /** - * @inheritDoc - */ - public setRightPadding (value: SizeEntity | SizeDTO | number | undefined) : this { - if (this._padding === undefined) { - const empty = SizeEntity.createZero().getDTO(); - this._padding = [ - empty, // top - StyleEntity.prepareSizeDTO(value) ?? empty, // right - empty, // bottom - empty, // left - ]; - } else if (isArray(this._padding)) { - this._padding[RIGHT_MARGIN_INDEX] = StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(); - } else { - this._padding = [ - this._padding, // top - StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(), // right - this._padding, // bottom - this._padding, // left - ]; - } - return this; - } - - /** - * @inheritDoc - */ - public setLeftPadding (value: SizeEntity | SizeDTO | number | undefined) : this { - if (this._padding === undefined) { - const empty = SizeEntity.createZero().getDTO(); - this._padding = [ - empty, // top - empty, // right - empty, // bottom - StyleEntity.prepareSizeDTO(value) ?? empty, // left - ]; - } else if (isArray(this._padding)) { - this._padding[LEFT_MARGIN_INDEX] = StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(); - } else { - this._padding = [ - this._padding, // top - this._padding, // right - this._padding, // bottom - StyleEntity.prepareSizeDTO(value) ?? SizeEntity.createZero().getDTO(), // left - ]; - } - return this; - } - - - - - - - /** - * @inheritDoc - */ - public getBorder () : BorderDTO | [BorderDTO, BorderDTO] | [BorderDTO, BorderDTO, BorderDTO, BorderDTO] | undefined { - return this._border; - } - - public getTopBorder () : BorderDTO | undefined { - if (isArray(this._border)) { - return this._border[0]; - } - return this._border; - } - - public getBottomBorder () : BorderDTO | undefined { - if (isArray(this._border)) { - return this._border[2]; - } - return this._border; - } - - public getRightBorder () : BorderDTO | undefined { - if (isArray(this._border)) { - return this._border[1]; - } - return this._border; - } - - public getLeftBorder () : BorderDTO | undefined { - if (isArray(this._border)) { - return this._border[3]; - } - return this._border; - } - - /** - * @inheritDoc - */ - public setBorder ( - value: Border | BorderDTO | number | undefined - ) : this { - this._border = StyleEntity.prepareBorderDTO(value); - return this; - } - - /** - * @inheritDoc - */ - public setTopBorder (value: Border | BorderDTO | number | undefined) : this { - if (this._border === undefined) { - const empty = BorderEntity.createEmptyBorder().getDTO(); - this._border = [ - StyleEntity.prepareBorderDTO(value) ?? empty, // top - empty, // right - empty, // bottom - empty, // left - ]; - } else if (isArray(this._border)) { - this._border[TOP_MARGIN_INDEX] = StyleEntity.prepareBorderDTO(value) ?? BorderEntity.createEmptyBorder().getDTO(); - } else { - this._border = [ - StyleEntity.prepareBorderDTO(value) ?? BorderEntity.createEmptyBorder().getDTO(), // top - this._border, // right - this._border, // bottom - this._border, // left - ]; - } - return this; - } - - /** - * @inheritDoc - */ - public setBottomBorder (value: Border | BorderDTO | number | undefined) : this { - if (this._border === undefined) { - const empty = BorderEntity.createEmptyBorder().getDTO(); - this._border = [ - empty, // top - empty, // right - StyleEntity.prepareBorderDTO(value) ?? empty, // bottom - empty, // left - ]; - } else if (isArray(this._border)) { - this._border[BOTTOM_MARGIN_INDEX] = StyleEntity.prepareBorderDTO(value) ?? BorderEntity.createEmptyBorder().getDTO(); - } else { - this._border = [ - this._border, // top - this._border, // right - StyleEntity.prepareBorderDTO(value) ?? BorderEntity.createEmptyBorder().getDTO(), // bottom - this._border, // left - ]; - } - return this; - } - - /** - * @inheritDoc - */ - public setRightBorder (value: Border | BorderDTO | number | undefined) : this { - if (this._border === undefined) { - const empty = BorderEntity.createEmptyBorder().getDTO(); - this._border = [ - empty, // top - StyleEntity.prepareBorderDTO(value) ?? empty, // right - empty, // bottom - empty, // left - ]; - } else if (isArray(this._border)) { - this._border[RIGHT_MARGIN_INDEX] = StyleEntity.prepareBorderDTO(value) ?? BorderEntity.createEmptyBorder().getDTO(); - } else { - this._border = [ - this._border, // top - StyleEntity.prepareBorderDTO(value) ?? BorderEntity.createEmptyBorder().getDTO(), // right - this._border, // bottom - this._border, // left - ]; - } - return this; - } - - /** - * @inheritDoc - */ - public setLeftBorder (value: Border | BorderDTO | number | undefined) : this { - const v = StyleEntity.prepareBorderDTO(value); - if (this._border === undefined) { - const empty = BorderEntity.createEmptyBorder().getDTO(); - this._border = [ - empty, // top - empty, // right - empty, // bottom - v ?? empty, // left - ]; - } else if (isArray(this._border)) { - this._border[LEFT_MARGIN_INDEX] = v ?? BorderEntity.createEmptyBorder().getDTO(); - } else { - this._border = [ - this._border, // top - this._border, // right - this._border, // bottom - v ?? BorderEntity.createEmptyBorder().getDTO(), // left - ]; - } - return this; - } - - public setBackground (value: Background | BackgroundEntity | undefined): this { - if (isBackgroundEntity(value)) { - this._background = value.getDTO(); - } else if (isBackground(value)) { - this._background = value.getDTO(); - } else { - this._background = value; - } - return this; - } - - public getBackground (): Background | undefined { - return this._background ? BackgroundEntity.createFromDTO(this._background) : undefined; - } - - public getBackgroundDTO (): BackgroundDTO | undefined { - return this._background; - } - - public getCssStyles () : ReadonlyJsonObject { - return { - ...(this._textColor ? { color: ColorEntity.createFromDTO(this._textColor).getCssStyles() } : {}), - ...(this._textAlign ? { textAlign: this._textAlign } : {}), - ...(this._boxSizing ? { boxSizing: this._boxSizing } : {}), - ...(this._background ? BackgroundEntity.createFromDTO(this._background).getCssStyles() : {}), - ...(this._width ? { width: SizeEntity.createFromDTO(this._width).getCssStyles() } : {}), - ...(this._height ? { height: SizeEntity.createFromDTO(this._height).getCssStyles() } : {}), - ...(this._minWidth ? { minWidth: SizeEntity.createFromDTO(this._minWidth).getCssStyles() } : {}), - ...(this._minHeight ? { minHeight: SizeEntity.createFromDTO(this._minHeight).getCssStyles() } : {}), - ...(this._maxWidth ? { maxWidth: SizeEntity.createFromDTO(this._maxWidth).getCssStyles() } : {}), - ...(this._maxHeight ? { maxHeight: SizeEntity.createFromDTO(this._maxHeight).getCssStyles() } : {}), - ...(this._margin ? StyleEntity.prepareSizeListCssStyles("margin", this._margin) : {}), - ...(this._padding ? StyleEntity.prepareSizeListCssStyles("padding", this._padding) : {}), - ...(this._border ? StyleEntity.prepareBorderListCssStyles( this._border ) : {}), - ...(this._font ? FontEntity.createFromDTO(this._font).getCssStyles() : {}), - ...(this._textDecoration ? TextDecorationEntity.createFromDTO(this._textDecoration).getCssStyles() : {}), - }; - } - -} - -export function isStyleEntity (value: unknown): value is StyleEntity { - return value instanceof StyleEntity; -} diff --git a/entities/TextDecorationEntity.ts b/entities/TextDecorationEntity.ts deleted file mode 100644 index 81e40c9..0000000 --- a/entities/TextDecorationEntity.ts +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright (c) 2023. Sendanor . All rights reserved. - -import { ReadonlyJsonObject } from "../Json"; -import { ColorDTO } from "../dto/ColorDTO"; -import { TextDecorationDTO, createTextDecorationDTO } from "../dto/TextDecorationDTO"; -import { SizeDTO } from "../dto/SizeDTO"; -import { - ColorEntity, - isColorEntity, -} from "./ColorEntity"; -import { isSizeEntity, SizeEntity } from "./SizeEntity"; -import { - Color, - isColor, -} from "./types/Color"; -import { TextDecoration } from "./types/TextDecoration"; -import { TextDecorationLineType } from "./types/TextDecorationLineType"; -import { TextDecorationStyle } from "./types/TextDecorationStyle"; -import { Size, isSize } from "./types/Size"; - -/** - * Text decoration entity. - */ -export class TextDecorationEntity - implements TextDecoration -{ - - /** - * Creates a text decoration entity. - * - * @param lineType - */ - public static create ( - lineType ?: TextDecorationLineType | undefined, - ) : TextDecorationEntity { - return new TextDecorationEntity( - lineType, - undefined, - undefined, - undefined, - ); - } - - /** - * Creates a font entity from DTO. - * - * @param value - */ - public static createFromDTO ( - value : TextDecorationDTO, - ) : TextDecorationEntity { - return new TextDecorationEntity( - value?.lineType, - value?.color, - value?.style, - value?.thickness, - ); - } - - private _lineType : TextDecorationLineType | undefined; - private _color : ColorDTO | undefined; - private _style : TextDecorationStyle | undefined; - private _thickness : SizeDTO | undefined; - - protected constructor ( - lineType : TextDecorationLineType | undefined, - color : ColorDTO | undefined, - style : TextDecorationStyle | undefined, - thickness : SizeDTO | undefined, - ) { - this._lineType = lineType; - this._color = color; - this._style = style; - this._thickness = thickness; - } - - /** - * Returns the DTO object. - */ - public getDTO () : TextDecorationDTO { - return createTextDecorationDTO( - this._lineType, - this._color, - this._style, - this._thickness, - ); - } - - /** - * @inheritDoc - */ - public valueOf() : ReadonlyJsonObject { - return this.toJSON(); - } - - /** - * @inheritDoc - */ - public toJSON () : ReadonlyJsonObject { - return this.getDTO() as unknown as ReadonlyJsonObject; - } - - /** - * @inheritDoc - */ - public getCssStyles (): ReadonlyJsonObject { - return { - ...(this._lineType ? { textDecorationLine: this._lineType } : {}), - ...(this._color ? { textDecorationColor: ColorEntity.createFromDTO(this._color).getCssStyles() } : {}), - ...(this._style ? { textDecorationStyle: this._style } : {}), - ...(this._thickness ? { textDecorationThickness: SizeEntity.createFromDTO( this._thickness ).getCssStyles() } : {}), - }; - } - - - /** - * @inheritDoc - */ - public setLineType (value : TextDecorationLineType | undefined) : this { - this._lineType = value; - return this; - } - - /** - * @inheritDoc - */ - public getLineType () : TextDecorationLineType | undefined { - return this._lineType; - } - - - - /** - * @inheritDoc - */ - public setColor (value : Color | ColorDTO | undefined) : this { - if (isColorEntity(value)) { - this._color = value.getDTO(); - } else if (isColor(value)) { - this._color = value.getDTO(); - } else { - this._color = value; - } - return this; - } - - /** - * @inheritDoc - */ - public getColor () : Color | undefined { - return this._color ? ColorEntity.createFromDTO(this._color) : undefined; - } - - /** - * @inheritDoc - */ - public getColorDTO () : ColorDTO | undefined { - return this._color; - } - - - /** - * @inheritDoc - */ - public setStyle (value : TextDecorationStyle | undefined) : this { - this._style = value; - return this; - } - - /** - * @inheritDoc - */ - public getStyle () : TextDecorationStyle | undefined { - return this._style; - } - - - /** - * @inheritDoc - */ - public setThickness (value : SizeEntity | Size | SizeDTO | undefined) : this { - if (isSizeEntity(value)) { - this._thickness = value.getDTO(); - } else if (isSize(value)) { - this._thickness = value.getDTO(); - } else { - this._thickness = value; - } - return this; - } - - /** - * @inheritDoc - */ - public getThickness () : Size | undefined { - return this._thickness ? SizeEntity.createFromDTO(this._thickness) : undefined; - } - - /** - * @inheritDoc - */ - public getThicknessDTO () : SizeDTO | undefined { - return this._thickness; - } - -} - -export function isTextDecorationEntity (value: unknown): value is TextDecorationEntity { - return value instanceof TextDecorationEntity; -} diff --git a/dto/ActionDTO.ts b/entities/action/ActionDTO.ts similarity index 94% rename from dto/ActionDTO.ts rename to entities/action/ActionDTO.ts index d8fa95e..97e0cbc 100644 --- a/dto/ActionDTO.ts +++ b/entities/action/ActionDTO.ts @@ -1,12 +1,12 @@ // Copyright (c) 2023. Heusala Group Oy . All rights reserved. -import { isReadonlyJsonObjectOrUndefined, ReadonlyJsonObject } from "../Json"; -import { explain, explainNot, explainOk, explainOr, explainProperty } from "../types/explain"; -import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../types/OtherKeys"; -import { explainRegularObject, isRegularObject } from "../types/RegularObject"; -import { explainString, isString } from "../types/String"; -import { isUndefined } from "../types/undefined"; -import { DTO } from "./types/DTO"; +import { isReadonlyJsonObjectOrUndefined, ReadonlyJsonObject } from "../../Json"; +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; +import { explainString, isString } from "../../types/String"; +import { isUndefined } from "../../types/undefined"; +import { DTO } from "../types/DTO"; export interface ActionDTO extends DTO { diff --git a/entities/types/App.ts b/entities/app/App.ts similarity index 79% rename from entities/types/App.ts rename to entities/app/App.ts index 8ad2c32..d59b88f 100644 --- a/entities/types/App.ts +++ b/entities/app/App.ts @@ -1,14 +1,14 @@ // Copyright (c) 2023. Sendanor . All rights reserved. import { ReadonlyJsonObject } from "../../Json"; -import { ComponentDTO } from "../../dto/ComponentDTO"; -import { AppDTO } from "../../dto/AppDTO"; -import { RouteDTO } from "../../dto/RouteDTO"; -import { ViewDTO } from "../../dto/ViewDTO"; -import { ComponentEntity } from "../ComponentEntity"; -import { ExtendableEntity } from "./ExtendableEntity"; -import { RouteEntity } from "../RouteEntity"; -import { ViewEntity } from "../ViewEntity"; +import { ComponentDTO } from "../component/ComponentDTO"; +import { AppDTO } from "./AppDTO"; +import { RouteDTO } from "../route/RouteDTO"; +import { ViewDTO } from "../view/ViewDTO"; +import { ComponentEntity } from "../component/ComponentEntity"; +import { ExtendableEntity } from "../types/ExtendableEntity"; +import { RouteEntity } from "../route/RouteEntity"; +import { ViewEntity } from "../view/ViewEntity"; /** * Interface for application definitions. diff --git a/dto/AppDTO.ts b/entities/app/AppDTO.ts similarity index 81% rename from dto/AppDTO.ts rename to entities/app/AppDTO.ts index e446be3..6de8143 100644 --- a/dto/AppDTO.ts +++ b/entities/app/AppDTO.ts @@ -1,19 +1,19 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { explainArrayOf, isArrayOf } from "../types/Array"; -import { explain, explainNot, explainOk, explainOr, explainProperty } from "../types/explain"; -import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../types/OtherKeys"; -import { explainRegularObject, isRegularObject } from "../types/RegularObject"; -import { explainString, explainStringOrUndefined, isString, isStringOrUndefined } from "../types/String"; -import { isUndefined } from "../types/undefined"; -import { ExtendableDTO } from "./types/ExtendableDTO"; -import { explainComponentDTO, ComponentDTO, isComponentDTO } from "./ComponentDTO"; -import { explainRouteDTO, RouteDTO, isRouteDTO } from "./RouteDTO"; -import { explainViewDTO, ViewDTO, isViewDTO } from "./ViewDTO"; -import { DTOWithName } from "./types/DTOWithName"; -import { DTOWithOptionalExtend } from "./types/DTOWithOptionalExtend"; -import { DTOWithOptionalLanguage } from "./types/DTOWithOptionalLanguage"; -import { DTOWithOptionalPublicUrl } from "./types/DTOWithOptionalPublicUrl"; +import { explainArrayOf, isArrayOf } from "../../types/Array"; +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; +import { explainString, explainStringOrUndefined, isString, isStringOrUndefined } from "../../types/String"; +import { isUndefined } from "../../types/undefined"; +import { ExtendableDTO } from "../types/ExtendableDTO"; +import { explainComponentDTO, ComponentDTO, isComponentDTO } from "../component/ComponentDTO"; +import { explainRouteDTO, RouteDTO, isRouteDTO } from "../route/RouteDTO"; +import { explainViewDTO, ViewDTO, isViewDTO } from "../view/ViewDTO"; +import { DTOWithName } from "../types/DTOWithName"; +import { DTOWithOptionalExtend } from "../types/DTOWithOptionalExtend"; +import { DTOWithOptionalLanguage } from "../types/DTOWithOptionalLanguage"; +import { DTOWithOptionalPublicUrl } from "../types/DTOWithOptionalPublicUrl"; export interface AppDTO extends diff --git a/entities/AppEntity.ts b/entities/app/AppEntity.ts similarity index 85% rename from entities/AppEntity.ts rename to entities/app/AppEntity.ts index 8883387..38874c3 100644 --- a/entities/AppEntity.ts +++ b/entities/app/AppEntity.ts @@ -1,18 +1,18 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { forEach } from "../functions/forEach"; -import { ReadonlyJsonObject } from "../Json"; -import { isArray } from "../types/Array"; -import { ComponentDTO } from "../dto/ComponentDTO"; -import { createAppDTO, AppDTO } from "../dto/AppDTO"; -import { RouteDTO } from "../dto/RouteDTO"; -import { ViewDTO } from "../dto/ViewDTO"; -import { App } from "./types/App"; -import { ComponentEntity, isComponentEntity } from "./ComponentEntity"; -import { Extendable } from "./types/Extendable"; -import { JsonSerializable } from "./types/JsonSerializable"; -import { isRouteEntity, RouteEntity } from "./RouteEntity"; -import { isViewEntity, ViewEntity } from "./ViewEntity"; +import { forEach } from "../../functions/forEach"; +import { ReadonlyJsonObject } from "../../Json"; +import { isArray } from "../../types/Array"; +import { ComponentDTO } from "../component/ComponentDTO"; +import { createAppDTO, AppDTO } from "./AppDTO"; +import { RouteDTO } from "../route/RouteDTO"; +import { ViewDTO } from "../view/ViewDTO"; +import { App } from "./App"; +import { ComponentEntity, isComponentEntity } from "../component/ComponentEntity"; +import { Extendable } from "../types/Extendable"; +import { JsonSerializable } from "../types/JsonSerializable"; +import { isRouteEntity, RouteEntity } from "../route/RouteEntity"; +import { isViewEntity, ViewEntity } from "../view/ViewEntity"; export class AppEntity implements diff --git a/entities/types/Background.ts b/entities/background/Background.ts similarity index 71% rename from entities/types/Background.ts rename to entities/background/Background.ts index bd7ddc4..63521e7 100644 --- a/entities/types/Background.ts +++ b/entities/background/Background.ts @@ -3,21 +3,21 @@ import { ReadonlyJsonObject } from "../../Json"; import { isFunction } from "../../types/Function"; import { isObject } from "../../types/Object"; -import { BackgroundDTO } from "../../dto/BackgroundDTO"; -import { BackgroundImageDTO } from "../../dto/BackgroundImageDTO"; -import { BackgroundRepeatDTO } from "../../dto/BackgroundRepeatDTO"; -import { ColorDTO } from "../../dto/ColorDTO"; -import { BackgroundAttachment } from "../../dto/types/BackgroundAttachment"; -import { BackgroundBlendMode } from "../../dto/types/BackgroundBlendMode"; -import { BackgroundClip } from "../../dto/types/BackgroundClip"; -import { BackgroundOrigin } from "../../dto/types/BackgroundOrigin"; -import { BackgroundPosition } from "../../dto/types/BackgroundPosition"; -import { BackgroundPositionOptions } from "../../dto/types/BackgroundPositionOptions"; -import { BackgroundSizeOptions } from "../../dto/types/BackgroundSizeOptions"; -import { BackgroundImage } from "./BackgroundImage"; -import { BackgroundRepeat } from "./BackgroundRepeat"; -import { Color } from "./Color"; -import { Entity } from "./Entity"; +import { BackgroundDTO } from "./BackgroundDTO"; +import { BackgroundImageDTO } from "../backgroundImage/BackgroundImageDTO"; +import { BackgroundRepeatDTO } from "../backgroundRepeat/BackgroundRepeatDTO"; +import { ColorDTO } from "../color/ColorDTO"; +import { BackgroundAttachment } from "../types/BackgroundAttachment"; +import { BackgroundBlendMode } from "../types/BackgroundBlendMode"; +import { BackgroundClip } from "../types/BackgroundClip"; +import { BackgroundOrigin } from "../types/BackgroundOrigin"; +import { BackgroundPosition } from "../types/BackgroundPosition"; +import { BackgroundPositionOptions } from "../types/BackgroundPositionOptions"; +import { BackgroundSizeOptions } from "../types/BackgroundSizeOptions"; +import { BackgroundImage } from "../backgroundImage/BackgroundImage"; +import { BackgroundRepeat } from "../backgroundRepeat/BackgroundRepeat"; +import { Color } from "../color/Color"; +import { Entity } from "../types/Entity"; /** * Presents a background image value diff --git a/dto/BackgroundDTO.ts b/entities/background/BackgroundDTO.ts similarity index 85% rename from dto/BackgroundDTO.ts rename to entities/background/BackgroundDTO.ts index c8f44f5..e86d8ed 100644 --- a/dto/BackgroundDTO.ts +++ b/entities/background/BackgroundDTO.ts @@ -1,19 +1,19 @@ // Copyright (c) 2023. Heusala Group Oy . All rights reserved. -import { explain, explainNot, explainOk, explainOr, explainProperty } from "../types/explain"; -import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../types/OtherKeys"; -import { explainRegularObject, isRegularObject } from "../types/RegularObject"; -import { isUndefined } from "../types/undefined"; -import { BackgroundImageDTO, explainBackgroundImageDTOOrUndefined, isBackgroundImageDTOOrUndefined } from "./BackgroundImageDTO"; -import { ColorDTO, explainColorDTOOrUndefined, isColorDTOOrUndefined } from "./ColorDTO"; -import { BackgroundAttachment, explainBackgroundAttachmentOrUndefined, isBackgroundAttachmentOrUndefined } from "./types/BackgroundAttachment"; -import { BackgroundBlendMode, explainBackgroundBlendModeOrUndefined, isBackgroundBlendModeOrUndefined } from "./types/BackgroundBlendMode"; -import { BackgroundClip, explainBackgroundClipOrUndefined, isBackgroundClipOrUndefined } from "./types/BackgroundClip"; -import { BackgroundOrigin, explainBackgroundOriginOrUndefined, isBackgroundOriginOrUndefined } from "./types/BackgroundOrigin"; -import { BackgroundPositionOptions, explainBackgroundPositionOptionsOrUndefined, isBackgroundPositionOptionsOrUndefined } from "./types/BackgroundPositionOptions"; -import { BackgroundRepeatDTO, explainBackgroundRepeatDTOOrUndefined, isBackgroundRepeatDTOOrUndefined } from "./BackgroundRepeatDTO"; -import { BackgroundSizeOptions, explainBackgroundSizeOptionsOrUndefined, isBackgroundSizeOptionsOrUndefined } from "./types/BackgroundSizeOptions"; -import { DTO } from "./types/DTO"; +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; +import { isUndefined } from "../../types/undefined"; +import { BackgroundImageDTO, explainBackgroundImageDTOOrUndefined, isBackgroundImageDTOOrUndefined } from "../backgroundImage/BackgroundImageDTO"; +import { ColorDTO, explainColorDTOOrUndefined, isColorDTOOrUndefined } from "../color/ColorDTO"; +import { BackgroundAttachment, explainBackgroundAttachmentOrUndefined, isBackgroundAttachmentOrUndefined } from "../types/BackgroundAttachment"; +import { BackgroundBlendMode, explainBackgroundBlendModeOrUndefined, isBackgroundBlendModeOrUndefined } from "../types/BackgroundBlendMode"; +import { BackgroundClip, explainBackgroundClipOrUndefined, isBackgroundClipOrUndefined } from "../types/BackgroundClip"; +import { BackgroundOrigin, explainBackgroundOriginOrUndefined, isBackgroundOriginOrUndefined } from "../types/BackgroundOrigin"; +import { BackgroundPositionOptions, explainBackgroundPositionOptionsOrUndefined, isBackgroundPositionOptionsOrUndefined } from "../types/BackgroundPositionOptions"; +import { BackgroundRepeatDTO, explainBackgroundRepeatDTOOrUndefined, isBackgroundRepeatDTOOrUndefined } from "../backgroundRepeat/BackgroundRepeatDTO"; +import { BackgroundSizeOptions, explainBackgroundSizeOptionsOrUndefined, isBackgroundSizeOptionsOrUndefined } from "../types/BackgroundSizeOptions"; +import { DTO } from "../types/DTO"; export interface BackgroundDTO extends DTO { readonly attachment ?: BackgroundAttachment; diff --git a/entities/BackgroundEntity.ts b/entities/background/BackgroundEntity.ts similarity index 78% rename from entities/BackgroundEntity.ts rename to entities/background/BackgroundEntity.ts index db49cae..600a3a5 100644 --- a/entities/BackgroundEntity.ts +++ b/entities/background/BackgroundEntity.ts @@ -1,26 +1,49 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ReadonlyJsonObject } from "../Json"; -import { isString } from "../types/String"; -import { BackgroundDTO, createBackgroundDTO } from "../dto/BackgroundDTO"; -import { BackgroundImageDTO } from "../dto/BackgroundImageDTO"; -import { BackgroundRepeatDTO } from "../dto/BackgroundRepeatDTO"; -import { ColorDTO } from "../dto/ColorDTO"; -import { BackgroundAttachment } from "../dto/types/BackgroundAttachment"; -import { BackgroundBlendMode } from "../dto/types/BackgroundBlendMode"; -import { BackgroundClip } from "../dto/types/BackgroundClip"; -import { BackgroundOrigin } from "../dto/types/BackgroundOrigin"; -import { BackgroundPosition, isBackgroundPosition } from "../dto/types/BackgroundPosition"; -import { BackgroundPositionOptions, getCssStylesForBackgroundPosition } from "../dto/types/BackgroundPositionOptions"; -import { BackgroundRepeatType, isBackgroundRepeatType } from "../dto/types/BackgroundRepeatType"; -import { BackgroundSizeOptions, getCssStylesForBackgroundSizeOptions } from "../dto/types/BackgroundSizeOptions"; -import { BackgroundImageEntity, isBackgroundImageEntity } from "./BackgroundImageEntity"; -import { BackgroundRepeatEntity, isBackgroundRepeatEntity } from "./BackgroundRepeatEntity"; -import { ColorEntity, isColorEntity } from "./ColorEntity"; -import { Background } from "./types/Background"; -import { BackgroundImage, isBackgroundImage } from "./types/BackgroundImage"; -import { BackgroundRepeat, isBackgroundRepeat } from "./types/BackgroundRepeat"; -import { Color, isColor } from "./types/Color"; +import { BackgroundSize } from "../backgroundSize/BackgroundSize"; +import { ReadonlyJsonObject } from "../../Json"; +import { isString } from "../../types/String"; +import { BackgroundDTO, createBackgroundDTO } from "./BackgroundDTO"; +import { BackgroundImageDTO } from "../backgroundImage/BackgroundImageDTO"; +import { BackgroundRepeatDTO } from "../backgroundRepeat/BackgroundRepeatDTO"; +import { ColorDTO } from "../color/ColorDTO"; +import { BackgroundAttachment } from "../types/BackgroundAttachment"; +import { BackgroundBlendMode } from "../types/BackgroundBlendMode"; +import { BackgroundClip } from "../types/BackgroundClip"; +import { BackgroundOrigin } from "../types/BackgroundOrigin"; +import { BackgroundPosition, isBackgroundPosition } from "../types/BackgroundPosition"; +import { BackgroundPositionOptions, getCssStylesForBackgroundPosition } from "../types/BackgroundPositionOptions"; +import { BackgroundRepeatType, isBackgroundRepeatType } from "../types/BackgroundRepeatType"; +import { BackgroundSizeOptions, getCssStylesForBackgroundSizeOptions } from "../types/BackgroundSizeOptions"; +import { BackgroundImageEntity, isBackgroundImageEntity } from "../backgroundImage/BackgroundImageEntity"; +import { BackgroundRepeatEntity, isBackgroundRepeatEntity } from "../backgroundRepeat/BackgroundRepeatEntity"; +import { ColorEntity, isColorEntity } from "../color/ColorEntity"; +import { SizeBoxEntity } from "../sizeBox/SizeBoxEntity"; +import { SizeDimensionsEntity } from "../sizeDimensions/SizeDimensionsEntity"; +import { SizeEntity } from "../size/SizeEntity"; +import { Background } from "./Background"; +import { BackgroundImage, isBackgroundImage } from "../backgroundImage/BackgroundImage"; +import { BackgroundRepeat, isBackgroundRepeat } from "../backgroundRepeat/BackgroundRepeat"; +import { Color, isColor } from "../color/Color"; +import { EntityFactoryImpl } from "../types/EntityFactoryImpl"; +import { VariableType } from "../types/EntityProperty"; +import { EntityPropertyImpl } from "../types/EntityPropertyImpl"; + +export const BackgroundEntityFactory = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("attachment").setTypes(BackgroundAttachment, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("blendMode").setTypes(BackgroundBlendMode, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("clip").setTypes(BackgroundClip, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("color").setTypes(ColorEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("image").setTypes(BackgroundImageEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("origin").setTypes(BackgroundOrigin, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("position").setTypes(SizeBoxEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("repeat").setTypes(BackgroundRepeatEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("size").setTypes(BackgroundSize, SizeEntity, SizeDimensionsEntity, VariableType.UNDEFINED) ) +); + +export const BaseBackgroundEntity = BackgroundEntityFactory.createEntityType(); + /** * Background entity. diff --git a/entities/types/BackgroundImage.ts b/entities/backgroundImage/BackgroundImage.ts similarity index 92% rename from entities/types/BackgroundImage.ts rename to entities/backgroundImage/BackgroundImage.ts index 7fe913f..249f1b4 100644 --- a/entities/types/BackgroundImage.ts +++ b/entities/backgroundImage/BackgroundImage.ts @@ -3,8 +3,8 @@ import { ReadonlyJsonObject } from "../../Json"; import { isFunction } from "../../types/Function"; import { isObject } from "../../types/Object"; -import { BackgroundImageDTO } from "../../dto/BackgroundImageDTO"; -import { Entity } from "./Entity"; +import { BackgroundImageDTO } from "./BackgroundImageDTO"; +import { Entity } from "../types/Entity"; /** * Presents a background image value diff --git a/dto/BackgroundImageDTO.ts b/entities/backgroundImage/BackgroundImageDTO.ts similarity index 84% rename from dto/BackgroundImageDTO.ts rename to entities/backgroundImage/BackgroundImageDTO.ts index 2f4d051..428a056 100644 --- a/dto/BackgroundImageDTO.ts +++ b/entities/backgroundImage/BackgroundImageDTO.ts @@ -1,11 +1,11 @@ // Copyright (c) 2023. Heusala Group Oy . All rights reserved. -import { explain, explainNot, explainOk, explainOr, explainProperty } from "../types/explain"; -import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../types/OtherKeys"; -import { explainRegularObject, isRegularObject } from "../types/RegularObject"; -import { explainString, isString } from "../types/String"; -import { isUndefined } from "../types/undefined"; -import { DTO } from "./types/DTO"; +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; +import { explainString, isString } from "../../types/String"; +import { isUndefined } from "../../types/undefined"; +import { DTO } from "../types/DTO"; export interface BackgroundImageDTO extends DTO { readonly url: string; diff --git a/entities/backgroundImage/BackgroundImageEntity.ts b/entities/backgroundImage/BackgroundImageEntity.ts new file mode 100644 index 0000000..d57940c --- /dev/null +++ b/entities/backgroundImage/BackgroundImageEntity.ts @@ -0,0 +1,87 @@ +// Copyright (c) 2023. Sendanor . All rights reserved. + +import { + BackgroundImageDTO, + createBackgroundImageDTO, + isBackgroundImageDTO, +} from "./BackgroundImageDTO"; +import { isString } from "../../types/String"; +import { + BackgroundImage, + isBackgroundImage, +} from "./BackgroundImage"; +import { EntityFactoryImpl } from "../types/EntityFactoryImpl"; +import { VariableType } from "../types/EntityProperty"; +import { EntityPropertyImpl } from "../types/EntityPropertyImpl"; + +export const BackgroundImageEntityFactory = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("url").setTypes(VariableType.STRING) ) +); + +export const BaseBackgroundImageEntity = BackgroundImageEntityFactory.createEntityType(); + +/** + * Background image entity. + */ +export class BackgroundImageEntity + extends BaseBackgroundImageEntity + implements BackgroundImage +{ + + /** + * Creates a background image entity. + * + * @param url + */ + public static create ( + url ?: string | undefined, + ) : BackgroundImageEntity { + return new BackgroundImageEntity( url ); + } + + /** + * Creates a background image entity from DTO. + * + * @param value + */ + public static createFromDTO ( + value : BackgroundImageDTO, + ) : BackgroundImageEntity { + return new BackgroundImageEntity( value ); + } + + public static url ( + url : string, + ) : BackgroundImageEntity { + return new BackgroundImageEntity( url ); + } + + public constructor ( + arg ?: string | BackgroundImage | BackgroundImageEntity | BackgroundImageDTO | undefined, + ) { + if (arg === undefined) { + super(); + } else if (isString(arg)) { + super(createBackgroundImageDTO(arg)); + } else if (isBackgroundImageDTO(arg)) { + super(arg); + } else if (isBackgroundImageEntity(arg) || isBackgroundImage(arg)) { + super(arg.getDTO()); + } else { + throw new TypeError(`new BackgroundImageEntity(): Unsupported runtime type: ${arg}`); + } + } + + /** + * @inheritDoc + */ + public getCssStyles (): string { + return `url(${this.getUrl()})`; + } + +} + +export function isBackgroundImageEntity (value: unknown): value is BackgroundImageEntity { + return value instanceof BackgroundImageEntity; +} diff --git a/entities/backgroundPosition/BackgroundPositionDTO.ts b/entities/backgroundPosition/BackgroundPositionDTO.ts new file mode 100644 index 0000000..95e5a8b --- /dev/null +++ b/entities/backgroundPosition/BackgroundPositionDTO.ts @@ -0,0 +1,14 @@ +// Copyright (c) 2023. Heusala Group Oy . All rights reserved. + +import { + SizeDTO, +} from "../size/SizeDTO"; +import { BackgroundPosition } from "../types/BackgroundPosition"; +import { DTO } from "../types/DTO"; + +export interface BackgroundPositionDTO extends DTO { + readonly direction ?: BackgroundPosition; + readonly size ?: SizeDTO; + readonly secondDirection ?: BackgroundPosition; + readonly secondSize ?: SizeDTO; +} diff --git a/entities/backgroundPosition/BackgroundPositionEntity.ts b/entities/backgroundPosition/BackgroundPositionEntity.ts new file mode 100644 index 0000000..e69de29 diff --git a/entities/types/BackgroundRepeat.ts b/entities/backgroundRepeat/BackgroundRepeat.ts similarity index 89% rename from entities/types/BackgroundRepeat.ts rename to entities/backgroundRepeat/BackgroundRepeat.ts index 969c254..68cd029 100644 --- a/entities/types/BackgroundRepeat.ts +++ b/entities/backgroundRepeat/BackgroundRepeat.ts @@ -3,9 +3,9 @@ import { ReadonlyJsonObject } from "../../Json"; import { isFunction } from "../../types/Function"; import { isObject } from "../../types/Object"; -import { BackgroundRepeatDTO } from "../../dto/BackgroundRepeatDTO"; -import { BackgroundRepeatType } from "../../dto/types/BackgroundRepeatType"; -import { Entity } from "./Entity"; +import { BackgroundRepeatDTO } from "./BackgroundRepeatDTO"; +import { BackgroundRepeatType } from "../types/BackgroundRepeatType"; +import { Entity } from "../types/Entity"; /** * Presents a color value diff --git a/dto/BackgroundRepeatDTO.ts b/entities/backgroundRepeat/BackgroundRepeatDTO.ts similarity index 86% rename from dto/BackgroundRepeatDTO.ts rename to entities/backgroundRepeat/BackgroundRepeatDTO.ts index d898337..4131101 100644 --- a/dto/BackgroundRepeatDTO.ts +++ b/entities/backgroundRepeat/BackgroundRepeatDTO.ts @@ -1,11 +1,11 @@ // Copyright (c) 2023. Heusala Group Oy . All rights reserved. -import { explain, explainNot, explainOk, explainOr, explainProperty } from "../types/explain"; -import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../types/OtherKeys"; -import { explainRegularObject, isRegularObject } from "../types/RegularObject"; -import { isUndefined } from "../types/undefined"; -import { BackgroundRepeatType, explainBackgroundRepeatType, isBackgroundRepeatType } from "./types/BackgroundRepeatType"; -import { DTO } from "./types/DTO"; +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; +import { isUndefined } from "../../types/undefined"; +import { BackgroundRepeatType, explainBackgroundRepeatType, isBackgroundRepeatType } from "../types/BackgroundRepeatType"; +import { DTO } from "../types/DTO"; export interface BackgroundRepeatDTO extends DTO { readonly x: BackgroundRepeatType; diff --git a/entities/BackgroundRepeatEntity.ts b/entities/backgroundRepeat/BackgroundRepeatEntity.ts similarity index 63% rename from entities/BackgroundRepeatEntity.ts rename to entities/backgroundRepeat/BackgroundRepeatEntity.ts index 636198c..9670512 100644 --- a/entities/BackgroundRepeatEntity.ts +++ b/entities/backgroundRepeat/BackgroundRepeatEntity.ts @@ -1,14 +1,31 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ReadonlyJsonObject } from "../Json"; -import { BackgroundRepeatDTO, createBackgroundRepeatDTO } from "../dto/BackgroundRepeatDTO"; -import { BackgroundRepeatType } from "../dto/types/BackgroundRepeatType"; -import { BackgroundRepeat } from "./types/BackgroundRepeat"; +import { + BackgroundRepeatDTO, + createBackgroundRepeatDTO, + isBackgroundRepeatDTO, +} from "./BackgroundRepeatDTO"; +import { + BackgroundRepeatType, + isBackgroundRepeatType, +} from "../types/BackgroundRepeatType"; +import { BackgroundRepeat } from "./BackgroundRepeat"; +import { EntityFactoryImpl } from "../types/EntityFactoryImpl"; +import { EntityPropertyImpl } from "../types/EntityPropertyImpl"; + +export const BackgroundRepeatEntityFactory = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("x").setTypes(BackgroundRepeatType) ) + .add( EntityPropertyImpl.create("y").setTypes(BackgroundRepeatType) ) +); + +export const BaseBackgroundRepeatEntity = BackgroundRepeatEntityFactory.createEntityType(); /** * Background repeat entity. */ export class BackgroundRepeatEntity + extends BaseBackgroundRepeatEntity implements BackgroundRepeat { @@ -74,39 +91,19 @@ export class BackgroundRepeatEntity return this.create(BackgroundRepeatType.NO_REPEAT, BackgroundRepeatType.NO_REPEAT); } - private _x : BackgroundRepeatType; - private _y : BackgroundRepeatType; - - protected constructor ( - x : BackgroundRepeatType, - y : BackgroundRepeatType, + public constructor ( + x ?: BackgroundRepeatType | BackgroundRepeatDTO, + y ?: BackgroundRepeatType, ) { - this._x = x; - this._y = y; - } - - /** - * Returns the DTO object. - */ - public getDTO () : BackgroundRepeatDTO { - return createBackgroundRepeatDTO( - this._x, - this._y, - ); - } - - /** - * @inheritDoc - */ - public valueOf() : ReadonlyJsonObject { - return this.toJSON(); - } - - /** - * @inheritDoc - */ - public toJSON () : ReadonlyJsonObject { - return this.getDTO() as unknown as ReadonlyJsonObject; + if (x === undefined) { + super(); + } else if ( isBackgroundRepeatType(x) && isBackgroundRepeatType(y) ) { + super( createBackgroundRepeatDTO(x, y) ); + } else if (isBackgroundRepeatDTO(x) ) { + super( x ); + } else { + throw new TypeError(`new BackgroundRepeatEntity(): Unsupported arguments: ${x}, ${y}`); + } } /** @@ -114,59 +111,32 @@ export class BackgroundRepeatEntity */ public getCssStyles (): string { - if (this._x === BackgroundRepeatType.REPEAT && this._y === BackgroundRepeatType.NO_REPEAT) { + const x = this.getX(); + const y = this.getY(); + + if (x === BackgroundRepeatType.REPEAT && y === BackgroundRepeatType.NO_REPEAT) { return "repeat-x"; } - if (this._x === BackgroundRepeatType.REPEAT && this._y === BackgroundRepeatType.REPEAT) { + if (x === BackgroundRepeatType.REPEAT && y === BackgroundRepeatType.REPEAT) { return "repeat"; } - if (this._x === BackgroundRepeatType.NO_REPEAT && this._y === BackgroundRepeatType.REPEAT) { + if (x === BackgroundRepeatType.NO_REPEAT && y === BackgroundRepeatType.REPEAT) { return "repeat-y"; } - if (this._x === BackgroundRepeatType.NO_REPEAT && this._y === BackgroundRepeatType.NO_REPEAT) { + if (x === BackgroundRepeatType.NO_REPEAT && y === BackgroundRepeatType.NO_REPEAT) { return "no-repeat"; } - if (this._x === BackgroundRepeatType.SPACE && this._y === BackgroundRepeatType.SPACE) { + if (x === BackgroundRepeatType.SPACE && y === BackgroundRepeatType.SPACE) { return "space"; } - if (this._x === BackgroundRepeatType.ROUND && this._y === BackgroundRepeatType.ROUND) { + if (x === BackgroundRepeatType.ROUND && y === BackgroundRepeatType.ROUND) { return "round"; } - return `${this._x} ${this._y}`; - } - - /** - * @inheritDoc - */ - public getX () : BackgroundRepeatType { - return this._x; - } - - /** - * @inheritDoc - */ - public getY () : BackgroundRepeatType { - return this._y; - } - - /** - * @inheritDoc - */ - public x (value : BackgroundRepeatType) : this { - this._x = value; - return this; - } - - /** - * @inheritDoc - */ - public y (value : BackgroundRepeatType) : this { - this._y = value; - return this; + return `${x} ${y}`; } /** diff --git a/dto/types/BackgroundSize.ts b/entities/backgroundSize/BackgroundSize.ts similarity index 100% rename from dto/types/BackgroundSize.ts rename to entities/backgroundSize/BackgroundSize.ts diff --git a/entities/types/Border.ts b/entities/border/Border.ts similarity index 79% rename from entities/types/Border.ts rename to entities/border/Border.ts index ea6bdf7..d504cb0 100644 --- a/entities/types/Border.ts +++ b/entities/border/Border.ts @@ -3,14 +3,14 @@ import { ReadonlyJsonObject } from "../../Json"; import { isFunction } from "../../types/Function"; import { isObject } from "../../types/Object"; -import { BorderDTO } from "../../dto/BorderDTO"; -import { ColorDTO } from "../../dto/ColorDTO"; -import { SizeDTO } from "../../dto/SizeDTO"; -import { BorderStyle } from "../../dto/types/BorderStyle"; -import { ColorEntity } from "../ColorEntity"; -import { Color } from "./Color"; -import { Entity } from "./Entity"; -import { Size } from "./Size"; +import { BorderDTO } from "./BorderDTO"; +import { ColorDTO } from "../color/ColorDTO"; +import { SizeDTO } from "../size/SizeDTO"; +import { BorderStyle } from "../types/BorderStyle"; +import { ColorEntity } from "../color/ColorEntity"; +import { Color } from "../color/Color"; +import { Entity } from "../types/Entity"; +import { Size } from "../size/Size"; /** * Presents a border value @@ -32,7 +32,7 @@ export interface Border extends Entity { /** * Returns CSS styles. */ - getCssStyles () : string; + getCssStyles () : ReadonlyJsonObject; setStyle (value : BorderStyle) : this; getStyle () : BorderStyle | undefined; diff --git a/dto/BorderDTO.ts b/entities/border/BorderDTO.ts similarity index 92% rename from dto/BorderDTO.ts rename to entities/border/BorderDTO.ts index 46f0295..2748782 100644 --- a/dto/BorderDTO.ts +++ b/entities/border/BorderDTO.ts @@ -1,14 +1,14 @@ // Copyright (c) 2023. Heusala Group Oy . All rights reserved. -import { isArray } from "../types/Array"; -import { explain, explainNot, explainOk, explainOr, explainProperty } from "../types/explain"; -import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../types/OtherKeys"; -import { explainRegularObject, isRegularObject } from "../types/RegularObject"; -import { isUndefined } from "../types/undefined"; -import { ColorDTO, explainColorDTOOrUndefined, isColorDTOOrUndefined } from "./ColorDTO"; -import { explainSizeDTOOrUndefined, isSizeDTOOrUndefined, SizeDTO } from "./SizeDTO"; -import { BorderStyle, explainBorderStyleOrUndefined, isBorderStyleOrUndefined } from "./types/BorderStyle"; -import { DTO } from "./types/DTO"; +import { isArray } from "../../types/Array"; +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; +import { isUndefined } from "../../types/undefined"; +import { ColorDTO, explainColorDTOOrUndefined, isColorDTOOrUndefined } from "../color/ColorDTO"; +import { explainSizeDTOOrUndefined, isSizeDTOOrUndefined, SizeDTO } from "../size/SizeDTO"; +import { BorderStyle, explainBorderStyleOrUndefined, isBorderStyleOrUndefined } from "../types/BorderStyle"; +import { DTO } from "../types/DTO"; export interface BorderDTO extends DTO { diff --git a/entities/border/BorderEntity.ts b/entities/border/BorderEntity.ts new file mode 100644 index 0000000..ba55a8a --- /dev/null +++ b/entities/border/BorderEntity.ts @@ -0,0 +1,153 @@ +// Copyright (c) 2023. Sendanor . All rights reserved. + +import { + BorderDTO, + createBorderDTO, + isBorderDTO, +} from "./BorderDTO"; +import { + ColorDTO, +} from "../color/ColorDTO"; +import { + SizeDTO, +} from "../size/SizeDTO"; +import { + BorderStyle, + isBorderStyle, +} from "../types/BorderStyle"; +import { ReadonlyJsonObject } from "../../Json"; +import { + ColorEntity, +} from "../color/ColorEntity"; +import { + SizeEntity, +} from "../size/SizeEntity"; +import { + Border, + isBorder, +} from "./Border"; +import { EntityFactoryImpl } from "../types/EntityFactoryImpl"; +import { VariableType } from "../types/EntityProperty"; +import { EntityPropertyImpl } from "../types/EntityPropertyImpl"; + +export const BorderEntityFactory = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("style").setTypes(BorderStyle, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("width").setTypes(SizeEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("radius").setTypes(SizeEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("color").setTypes(ColorEntity, VariableType.UNDEFINED) ) +); + +export const BaseBorderEntity = BorderEntityFactory.createEntityType(); + +/** + * Border entity. + */ +export class BorderEntity + extends BaseBorderEntity + implements Border +{ + + /** + * Creates a border entity. + * + * @param style + * @param width + * @param color + * @param radius + */ + public static create ( + style ?: BorderStyle | undefined, + width ?: SizeDTO | undefined, + color ?: ColorDTO | undefined, + radius ?: SizeDTO | undefined, + ) : BorderEntity { + return new BorderEntity( + style, + width, + color, + radius, + ); + } + + public static createEmptyBorder () : BorderEntity { + return this.create( + undefined, + undefined, + undefined, + undefined, + ); + } + + /** + * Creates a border entity from a DTO. + * + * @param dto + */ + public static createFromDTO ( + dto : BorderDTO, + ) : BorderEntity { + return BorderEntity.create( + dto?.style, + dto?.width, + dto?.color, + dto?.radius, + ); + } + + public constructor ( + ) + + public constructor ( + style : BorderDTO | Border, + ) + + public constructor ( + style ?: BorderStyle, + width ?: SizeDTO, + color ?: ColorDTO, + radius ?: SizeDTO, + ); + + public constructor ( + style ?: BorderStyle | BorderDTO | Border | undefined, + width ?: SizeDTO | undefined, + color ?: ColorDTO | undefined, + radius ?: SizeDTO | undefined, + ) { + if ( style === undefined && width === undefined && color === undefined && radius === undefined ) { + super(); + } else if ( isBorderStyle(style) ) { + super( + createBorderDTO( + width, + style, + color, + radius, + ) + ); + } else if ( isBorderDTO(style) ) { + super(style); + } else if ( isBorder(style) ) { + super(style?.getDTO()); + } else { + throw new TypeError(`new BorderEntity(): Incorrect arguments: ${style}, ${width}, ${color}, ${radius}`); + } + } + + public getCssStyles (): ReadonlyJsonObject { + const width = this.getWidth(); + const color = this.getColor(); + const style = this.getStyle(); + return { + border: `${ width ? width.getCssStyles() : '0' } ${ + style + }${ color ? ' ' + color.getCssStyles() : '' }` + }; + } + +} + +export function isBorderEntity (value: unknown): value is BorderEntity { + return value instanceof BorderEntity; +} diff --git a/entities/borderBox/BorderBox.ts b/entities/borderBox/BorderBox.ts new file mode 100644 index 0000000..cc0c0d7 --- /dev/null +++ b/entities/borderBox/BorderBox.ts @@ -0,0 +1,145 @@ +// Copyright (c) 2023. Sendanor . All rights reserved. + +import { + BorderDTO, +} from "../border/BorderDTO"; +import { ReadonlyJsonObject } from "../../Json"; +import { isFunction } from "../../types/Function"; +import { isObject } from "../../types/Object"; +import { + BorderBoxDTO, +} from "./BorderBoxDTO"; +import { BorderEntity } from "../border/BorderEntity"; +import { Border } from "../border/Border"; +import { Entity } from "../types/Entity"; + +/** + * Presents a box of borders (e.g. top, right, bottom, left) + */ +export interface BorderBox + extends Entity { + + /** + * Returns the DTO object. + */ + getDTO () : BorderBoxDTO; + + /** + * @inheritDoc + */ + valueOf() : ReadonlyJsonObject; + + /** + * @inheritDoc + */ + toJSON () : ReadonlyJsonObject; + + /** + * Returns CSS styles. + */ + getCssStyles () : ReadonlyJsonObject; + + + /** + * Get a top border. + */ + getTop () : BorderEntity | undefined; + + /** + * Get top border as a DTO. + */ + getTopDTO () : BorderDTO | undefined; + + /** + * Set a top border. + * + * @param value + */ + setTop ( + value ?: BorderEntity | Border | BorderDTO | undefined, + ) : this; + + + /** + * Get a right border. + */ + getRight () : BorderEntity | undefined; + + /** + * Get right border as a DTO. + */ + getRightDTO () : BorderDTO | undefined; + + /** + * Set a right border. + * + * @param value + */ + setRight ( + value ?: BorderEntity | Border | BorderDTO | undefined, + ) : this; + + + /** + * Get a bottom border. + */ + getBottom () : BorderEntity | undefined; + + /** + * Get bottom border as a DTO. + */ + getBottomDTO () : BorderDTO | undefined; + + /** + * Set a bottom border. + * + * @param value + */ + setBottom ( + value ?: BorderEntity | Border | BorderDTO | undefined, + ) : this; + + + /** + * Get a left border. + */ + getLeft () : BorderEntity | undefined; + + /** + * Get left border as a DTO. + */ + getLeftDTO () : BorderDTO | undefined; + + /** + * Set a left border. + * + * @param value + */ + setLeft ( + value ?: BorderEntity | Border | BorderDTO | undefined, + ) : this; + +} + +export function isBorderBox (value : unknown) : value is BorderBox { + return ( + isObject(value) + && isFunction(value?.getDTO) + && isFunction(value?.valueOf) + && isFunction(value?.toJSON) + && isFunction(value?.getCssStyles) + && isFunction(value?.getTop) + && isFunction(value?.getTopDTO) + && isFunction(value?.setTop) + && isFunction(value?.getRight) + && isFunction(value?.getRightDTO) + && isFunction(value?.setRight) + && isFunction(value?.getBottom) + && isFunction(value?.getBottomDTO) + && isFunction(value?.setBottom) + && isFunction(value?.getLeft) + && isFunction(value?.getLeftDTO) + && isFunction(value?.setLeft) + ); +} + diff --git a/entities/borderBox/BorderBoxDTO.ts b/entities/borderBox/BorderBoxDTO.ts new file mode 100644 index 0000000..01d0b42 --- /dev/null +++ b/entities/borderBox/BorderBoxDTO.ts @@ -0,0 +1,84 @@ +// Copyright (c) 2023. Heusala Group Oy . All rights reserved. + +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; +import { isUndefined } from "../../types/undefined"; +import { + explainBorderDTOOrUndefined, + isBorderDTOOrUndefined, + BorderDTO, +} from "../border/BorderDTO"; +import { DTO } from "../types/DTO"; + +export interface BorderBoxDTO extends DTO { + readonly top ?: BorderDTO; + readonly right ?: BorderDTO; + readonly bottom ?: BorderDTO; + readonly left ?: BorderDTO; +} + +export function createBorderBoxDTO ( + top : BorderDTO | undefined, + right : BorderDTO | undefined, + bottom : BorderDTO | undefined, + left : BorderDTO | undefined, +) : BorderBoxDTO { + return { + top, + right, + bottom, + left, + }; +} + +export function isBorderBoxDTO (value: unknown) : value is BorderBoxDTO { + return ( + isRegularObject(value) + && hasNoOtherKeysInDevelopment(value, [ + 'top', + 'right', + 'bottom', + 'left', + ]) + && isBorderDTOOrUndefined(value?.top) + && isBorderDTOOrUndefined(value?.right) + && isBorderDTOOrUndefined(value?.bottom) + && isBorderDTOOrUndefined(value?.left) + ); +} + +export function explainBorderBoxDTO (value: any) : string { + return explain( + [ + explainRegularObject(value), + explainNoOtherKeysInDevelopment(value, [ + 'top', + 'right', + 'bottom', + 'left', + ]) + , explainProperty("top", explainBorderDTOOrUndefined(value?.top)) + , explainProperty("right", explainBorderDTOOrUndefined(value?.right)) + , explainProperty("bottom", explainBorderDTOOrUndefined(value?.bottom)) + , explainProperty("left", explainBorderDTOOrUndefined(value?.left)) + ] + ); +} + +export function stringifyBorderBoxDTO (value : BorderBoxDTO) : string { + return `BorderBoxDTO(${value})`; +} + +export function parseBorderBoxDTO (value: unknown) : BorderBoxDTO | undefined { + if (isBorderBoxDTO(value)) return value; + return undefined; +} + +export function isBorderBoxDTOOrUndefined (value: unknown): value is BorderBoxDTO | undefined { + return isUndefined(value) || isBorderBoxDTO(value); +} + +export function explainBorderBoxDTOOrUndefined (value: unknown): string { + return isBorderBoxDTOOrUndefined(value) ? explainOk() : explainNot(explainOr(['BorderBoxDTO', 'undefined'])); +} diff --git a/entities/borderBox/BorderBoxEntity.ts b/entities/borderBox/BorderBoxEntity.ts new file mode 100644 index 0000000..a397933 --- /dev/null +++ b/entities/borderBox/BorderBoxEntity.ts @@ -0,0 +1,183 @@ +// Copyright (c) 2023. Sendanor . All rights reserved. + +import { + BorderBoxDTO, + createBorderBoxDTO, + isBorderBoxDTO, +} from "./BorderBoxDTO"; +import { + isBorderDTO, + BorderDTO, +} from "../border/BorderDTO"; +import { reduce } from "../../functions/reduce"; +import { ReadonlyJsonObject } from "../../Json"; +import { BorderEntity } from "../border/BorderEntity"; +import { + BorderBox, + isBorderBox, +} from "./BorderBox"; +import { EntityFactoryImpl } from "../types/EntityFactoryImpl"; +import { VariableType } from "../types/EntityProperty"; +import { EntityPropertyImpl } from "../types/EntityPropertyImpl"; + +export const BorderBoxEntityFactory = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("top").setTypes(BorderEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("right").setTypes(BorderEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("bottom").setTypes(BorderEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("left").setTypes(BorderEntity, VariableType.UNDEFINED) ) +); + +export const BaseBorderBoxEntity = BorderBoxEntityFactory.createEntityType(); + +/** + * BorderBox entity. + */ +export class BorderBoxEntity + extends BaseBorderBoxEntity + implements BorderBox +{ + + public static create () : BorderBoxEntity; + + /** + * Creates a size box entity. + * + * @param topAndBottom + * @param rightAndLeft + */ + public static create ( + topAndBottom : BorderDTO, + rightAndLeft : BorderDTO, + ) : BorderBoxEntity; + + /** + * Creates a size box entity. + * + * @param top + * @param right + * @param bottom + * @param left + */ + public static create ( + top : BorderDTO, + right : BorderDTO, + bottom : BorderDTO, + left : BorderDTO, + ) : BorderBoxEntity; + + /** + * Creates a size box entity. + * + * @param top + * @param right + * @param bottom + * @param left + */ + public static create ( + top ?: BorderDTO | BorderBoxDTO | BorderBoxEntity, + right ?: BorderDTO, + bottom ?: BorderDTO, + left ?: BorderDTO, + ) : BorderBoxEntity { + if ( top === undefined && right === undefined && bottom === undefined && left === undefined ) { + return new BorderBoxEntity(); + } else if ( isBorderBoxDTO(top) ) { + return new BorderBoxEntity(top); + } else if ( isBorderBoxEntity(top) ) { + return new BorderBoxEntity(top.getDTO()); + } else if ( isBorderBox(top) ) { + return new BorderBoxEntity(top.getDTO()); + } else if ( isBorderDTO(top) && isBorderDTO(right) && bottom === undefined && left === undefined ) { + return new BorderBoxEntity( createBorderBoxDTO(top, right, top, right) ); + } else if ( isBorderDTO(top) && isBorderDTO(right) && isBorderDTO(bottom) && isBorderDTO(left) ) { + return new BorderBoxEntity( createBorderBoxDTO(top, right, bottom, left) ); + } else { + throw new TypeError(`Invalid arguments for create: ${top}, ${right}, ${bottom}, ${left}`); + } + } + + /** + * Creates a size box entity from DTO. + * + * @param value + */ + public static createFromDTO ( + value : BorderBoxDTO, + ) : BorderBoxEntity { + return new BorderBoxEntity(value); + } + + public static merge ( + ...values: readonly (BorderBoxDTO | BorderBox | BorderBoxEntity)[] + ) : BorderBoxEntity { + return BorderBoxEntity.createFromDTO( + reduce( + values, + ( + prev: BorderBoxDTO, + item: BorderBoxDTO | BorderBox | BorderBoxEntity, + ) : BorderBoxDTO => { + const dto : BorderBoxDTO = this.toDTO(item); + return { + ...prev, + ...dto, + }; + }, + createBorderBoxDTO( + undefined, + undefined, + undefined, + undefined, + ), + ) + ); + } + + public static toDTO ( + value: BorderBoxDTO | BorderBox | BorderBoxEntity, + ) : BorderBoxDTO { + if (isBorderBoxEntity(value)) { + return value.getDTO(); + } else if (isBorderBox(value)) { + return value.getDTO(); + } else { + return value; + } + } + + protected constructor ( + value ?: BorderBoxDTO | BorderBox, + ) { + super( + isBorderBoxDTO(value) + ? value + : ( + isBorderBox(value) + ? value.getDTO() + : undefined + ) + ); + } + + /** + * @inheritDoc + */ + public getCssStyles (): ReadonlyJsonObject { + const top = this.getTop(); + const right = this.getRight(); + const bottom = this.getBottom(); + const left = this.getLeft(); + return { + ...( top !== undefined ? { 'border-top': top.getCssStyles() }: {}), + ...( right !== undefined ? { 'border-right': right.getCssStyles() }: {}), + ...( bottom !== undefined ? { 'border-bottom': bottom.getCssStyles() }: {}), + ...( left !== undefined ? { 'border-left': left.getCssStyles() }: {}), + }; + } + +} + +export function isBorderBoxEntity (value: unknown): value is BorderBoxEntity { + return value instanceof BorderBoxEntity; +} diff --git a/entities/types/Color.ts b/entities/color/Color.ts similarity index 92% rename from entities/types/Color.ts rename to entities/color/Color.ts index dfaa613..76bf190 100644 --- a/entities/types/Color.ts +++ b/entities/color/Color.ts @@ -3,8 +3,8 @@ import { ReadonlyJsonObject } from "../../Json"; import { isFunction } from "../../types/Function"; import { isObject } from "../../types/Object"; -import { ColorDTO } from "../../dto/ColorDTO"; -import { Entity } from "./Entity"; +import { ColorDTO } from "./ColorDTO"; +import { Entity } from "../types/Entity"; /** * Presents a color value diff --git a/entities/color/ColorDTO.ts b/entities/color/ColorDTO.ts new file mode 100644 index 0000000..fead14f --- /dev/null +++ b/entities/color/ColorDTO.ts @@ -0,0 +1,7 @@ +// Copyright (c) 2023. Heusala Group Oy . All rights reserved. + +import { DTO } from "../types/DTO"; + +export interface ColorDTO extends DTO { + readonly value: string; +} diff --git a/entities/ColorEntity.ts b/entities/color/ColorEntity.ts similarity index 54% rename from entities/ColorEntity.ts rename to entities/color/ColorEntity.ts index b2c2e24..a587e06 100644 --- a/entities/ColorEntity.ts +++ b/entities/color/ColorEntity.ts @@ -1,15 +1,45 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { reduce } from "../functions/reduce"; -import { ReadonlyJsonObject } from "../Json"; -import { isString } from "../types/String"; -import { ColorDTO, createColorDTO } from "../dto/ColorDTO"; -import { Color, isColor } from "./types/Color"; +import { + explainNot, + explainOk, + explainOr, +} from "../../types/explain"; +import { + ColorDTO, +} from "./ColorDTO"; +import { reduce } from "../../functions/reduce"; +import { isString } from "../../types/String"; +import { + Color, + isColor, +} from "./Color"; +import { EntityFactoryImpl } from "../types/EntityFactoryImpl"; +import { VariableType } from "../types/EntityProperty"; +import { EntityPropertyImpl } from "../types/EntityPropertyImpl"; + +export const ColorEntityFactory = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("value").setTypes(VariableType.STRING) ) +); + +export const isColorDTO = ColorEntityFactory.createIsDTO(); + +export const explainColorDTO = ColorEntityFactory.createExplainDTO(); + +export const isColorDTOOrUndefined = ColorEntityFactory.createIsDTOOr(VariableType.UNDEFINED); + +export function explainColorDTOOrUndefined (value: unknown): string { + return isColorDTOOrUndefined(value) ? explainOk() : explainNot(explainOr(['ColorDTO', 'undefined'])); +} + +export const BaseColorEntity = ColorEntityFactory.createEntityType(); /** * Color entity. */ export class ColorEntity + extends BaseColorEntity implements Color { @@ -19,7 +49,7 @@ export class ColorEntity * @param value */ public static create ( - value : string, + value ?: string, ) : ColorEntity { return new ColorEntity(value); } @@ -59,9 +89,7 @@ export class ColorEntity ...dto, }; }, - createColorDTO( - '', - ), + {value: ''}, ) ); } @@ -80,55 +108,29 @@ export class ColorEntity } } - private _value : string; - protected constructor ( - value : string, + value ?: string | ColorDTO | Color, ) { - this._value = value; - } - - /** - * Returns the DTO object. - */ - public getDTO () : ColorDTO { - return createColorDTO(this._value); - } - - /** - * @inheritDoc - */ - public valueOf() : ReadonlyJsonObject { - return this.toJSON(); - } - - /** - * @inheritDoc - */ - public toJSON () : ReadonlyJsonObject { - return this.getDTO() as unknown as ReadonlyJsonObject; - } - - /** - * @inheritDoc - */ - public setValue (value : string ) : this { - this._value = value; - return this; - } - - /** - * @inheritDoc - */ - public getValue () : string { - return this._value; + super( + isColorDTO(value) + ? value + : ( + isColor(value) + ? value.getDTO() + : ( + value + ? { value } + : undefined + ) + ) + ); } /** * @inheritDoc */ public getCssStyles (): string { - return `${this._value}`; + return `${this.getValue()}`; } } diff --git a/entities/types/Component.ts b/entities/component/Component.ts similarity index 94% rename from entities/types/Component.ts rename to entities/component/Component.ts index 0785b6b..6b1032d 100644 --- a/entities/types/Component.ts +++ b/entities/component/Component.ts @@ -4,12 +4,12 @@ import { ReadonlyJsonAny, ReadonlyJsonArray, ReadonlyJsonArrayOf, ReadonlyJsonOb import { isFunction } from "../../types/Function"; import { isObject } from "../../types/Object"; import { TestCallbackNonStandard } from "../../types/TestCallback"; -import { ComponentDTO } from "../../dto/ComponentDTO"; -import { StyleDTO } from "../../dto/StyleDTO"; -import { ComponentEntityContent } from "../ComponentEntity"; -import { StyleEntity } from "../StyleEntity"; -import { ExtendableEntity } from "./ExtendableEntity"; -import { Style } from "./Style"; +import { ComponentDTO } from "./ComponentDTO"; +import { StyleDTO } from "../style/StyleDTO"; +import { ComponentEntityContent } from "./ComponentEntity"; +import { StyleEntity } from "../style/StyleEntity"; +import { ExtendableEntity } from "../types/ExtendableEntity"; +import { Style } from "../style/Style"; /** * Interface for Component entities. diff --git a/dto/ComponentDTO.ts b/entities/component/ComponentDTO.ts similarity index 84% rename from dto/ComponentDTO.ts rename to entities/component/ComponentDTO.ts index 38fd5ad..a46afe5 100644 --- a/dto/ComponentDTO.ts +++ b/entities/component/ComponentDTO.ts @@ -1,46 +1,42 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { explainReadonlyJsonObjectOrUndefined, isReadonlyJsonObjectOrUndefined, ReadonlyJsonObject } from "../Json"; +import { explainReadonlyJsonObjectOrUndefined, isReadonlyJsonObjectOrUndefined, ReadonlyJsonObject } from "../../Json"; import { explainArrayOf, isArrayOf, -} from "../types/Array"; -import { explain, explainNot, explainOk, explainOr, explainProperty } from "../types/explain"; -import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../types/OtherKeys"; -import { explainRegularObject, isRegularObject } from "../types/RegularObject"; +} from "../../types/Array"; +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; import { explainString, explainStringOrUndefined, isString, isStringOrUndefined, prefixLines, -} from "../types/String"; -import { isUndefined } from "../types/undefined"; -import { ExtendableDTO } from "./types/ExtendableDTO"; -import { explainStyleDTOOrUndefined, StyleDTO, isStyleDTOOrUndefined } from "./StyleDTO"; -import { DTOWithContent } from "./types/DTOWithContent"; -import { DTOWithOptionalExtend } from "./types/DTOWithOptionalExtend"; -import { DTOWithName } from "./types/DTOWithName"; +} from "../../types/String"; +import { isUndefined } from "../../types/undefined"; +import { ExtendableDTO } from "../types/ExtendableDTO"; +import { explainStyleDTOOrUndefined, StyleDTO, isStyleDTOOrUndefined } from "../style/StyleDTO"; +import { DTOWithContent } from "../types/DTOWithContent"; +import { DTOWithOptionalExtend } from "../types/DTOWithOptionalExtend"; +import { DTOWithName } from "../types/DTOWithName"; -export type ComponentContent = string | ComponentDTO | readonly (string|ComponentDTO)[]; +export type ComponentContent = readonly (string|ComponentDTO)[]; export function isComponentContent ( value: unknown) : value is ComponentContent { - return ( - isStringOrComponentDTO(value) - || isArrayOf(value, isStringOrComponentDTO) - ); + return isArrayOf(value, isStringOrComponentDTO); } export function explainComponentContent (value: any) : string { - return isComponentContent(value) ? explainOk() : explainNot(explainOr([ - `string|ComponentDTO (\n${prefixLines(explainStringOrComponentDTO(value), ' ')}\n)`, + return isComponentContent(value) ? explainOk() : explainNot( `Array(\n${prefixLines(explainArrayOf( "string|ComponentDTO", explainStringOrComponentDTO, value, isStringOrComponentDTO ), ' ')}\n)` - ])); + ); } diff --git a/entities/ComponentEntity.ts b/entities/component/ComponentEntity.ts similarity index 92% rename from entities/ComponentEntity.ts rename to entities/component/ComponentEntity.ts index 6eebd17..f30f86c 100644 --- a/entities/ComponentEntity.ts +++ b/entities/component/ComponentEntity.ts @@ -1,18 +1,18 @@ // Copyright (c) 2023. Heusala Group Oy . All rights reserved. -import { has } from "../functions/has"; -import { map } from "../functions/map"; -import { isReadonlyJsonArray, isReadonlyJsonArrayOf, isReadonlyJsonObject, ReadonlyJsonAny, ReadonlyJsonArray, ReadonlyJsonArrayOf, ReadonlyJsonObject } from "../Json"; -import { isArray } from "../types/Array"; -import { isBoolean } from "../types/Boolean"; -import { isNumber } from "../types/Number"; -import { isString } from "../types/String"; -import { TestCallbackNonStandard } from "../types/TestCallback"; -import { createComponentDTO, ComponentContent, ComponentDTO } from "../dto/ComponentDTO"; -import { StyleDTO } from "../dto/StyleDTO"; -import { Component } from "./types/Component"; -import { isStyle, Style } from "./types/Style"; -import { isStyleEntity, StyleEntity } from "./StyleEntity"; +import { has } from "../../functions/has"; +import { map } from "../../functions/map"; +import { isReadonlyJsonArray, isReadonlyJsonArrayOf, isReadonlyJsonObject, ReadonlyJsonAny, ReadonlyJsonArray, ReadonlyJsonArrayOf, ReadonlyJsonObject } from "../../Json"; +import { isArray } from "../../types/Array"; +import { isBoolean } from "../../types/Boolean"; +import { isNumber } from "../../types/Number"; +import { isString } from "../../types/String"; +import { TestCallbackNonStandard } from "../../types/TestCallback"; +import { createComponentDTO, ComponentContent, ComponentDTO } from "./ComponentDTO"; +import { StyleDTO } from "../style/StyleDTO"; +import { Component } from "./Component"; +import { isStyle, Style } from "../style/Style"; +import { isStyleEntity, StyleEntity } from "../style/StyleEntity"; /** * Type for internal component content. diff --git a/entities/types/Font.ts b/entities/font/Font.ts similarity index 59% rename from entities/types/Font.ts rename to entities/font/Font.ts index 7f8ccd9..b083974 100644 --- a/entities/types/Font.ts +++ b/entities/font/Font.ts @@ -3,12 +3,13 @@ import { ReadonlyJsonObject } from "../../Json"; import { isFunction } from "../../types/Function"; import { isObject } from "../../types/Object"; -import { FontDTO } from "../../dto/FontDTO"; -import { SizeDTO } from "../../dto/SizeDTO"; -import { Entity } from "./Entity"; -import { FontStyle } from "./FontStyle"; -import { FontVariant } from "./FontVariant"; -import { FontWeight } from "./FontWeight"; +import { FontDTO } from "./FontDTO"; +import { SizeDTO } from "../size/SizeDTO"; +import { Entity } from "../types/Entity"; +import { FontStyle } from "./types/FontStyle"; +import { FontVariant } from "./types/FontVariant"; +import { FontWeight } from "./types/FontWeight"; +import { Size } from "../size/Size"; /** * Presents a font value. @@ -41,6 +42,11 @@ export interface Font */ getFontStyle () : FontStyle | undefined; + /** + * Get a font style. + */ + getStyle () : FontStyle | undefined; + /** * Set a font style. * @@ -48,11 +54,23 @@ export interface Font */ setFontStyle (value : FontStyle | undefined) : this; + /** + * Set a font style. + * + * @param value + */ + setStyle (value : FontStyle | undefined) : this; + /** * Get a font variant. */ getFontVariant () : FontVariant | undefined; + /** + * Get a font variant. + */ + getVariant () : FontVariant | undefined; + /** * Set a font variant. * @@ -60,11 +78,23 @@ export interface Font */ setFontVariant (value : FontVariant | undefined) : this; + /** + * Set a font variant. + * + * @param value + */ + setVariant (value : FontVariant | undefined) : this; + /** * Get a font weight. */ getFontWeight () : FontWeight | undefined; + /** + * Get a font weight. + */ + getWeight () : FontWeight | undefined; + /** * Set a font weight. * @@ -72,10 +102,39 @@ export interface Font */ setFontWeight (value : FontWeight | undefined) : this; + /** + * Set a font weight. + * + * @param value + */ + setWeight (value : FontWeight | undefined) : this; + + /** + * Get a font size. + */ + getFontSize () : Size | undefined; + + /** + * Get a font size. + */ + getSize () : Size | undefined; + + /** + * Get a font size. + */ + getFontSizeDTO () : SizeDTO | undefined; + /** * Get a font size. */ - getFontSize () : SizeDTO | undefined; + getSizeDTO () : SizeDTO | undefined; + + /** + * Set a font size. + * + * @param value + */ + setSize (value : SizeDTO | undefined) : this; /** * Set a font size. @@ -87,7 +146,12 @@ export interface Font /** * Get a font line-height. */ - getLineHeight () : SizeDTO | undefined; + getLineHeight () : Size | undefined; + + /** + * Get a font line-height. + */ + getLineHeightDTO () : SizeDTO | undefined; /** * Set a font line-height. @@ -99,6 +163,12 @@ export interface Font /** * Get a font family. */ + getFamily () : string | undefined; + + /** + * Get a font family. + * Alias for `./getFamily()`. + */ getFontFamily () : string | undefined; /** @@ -108,6 +178,14 @@ export interface Font */ setFontFamily (value : string | undefined) : this; + /** + * Set a font family. + * + * Alias for `./setFamily()`. + * @param value + */ + setFamily (value : string | undefined) : this; + } export function isFont (value : unknown) : value is Font { diff --git a/dto/FontDTO.ts b/entities/font/FontDTO.ts similarity index 88% rename from dto/FontDTO.ts rename to entities/font/FontDTO.ts index 586f85f..b048338 100644 --- a/dto/FontDTO.ts +++ b/entities/font/FontDTO.ts @@ -1,15 +1,15 @@ // Copyright (c) 2023. Heusala Group Oy . All rights reserved. -import { explain, explainNot, explainOk, explainOr, explainProperty } from "../types/explain"; -import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../types/OtherKeys"; -import { explainRegularObject, isRegularObject } from "../types/RegularObject"; -import { explainStringOrUndefined, isStringOrUndefined } from "../types/String"; -import { isUndefined } from "../types/undefined"; -import { explainFontStyleOrUndefined, FontStyle, isFontStyleOrUndefined } from "../entities/types/FontStyle"; -import { explainFontVariantOrUndefined, FontVariant, isFontVariantOrUndefined } from "../entities/types/FontVariant"; -import { explainFontWeightOrUndefined, FontWeight, isFontWeightOrUndefined } from "../entities/types/FontWeight"; -import { explainSizeDTOOrUndefined, isSizeDTOOrUndefined, SizeDTO } from "./SizeDTO"; -import { DTO } from "./types/DTO"; +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; +import { explainStringOrUndefined, isStringOrUndefined } from "../../types/String"; +import { isUndefined } from "../../types/undefined"; +import { explainFontStyleOrUndefined, FontStyle, isFontStyleOrUndefined } from "./types/FontStyle"; +import { explainFontVariantOrUndefined, FontVariant, isFontVariantOrUndefined } from "./types/FontVariant"; +import { explainFontWeightOrUndefined, FontWeight, isFontWeightOrUndefined } from "./types/FontWeight"; +import { explainSizeDTOOrUndefined, isSizeDTOOrUndefined, SizeDTO } from "../size/SizeDTO"; +import { DTO } from "../types/DTO"; export interface FontDTO extends DTO { readonly style ?: FontStyle; diff --git a/entities/font/FontEntity.ts b/entities/font/FontEntity.ts new file mode 100644 index 0000000..35cc40a --- /dev/null +++ b/entities/font/FontEntity.ts @@ -0,0 +1,152 @@ +// Copyright (c) 2023. Sendanor . All rights reserved. + +import { + createFontDTO, + FontDTO, + isFontDTO, +} from "./FontDTO"; +import { SizeDTO } from "../size/SizeDTO"; +import { ReadonlyJsonObject } from "../../Json"; +import { + SizeEntity, +} from "../size/SizeEntity"; +import { EntityFactoryImpl } from "../types/EntityFactoryImpl"; +import { VariableType } from "../types/EntityProperty"; +import { EntityPropertyImpl } from "../types/EntityPropertyImpl"; +import { + Font, +} from "./Font"; +import { + FontStyle, + isFontStyle, +} from "./types/FontStyle"; +import { FontVariant } from "./types/FontVariant"; +import { FontWeight } from "./types/FontWeight"; + +export const FontEntityFactory = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("style").setTypes( FontStyle, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("variant").setTypes( FontVariant, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("weight").setTypes( FontWeight, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("size").setTypes( SizeEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("lineHeight").setTypes( SizeEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("family").setTypes( VariableType.STRING, VariableType.UNDEFINED) ) +); + +export const BaseFontEntity = FontEntityFactory.createEntityType(); + + +/** + * Font entity. + */ +export class FontEntity + extends BaseFontEntity + implements Font +{ + + /** + * Creates a font entity. + * + * @param value + */ + public static create ( + value ?: string | undefined, + ) : FontEntity { + return new FontEntity( + undefined, + undefined, + undefined, + undefined, + undefined, + value, + ); + } + + /** + * Creates a font entity from DTO. + * + * @param value + */ + public static createFromDTO ( + value : FontDTO, + ) : FontEntity { + return new FontEntity( + value?.style, + value?.variant, + value?.weight, + value?.size, + value?.lineHeight, + value?.family, + ); + } + + public constructor (); + + public constructor ( + font: FontDTO | FontEntity | Font, + ); + + public constructor ( + style ?: FontStyle | undefined, + variant ?: FontVariant | undefined, + weight ?: FontWeight | undefined, + size ?: SizeDTO | undefined, + lineHeight ?: SizeDTO | undefined, + family ?: string | undefined, + ); + + public constructor ( + style ?: FontStyle | FontDTO | FontEntity | Font | undefined, + variant ?: FontVariant | undefined, + weight ?: FontWeight | undefined, + size ?: SizeDTO | undefined, + lineHeight ?: SizeDTO | undefined, + family ?: string | undefined, + ) { + if (style === undefined && variant === undefined && weight === undefined && size === undefined && lineHeight === undefined && family === undefined) { + super(); + } else if ( isFontStyle(style) ) { + super( createFontDTO( + style, + variant, + weight, + size, + lineHeight, + family, + ) ); + } else if (isFontDTO(style)) { + super( style ); + } else if (isFontEntity(style)) { + super( style.getDTO() ); + } else { + throw new TypeError( + `new FontEntity(): Invalid arguments: ${style}, ${variant }, ${ weight }, ${ size }, ${ lineHeight }, ${ family }` + ); + } + } + /** + * @inheritDoc + */ + public getCssStyles (): ReadonlyJsonObject { + const style = this.getFontStyle(); + const variant = this.getFontVariant(); + const weight = this.getFontWeight(); + const size = this.getFontSize(); + const lineHeight = this.getLineHeight(); + const family = this.getFontFamily(); + return { + ...(style ? { fontStyle: style } : {}), + ...(variant ? { fontVariant: variant } : {}), + ...(weight ? { fontWeight: weight } : {}), + ...(size ? { fontSize: size.getCssStyles() } : {}), + ...(lineHeight ? { lineHeight: lineHeight.getCssStyles() } : {}), + ...(family ? { fontFamily: family } : {}), + }; + } + + +} + +export function isFontEntity (value: unknown): value is FontEntity { + return value instanceof FontEntity; +} diff --git a/entities/types/FontStyle.ts b/entities/font/types/FontStyle.ts similarity index 89% rename from entities/types/FontStyle.ts rename to entities/font/types/FontStyle.ts index 923ef00..241061a 100644 --- a/entities/types/FontStyle.ts +++ b/entities/font/types/FontStyle.ts @@ -1,8 +1,8 @@ // Copyright (c) 2023. Heusala Group Oy . All rights reserved. -import { explainEnum, isEnum, parseEnum, stringifyEnum } from "../../types/Enum"; -import { explainNot, explainOk, explainOr } from "../../types/explain"; -import { isUndefined } from "../../types/undefined"; +import { explainEnum, isEnum, parseEnum, stringifyEnum } from "../../../types/Enum"; +import { explainNot, explainOk, explainOr } from "../../../types/explain"; +import { isUndefined } from "../../../types/undefined"; export enum FontStyle { diff --git a/entities/types/FontVariant.ts b/entities/font/types/FontVariant.ts similarity index 87% rename from entities/types/FontVariant.ts rename to entities/font/types/FontVariant.ts index 04bdec1..a194089 100644 --- a/entities/types/FontVariant.ts +++ b/entities/font/types/FontVariant.ts @@ -1,8 +1,8 @@ // Copyright (c) 2023. Heusala Group Oy . All rights reserved. -import { explainEnum, isEnum, parseEnum, stringifyEnum } from "../../types/Enum"; -import { explainNot, explainOk, explainOr } from "../../types/explain"; -import { isUndefined } from "../../types/undefined"; +import { explainEnum, isEnum, parseEnum, stringifyEnum } from "../../../types/Enum"; +import { explainNot, explainOk, explainOr } from "../../../types/explain"; +import { isUndefined } from "../../../types/undefined"; /** * diff --git a/entities/types/FontWeight.ts b/entities/font/types/FontWeight.ts similarity index 87% rename from entities/types/FontWeight.ts rename to entities/font/types/FontWeight.ts index 01dd02c..fd9ba66 100644 --- a/entities/types/FontWeight.ts +++ b/entities/font/types/FontWeight.ts @@ -1,8 +1,8 @@ // Copyright (c) 2023. Heusala Group Oy . All rights reserved. -import { explainEnum, isEnum, parseEnum, stringifyEnum } from "../../types/Enum"; -import { explainNot, explainOk, explainOr } from "../../types/explain"; -import { isUndefined } from "../../types/undefined"; +import { explainEnum, isEnum, parseEnum, stringifyEnum } from "../../../types/Enum"; +import { explainNot, explainOk, explainOr } from "../../../types/explain"; +import { isUndefined } from "../../../types/undefined"; export enum FontWeight { NORMAL = "normal", diff --git a/dto/RouteDTO.ts b/entities/route/RouteDTO.ts similarity index 84% rename from dto/RouteDTO.ts rename to entities/route/RouteDTO.ts index 750417c..6b7c760 100644 --- a/dto/RouteDTO.ts +++ b/entities/route/RouteDTO.ts @@ -1,16 +1,16 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { explain, explainNot, explainOk, explainOr, explainProperty } from "../types/explain"; -import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../types/OtherKeys"; -import { explainRegularObject, isRegularObject } from "../types/RegularObject"; -import { explainString, explainStringOrUndefined, isString, isStringOrUndefined } from "../types/String"; -import { isUndefined } from "../types/undefined"; -import { DTO } from "./types/DTO"; -import { ExtendableDTO } from "./types/ExtendableDTO"; -import { DTOWithOptionalExtend } from "./types/DTOWithOptionalExtend"; -import { DTOWithName } from "./types/DTOWithName"; -import { DTOWithOptionalLanguage } from "./types/DTOWithOptionalLanguage"; -import { DTOWithOptionalPublicUrl } from "./types/DTOWithOptionalPublicUrl"; +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; +import { explainString, explainStringOrUndefined, isString, isStringOrUndefined } from "../../types/String"; +import { isUndefined } from "../../types/undefined"; +import { DTO } from "../types/DTO"; +import { ExtendableDTO } from "../types/ExtendableDTO"; +import { DTOWithOptionalExtend } from "../types/DTOWithOptionalExtend"; +import { DTOWithName } from "../types/DTOWithName"; +import { DTOWithOptionalLanguage } from "../types/DTOWithOptionalLanguage"; +import { DTOWithOptionalPublicUrl } from "../types/DTOWithOptionalPublicUrl"; export interface RouteDTO extends diff --git a/entities/RouteEntity.ts b/entities/route/RouteEntity.ts similarity index 91% rename from entities/RouteEntity.ts rename to entities/route/RouteEntity.ts index ca639e8..56d7825 100644 --- a/entities/RouteEntity.ts +++ b/entities/route/RouteEntity.ts @@ -1,9 +1,9 @@ // Copyright (c) 2023. Heusala Group Oy . All rights reserved. -import { ReadonlyJsonObject } from "../Json"; -import { createRouteDTO, RouteDTO } from "../dto/RouteDTO"; -import { Extendable } from "./types/Extendable"; -import { JsonSerializable } from "./types/JsonSerializable"; +import { ReadonlyJsonObject } from "../../Json"; +import { createRouteDTO, RouteDTO } from "./RouteDTO"; +import { Extendable } from "../types/Extendable"; +import { JsonSerializable } from "../types/JsonSerializable"; export class RouteEntity implements diff --git a/dto/SeoDTO.ts b/entities/seo/SeoDTO.ts similarity index 89% rename from dto/SeoDTO.ts rename to entities/seo/SeoDTO.ts index 03e2c4f..047306e 100644 --- a/dto/SeoDTO.ts +++ b/entities/seo/SeoDTO.ts @@ -1,11 +1,11 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { explain, explainNot, explainOk, explainOr, explainProperty } from "../types/explain"; -import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../types/OtherKeys"; -import { explainRegularObject, isRegularObject } from "../types/RegularObject"; -import { explainStringOrUndefined, isStringOrUndefined } from "../types/String"; -import { isUndefined } from "../types/undefined"; -import { DTO } from "./types/DTO"; +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; +import { explainStringOrUndefined, isStringOrUndefined } from "../../types/String"; +import { isUndefined } from "../../types/undefined"; +import { DTO } from "../types/DTO"; export interface SeoDTO extends DTO { readonly title ?: string; diff --git a/entities/types/Size.ts b/entities/size/Size.ts similarity index 77% rename from entities/types/Size.ts rename to entities/size/Size.ts index 0531c79..7ef908a 100644 --- a/entities/types/Size.ts +++ b/entities/size/Size.ts @@ -3,9 +3,12 @@ import { ReadonlyJsonObject } from "../../Json"; import { isFunction } from "../../types/Function"; import { isObject } from "../../types/Object"; -import { AutoSizeType, SizeDTO } from "../../dto/SizeDTO"; -import { Entity } from "./Entity"; -import { UnitType } from "./UnitType"; +import { + SizeDTO, + SpecialSize, +} from "./SizeDTO"; +import { Entity } from "../types/Entity"; +import { UnitType } from "../types/UnitType"; /** * Presents a color value @@ -31,7 +34,16 @@ export interface Size /** * Get a value. */ - getValue () : number | AutoSizeType; + getValue () : number | SpecialSize.AUTO; + + /** + * Set a value. + * + * @param value + */ + setValue ( + value : SpecialSize.AUTO, + ) : this; /** * Set a value. @@ -47,6 +59,11 @@ export interface Size /** * Get unit type. */ + getUnit () : UnitType | undefined; + + /** + * Get unit type. It is an alias. + */ getUnitType () : UnitType | undefined; /** diff --git a/dto/SizeDTO.ts b/entities/size/SizeDTO.ts similarity index 81% rename from dto/SizeDTO.ts rename to entities/size/SizeDTO.ts index 9816356..6a43408 100644 --- a/dto/SizeDTO.ts +++ b/entities/size/SizeDTO.ts @@ -1,25 +1,26 @@ // Copyright (c) 2023. Heusala Group Oy . All rights reserved. -import { isArray } from "../types/Array"; -import { explain, explainNot, explainOk, explainOr, explainProperty } from "../types/explain"; -import { isNumber } from "../types/Number"; -import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../types/OtherKeys"; -import { explainRegularObject, isRegularObject } from "../types/RegularObject"; -import { isUndefined } from "../types/undefined"; -import { explainUnitTypeOrUndefined, isUnitTypeOrUndefined, UnitType } from "../entities/types/UnitType"; -import { DTO } from "./types/DTO"; +import { isArray } from "../../types/Array"; +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { isNumber } from "../../types/Number"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; +import { isUndefined } from "../../types/undefined"; +import { explainUnitTypeOrUndefined, isUnitTypeOrUndefined, UnitType } from "../types/UnitType"; +import { DTO } from "../types/DTO"; -export const AUTO_KEYWORD : AutoSizeType = "auto"; -export type AutoSizeType = "auto"; +export enum SpecialSize { + AUTO = "auto" +} -export function isAutoSizeType (value : unknown) : value is AutoSizeType { - return value === AUTO_KEYWORD; +export function isAutoSizeType (value : unknown) : value is SpecialSize.AUTO { + return value === SpecialSize.AUTO; } export interface SizeDTO extends DTO { - readonly value: number | AutoSizeType; + readonly value: number | SpecialSize; /** * Defaults to pixels. @@ -29,7 +30,7 @@ export interface SizeDTO extends DTO { } export function createSizeDTO ( - value : number | AutoSizeType, + value : number | SpecialSize, unit ?: UnitType | undefined, ) : SizeDTO { return { @@ -45,7 +46,7 @@ export function isSizeDTO (value: unknown) : value is SizeDTO { 'value', 'unit', ]) - && (isNumber(value?.value) || value?.value === AUTO_KEYWORD) + && (isNumber(value?.value) || value?.value === SpecialSize.AUTO) && isUnitTypeOrUndefined(value?.unit) ); } @@ -66,7 +67,7 @@ export function explainSizeDTO (value: any) : string { export function explainNumberOrAuto (value: unknown) : string { - return isNumber(value) || value === AUTO_KEYWORD ? explainOk() : explainNot(explainOr(['number', '"auto"'])); + return isNumber(value) || value === SpecialSize.AUTO ? explainOk() : explainNot(explainOr(['number', '"auto"'])); } export function stringifySizeDTO (value : SizeDTO) : string { diff --git a/entities/size/SizeEntity.test.ts b/entities/size/SizeEntity.test.ts new file mode 100644 index 0000000..c1f397d --- /dev/null +++ b/entities/size/SizeEntity.test.ts @@ -0,0 +1,32 @@ +// Copyright (c) 2023. Heusala Group Oy . All rights reserved. + +import { SizeEntity } from "./SizeEntity"; +import { UnitType } from "../types/UnitType"; + +describe('SizeEntity', () => { + + describe('#create', () => { + + it('can create an entity', () => { + expect( SizeEntity.create() ).toBeDefined(); + }); + + it('can create an entity with auto size by default', () => { + expect( SizeEntity.create().isAuto() ).toBe(true); + }); + + it('can create an entity with 10 px', () => { + const entity = SizeEntity.create(10); + expect( entity.getValue() ).toBe(10); + expect( entity.getUnitType() ).toBe(UnitType.PX); + }); + + it('can create an entity with 10 %', () => { + const entity = SizeEntity.create(10, UnitType.PERCENT); + expect( entity.getValue() ).toBe(10); + expect( entity.getUnitType() ).toBe(UnitType.PERCENT); + }); + + }); + +}); diff --git a/entities/SizeEntity.ts b/entities/size/SizeEntity.ts similarity index 58% rename from entities/SizeEntity.ts rename to entities/size/SizeEntity.ts index 5e9bbe1..1e66fdd 100644 --- a/entities/SizeEntity.ts +++ b/entities/size/SizeEntity.ts @@ -1,21 +1,57 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ReadonlyJsonObject } from "../Json"; -import { SizeDTO, createSizeDTO, AUTO_KEYWORD, AutoSizeType, isAutoSizeType } from "../dto/SizeDTO"; -import { Size } from "./types/Size"; -import { UnitType } from "./types/UnitType"; +import { + createSizeDTO, + isAutoSizeType, + isSizeDTO, + SizeDTO, + SpecialSize, +} from "./SizeDTO"; +import { isNumber } from "../../types/Number"; +import { EntityFactoryImpl } from "../types/EntityFactoryImpl"; +import { VariableType } from "../types/EntityProperty"; +import { EntityPropertyImpl } from "../types/EntityPropertyImpl"; +import { + isSize, + Size, +} from "./Size"; +import { + isUnitTypeOrUndefined, + UnitType, +} from "../types/UnitType"; + +export const SizeEntityFactory = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("value").setTypes(VariableType.NUMBER, SpecialSize) ) + .add( EntityPropertyImpl.create("unit", "unitType").setTypes(VariableType.STRING, VariableType.UNDEFINED) ) +); + +export const BaseSizeEntity = SizeEntityFactory.createEntityType(); /** * Size entity. */ export class SizeEntity - implements Size -{ + extends BaseSizeEntity { public static createAuto () : SizeEntity { - return new SizeEntity(AUTO_KEYWORD); + return new SizeEntity(SpecialSize.AUTO); } + /** + * Creates a size with pixels. + * + * @param value + */ + public static create ( + value : Size, + ) : SizeEntity; + + /** + * Creates a size entity with auto size. + */ + public static create () : SizeEntity; + /** * Creates a size with pixels. * @@ -31,7 +67,7 @@ export class SizeEntity * @param value */ public static create ( - value : AutoSizeType, + value : SpecialSize.AUTO, ) : SizeEntity; /** @@ -52,12 +88,25 @@ export class SizeEntity * @param unit Defaults to pixels. */ public static create ( - value : number | AutoSizeType, + value ?: Size | number | SpecialSize.AUTO, unit ?: UnitType, ) : SizeEntity { + if (value === undefined) { + return new SizeEntity(SpecialSize.AUTO) + } + if (isAutoSizeType(value)) { - return new SizeEntity(AUTO_KEYWORD); + return new SizeEntity(SpecialSize.AUTO); + } + + if (isSizeEntity(value) || isSize(value)) { + const v = value.getValue(); + if (v === SpecialSize.AUTO) return new SizeEntity(SpecialSize.AUTO); + return new SizeEntity( + v, + unit ?? UnitType.PX, + ); } return new SizeEntity( @@ -187,17 +236,28 @@ export class SizeEntity ); } - private _value : number | "auto"; - private _unit : UnitType | undefined; + /** + * Construct empty entity + * + * @protected + */ + public constructor (); + + /** + * Construct empty from DTO + */ + public constructor ( + dto: SizeDTO + ); /** * Construct the entity with unit type. * * @param value * @param unit - * @protected + * @public */ - protected constructor ( + public constructor ( value : number, unit : UnitType, ); @@ -208,8 +268,8 @@ export class SizeEntity * @param value * @protected */ - protected constructor ( - value : AutoSizeType, + public constructor ( + value : SpecialSize.AUTO, ); /** @@ -219,80 +279,46 @@ export class SizeEntity * @param unit * @protected */ - protected constructor ( - value : number | AutoSizeType, - unit ?: UnitType, + public constructor ( + value ?: SizeDTO | number | SpecialSize.AUTO, + unit ?: UnitType, ) { - this._value = value; - this._unit = unit; - } - - /** - * @inheritDoc - */ - public getDTO () : SizeDTO { - return createSizeDTO( - this._value, - this._unit, - ); - } - - /** - * @inheritDoc - */ - public valueOf() : ReadonlyJsonObject { - return this.toJSON(); - } - - /** - * @inheritDoc - */ - public toJSON () : ReadonlyJsonObject { - return this.getDTO() as unknown as ReadonlyJsonObject; - } - - /** - * @inheritDoc - */ - public setValue ( - value : number, - unit ?: UnitType | undefined, - ) : this { - this._value = value; - if (unit !== undefined) { - this._unit = unit; + if (value === undefined && unit === undefined) { + super(); + } else if ( isNumber(value) && isUnitTypeOrUndefined(unit) ) { + super(createSizeDTO( + value, + unit, + )); + } else if ( isAutoSizeType(value) ) { + super( createSizeDTO(SpecialSize.AUTO, undefined) ); + } else if (isSizeDTO(value)) { + super(value); + } else if (isSizeEntity(value)) { + super(createSizeDTO( + value.getValue(), + value.getUnitType(), + )); + } else { + throw new TypeError(`new SizeEntity(): Invalid arguments: ${value}, ${unit}`); } - return this; - } - - /** - * @inheritDoc - */ - public getValue () : number | AutoSizeType { - return this._value; } - /** - * @inheritDoc - */ - public getUnitType () : UnitType | undefined { - return this._unit; - } public isAuto (): boolean { - return this._value === AUTO_KEYWORD; + return this.getValue() === SpecialSize.AUTO; } public setAuto (): this { - this._value = AUTO_KEYWORD; - this._unit = undefined; + this.setValue(SpecialSize.AUTO); return this; } public getCssStyles (): string { - if (this.isAuto()) return 'auto'; - if (this._value === 0) return `0`; - return `${this._value}${this._unit}`; + const value = this.getValue(); + if (value === SpecialSize.AUTO) return 'auto'; + if (value === 0) return `0`; + return `${value}${this.getUnitType()}`; } } diff --git a/entities/sizeBox/SizeBox.ts b/entities/sizeBox/SizeBox.ts new file mode 100644 index 0000000..459ecbe --- /dev/null +++ b/entities/sizeBox/SizeBox.ts @@ -0,0 +1,190 @@ +// Copyright (c) 2023. Sendanor . All rights reserved. + +import { + SizeDTO, + SpecialSize, +} from "../size/SizeDTO"; +import { ReadonlyJsonObject } from "../../Json"; +import { isFunction } from "../../types/Function"; +import { isObject } from "../../types/Object"; +import { + SizeBoxDTO, +} from "./SizeBoxDTO"; +import { SizeEntity } from "../size/SizeEntity"; +import { Entity } from "../types/Entity"; +import { UnitType } from "../types/UnitType"; + +/** + * Presents a box of sizes (e.g. top, bottom, left, right) + */ +export interface SizeBox + extends Entity { + + /** + * Returns the DTO object. + */ + getDTO () : SizeBoxDTO; + + /** + * @inheritDoc + */ + valueOf() : ReadonlyJsonObject; + + /** + * @inheritDoc + */ + toJSON () : ReadonlyJsonObject; + + /** + * Returns CSS styles. + */ + getCssStyles () : string; + + + /** + * Get a top size. + */ + getTop () : SizeEntity | undefined; + + /** + * Get top size as a DTO. + */ + getTopDTO () : SizeDTO | undefined; + + /** + * Set a top value as auto + * + * @param value + */ + setTop ( + value : SpecialSize.AUTO, + ) : this; + + /** + * Set a top as a unit. + * + * @param value + * @param unit + */ + setTop ( + value ?: number | undefined, + unit ?: UnitType | undefined, + ) : this; + + + /** + * Get a right size. + */ + getRight () : SizeEntity | undefined; + + /** + * Get right size as a DTO. + */ + getRightDTO () : SizeDTO | undefined; + + /** + * Set a right value as auto + * + * @param value + */ + setRight ( + value : SpecialSize.AUTO, + ) : this; + + /** + * Set a right as a unit. + * + * @param value + * @param unit + */ + setRight ( + value ?: number | undefined, + unit ?: UnitType | undefined, + ) : this; + + + /** + * Get a bottom size. + */ + getBottom () : SizeEntity | undefined; + + /** + * Get bottom size as a DTO. + */ + getBottomDTO () : SizeDTO | undefined; + + /** + * Set a bottom value as auto + * + * @param value + */ + setBottom ( + value : SpecialSize.AUTO, + ) : this; + + /** + * Set a bottom as a unit. + * + * @param value + * @param unit + */ + setBottom ( + value ?: number | undefined, + unit ?: UnitType | undefined, + ) : this; + + + /** + * Get a left size. + */ + getLeft () : SizeEntity | undefined; + + /** + * Get left size as a DTO. + */ + getLeftDTO () : SizeDTO | undefined; + + /** + * Set a left value as auto + * + * @param value + */ + setLeft ( + value : SpecialSize.AUTO, + ) : this; + + /** + * Set a left as a unit. + * + * @param value + * @param unit + */ + setLeft ( + value ?: number | undefined, + unit ?: UnitType | undefined, + ) : this; + +} + +export function isSizeBox (value : unknown) : value is SizeBox { + return ( + isObject(value) + && isFunction(value?.getDTO) + && isFunction(value?.valueOf) + && isFunction(value?.toJSON) + && isFunction(value?.getCssStyles) + && isFunction(value?.getTop) + && isFunction(value?.getTopDTO) + && isFunction(value?.setTop) + && isFunction(value?.getRight) + && isFunction(value?.getRightDTO) + && isFunction(value?.setRight) + && isFunction(value?.getBottom) + && isFunction(value?.getBottomDTO) + && isFunction(value?.setBottom) + && isFunction(value?.getLeft) + && isFunction(value?.getLeftDTO) + && isFunction(value?.setLeft) + ); +} + diff --git a/entities/sizeBox/SizeBoxDTO.ts b/entities/sizeBox/SizeBoxDTO.ts new file mode 100644 index 0000000..7de454f --- /dev/null +++ b/entities/sizeBox/SizeBoxDTO.ts @@ -0,0 +1,84 @@ +// Copyright (c) 2023. Heusala Group Oy . All rights reserved. + +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; +import { isUndefined } from "../../types/undefined"; +import { + explainSizeDTOOrUndefined, + isSizeDTOOrUndefined, + SizeDTO, +} from "../size/SizeDTO"; +import { DTO } from "../types/DTO"; + +export interface SizeBoxDTO extends DTO { + readonly top ?: SizeDTO; + readonly right ?: SizeDTO; + readonly bottom ?: SizeDTO; + readonly left ?: SizeDTO; +} + +export function createSizeBoxDTO ( + top : SizeDTO | undefined, + right : SizeDTO | undefined, + bottom : SizeDTO | undefined, + left : SizeDTO | undefined, +) : SizeBoxDTO { + return { + top, + right, + bottom, + left, + }; +} + +export function isSizeBoxDTO (value: unknown) : value is SizeBoxDTO { + return ( + isRegularObject(value) + && hasNoOtherKeysInDevelopment(value, [ + 'top', + 'right', + 'bottom', + 'left', + ]) + && isSizeDTOOrUndefined(value?.top) + && isSizeDTOOrUndefined(value?.right) + && isSizeDTOOrUndefined(value?.bottom) + && isSizeDTOOrUndefined(value?.left) + ); +} + +export function explainSizeBoxDTO (value: any) : string { + return explain( + [ + explainRegularObject(value), + explainNoOtherKeysInDevelopment(value, [ + 'top', + 'right', + 'bottom', + 'left', + ]) + , explainProperty("top", explainSizeDTOOrUndefined(value?.top)) + , explainProperty("right", explainSizeDTOOrUndefined(value?.right)) + , explainProperty("bottom", explainSizeDTOOrUndefined(value?.bottom)) + , explainProperty("left", explainSizeDTOOrUndefined(value?.left)) + ] + ); +} + +export function stringifySizeBoxDTO (value : SizeBoxDTO) : string { + return `SizeBoxDTO(${value})`; +} + +export function parseSizeBoxDTO (value: unknown) : SizeBoxDTO | undefined { + if (isSizeBoxDTO(value)) return value; + return undefined; +} + +export function isSizeBoxDTOOrUndefined (value: unknown): value is SizeBoxDTO | undefined { + return isUndefined(value) || isSizeBoxDTO(value); +} + +export function explainSizeBoxDTOOrUndefined (value: unknown): string { + return isSizeBoxDTOOrUndefined(value) ? explainOk() : explainNot(explainOr(['SizeBoxDTO', 'undefined'])); +} diff --git a/entities/sizeBox/SizeBoxEntity.ts b/entities/sizeBox/SizeBoxEntity.ts new file mode 100644 index 0000000..14a9a62 --- /dev/null +++ b/entities/sizeBox/SizeBoxEntity.ts @@ -0,0 +1,183 @@ +// Copyright (c) 2023. Sendanor . All rights reserved. + +import { + SizeBoxDTO, + createSizeBoxDTO, + isSizeBoxDTO, +} from "./SizeBoxDTO"; +import { + isSizeDTO, + SizeDTO, +} from "../size/SizeDTO"; +import { reduce } from "../../functions/reduce"; +import { SizeEntity } from "../size/SizeEntity"; +import { + SizeBox, + isSizeBox, +} from "./SizeBox"; +import { EntityFactoryImpl } from "../types/EntityFactoryImpl"; +import { VariableType } from "../types/EntityProperty"; +import { EntityPropertyImpl } from "../types/EntityPropertyImpl"; + +export const SizeBoxEntityFactory = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("top").setTypes(SizeEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("right").setTypes(SizeEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("bottom").setTypes(SizeEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("left").setTypes(SizeEntity, VariableType.UNDEFINED) ) +); + +export const BaseSizeBoxEntity = SizeBoxEntityFactory.createEntityType(); + +/** + * SizeBox entity. + */ +export class SizeBoxEntity + extends BaseSizeBoxEntity + implements SizeBox +{ + + public static create () : SizeBoxEntity; + + /** + * Creates a size box entity. + * + * @param topAndBottom + * @param rightAndLeft + */ + public static create ( + topAndBottom : SizeDTO, + rightAndLeft : SizeDTO, + ) : SizeBoxEntity; + + /** + * Creates a size box entity. + * + * @param top + * @param right + * @param bottom + * @param left + */ + public static create ( + top : SizeDTO, + right : SizeDTO, + bottom : SizeDTO, + left : SizeDTO, + ) : SizeBoxEntity; + + /** + * Creates a size box entity. + * + * @param top + * @param right + * @param bottom + * @param left + */ + public static create ( + top ?: SizeDTO | SizeBoxDTO | SizeBoxEntity, + right ?: SizeDTO, + bottom ?: SizeDTO, + left ?: SizeDTO, + ) : SizeBoxEntity { + if ( top === undefined && right === undefined && bottom === undefined && left === undefined ) { + return new SizeBoxEntity(); + } else if ( isSizeBoxDTO(top) ) { + return new SizeBoxEntity(top); + } else if ( isSizeBoxEntity(top) ) { + return new SizeBoxEntity(top.getDTO()); + } else if ( isSizeBox(top) ) { + return new SizeBoxEntity(top.getDTO()); + } else if ( isSizeDTO(top) && isSizeDTO(right) && bottom === undefined && left === undefined ) { + return new SizeBoxEntity( createSizeBoxDTO(top, right, top, right) ); + } else if ( isSizeDTO(top) && isSizeDTO(right) && isSizeDTO(bottom) && isSizeDTO(left) ) { + return new SizeBoxEntity( createSizeBoxDTO(top, right, bottom, left) ); + } else { + throw new TypeError(`Invalid arguments for create: ${top}, ${right}, ${bottom}, ${left}`); + } + } + + /** + * Creates a size box entity from DTO. + * + * @param value + */ + public static createFromDTO ( + value : SizeBoxDTO, + ) : SizeBoxEntity { + return new SizeBoxEntity(value); + } + + public static merge ( + ...values: readonly (SizeBoxDTO | SizeBox | SizeBoxEntity)[] + ) : SizeBoxEntity { + return SizeBoxEntity.createFromDTO( + reduce( + values, + ( + prev: SizeBoxDTO, + item: SizeBoxDTO | SizeBox | SizeBoxEntity, + ) : SizeBoxDTO => { + const dto : SizeBoxDTO = this.toDTO(item); + return { + ...prev, + ...dto, + }; + }, + createSizeBoxDTO( + undefined, + undefined, + undefined, + undefined, + ), + ) + ); + } + + public static toDTO ( + value: SizeBoxDTO | SizeBox | SizeBoxEntity, + ) : SizeBoxDTO { + if (isSizeBoxEntity(value)) { + return value.getDTO(); + } else if (isSizeBox(value)) { + return value.getDTO(); + } else { + return value; + } + } + + protected constructor ( + value ?: SizeBoxDTO | SizeBox, + ) { + super( + isSizeBoxDTO(value) + ? value + : ( + isSizeBox(value) + ? value.getDTO() + : undefined + ) + ); + } + + /** + * @inheritDoc + */ + public getCssStyles (): string { + const top = (this.getTop() ?? SizeEntity.createZero()).getCssStyles(); + const right = (this.getRight() ?? SizeEntity.createZero()).getCssStyles(); + const bottom = (this.getBottom() ?? SizeEntity.createZero()).getCssStyles(); + const left = (this.getLeft() ?? SizeEntity.createZero()).getCssStyles(); + if ( top === bottom && right === left ) { + if ( top === right ) { + return `${ top }`; + } + return `${ top } ${ right }`; + } + return `${ top } ${ right } ${ bottom } ${ left }`; + } + +} + +export function isSizeBoxEntity (value: unknown): value is SizeBoxEntity { + return value instanceof SizeBoxEntity; +} diff --git a/entities/sizeDimensions/SizeDimensions.ts b/entities/sizeDimensions/SizeDimensions.ts new file mode 100644 index 0000000..7b63c5d --- /dev/null +++ b/entities/sizeDimensions/SizeDimensions.ts @@ -0,0 +1,122 @@ +// Copyright (c) 2023. Sendanor . All rights reserved. + +import { + SizeDTO, + SpecialSize, +} from "../size/SizeDTO"; +import { ReadonlyJsonObject } from "../../Json"; +import { isFunction } from "../../types/Function"; +import { isObject } from "../../types/Object"; +import { + SizeDimensionsDTO, +} from "./SizeDimensionsDTO"; +import { SizeEntity } from "../size/SizeEntity"; +import { Entity } from "../types/Entity"; +import { UnitType } from "../types/UnitType"; + +/** + * Presents dimensions of a box (e.g. width, height) + */ +export interface SizeDimensions + extends Entity { + + /** + * Returns the DTO object. + */ + getDTO () : SizeDimensionsDTO; + + /** + * @inheritDoc + */ + valueOf() : ReadonlyJsonObject; + + /** + * @inheritDoc + */ + toJSON () : ReadonlyJsonObject; + + /** + * Returns CSS styles. + */ + getCssStyles () : string; + + + /** + * Get a top size. + */ + getWidth () : SizeEntity | undefined; + + /** + * Get top size as a DTO. + */ + getWidthDTO () : SizeDTO | undefined; + + /** + * Set a top value as auto + * + * @param value + */ + setWidth ( + value : SpecialSize.AUTO, + ) : this; + + /** + * Set a top as a unit. + * + * @param value + * @param unit + */ + setWidth ( + value ?: number | undefined, + unit ?: UnitType | undefined, + ) : this; + + + /** + * Get a right size. + */ + getHeight () : SizeEntity | undefined; + + /** + * Get right size as a DTO. + */ + getHeightDTO () : SizeDTO | undefined; + + /** + * Set a right value as auto + * + * @param value + */ + setHeight ( + value : SpecialSize.AUTO, + ) : this; + + /** + * Set a right as a unit. + * + * @param value + * @param unit + */ + setHeight ( + value ?: number | undefined, + unit ?: UnitType | undefined, + ) : this; + +} + +export function isSizeDimensions (value : unknown) : value is SizeDimensions { + return ( + isObject(value) + && isFunction(value?.getDTO) + && isFunction(value?.valueOf) + && isFunction(value?.toJSON) + && isFunction(value?.getCssStyles) + && isFunction(value?.getWidth) + && isFunction(value?.getWidthDTO) + && isFunction(value?.setWidth) + && isFunction(value?.getHeight) + && isFunction(value?.getHeightDTO) + && isFunction(value?.setHeight) + ); +} + diff --git a/entities/sizeDimensions/SizeDimensionsDTO.ts b/entities/sizeDimensions/SizeDimensionsDTO.ts new file mode 100644 index 0000000..895ac52 --- /dev/null +++ b/entities/sizeDimensions/SizeDimensionsDTO.ts @@ -0,0 +1,70 @@ +// Copyright (c) 2023. Heusala Group Oy . All rights reserved. + +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; +import { isUndefined } from "../../types/undefined"; +import { + explainSizeDTOOrUndefined, + isSizeDTOOrUndefined, + SizeDTO, +} from "../size/SizeDTO"; +import { DTO } from "../types/DTO"; + +export interface SizeDimensionsDTO extends DTO { + readonly width ?: SizeDTO; + readonly height ?: SizeDTO; +} + +export function createSizeDimensionsDTO ( + width : SizeDTO | undefined, + height : SizeDTO | undefined, +) : SizeDimensionsDTO { + return { + width, + height, + }; +} + +export function isSizeDimensionsDTO (value: unknown) : value is SizeDimensionsDTO { + return ( + isRegularObject(value) + && hasNoOtherKeysInDevelopment(value, [ + 'width', + 'height', + ]) + && isSizeDTOOrUndefined(value?.width) + && isSizeDTOOrUndefined(value?.height) + ); +} + +export function explainSizeDimensionsDTO (value: any) : string { + return explain( + [ + explainRegularObject(value), + explainNoOtherKeysInDevelopment(value, [ + 'width', + 'height', + ]) + , explainProperty("width", explainSizeDTOOrUndefined(value?.width)) + , explainProperty("height", explainSizeDTOOrUndefined(value?.height)) + ] + ); +} + +export function stringifySizeDimensionsDTO (value : SizeDimensionsDTO) : string { + return `SizeDimensionsDTO(${value})`; +} + +export function parseSizeDimensionsDTO (value: unknown) : SizeDimensionsDTO | undefined { + if (isSizeDimensionsDTO(value)) return value; + return undefined; +} + +export function isSizeDimensionsDTOOrUndefined (value: unknown): value is SizeDimensionsDTO | undefined { + return isUndefined(value) || isSizeDimensionsDTO(value); +} + +export function explainSizeDimensionsDTOOrUndefined (value: unknown): string { + return isSizeDimensionsDTOOrUndefined(value) ? explainOk() : explainNot(explainOr(['SizeDimensionsDTO', 'undefined'])); +} diff --git a/entities/sizeDimensions/SizeDimensionsEntity.ts b/entities/sizeDimensions/SizeDimensionsEntity.ts new file mode 100644 index 0000000..e36533b --- /dev/null +++ b/entities/sizeDimensions/SizeDimensionsEntity.ts @@ -0,0 +1,155 @@ +// Copyright (c) 2023. Sendanor . All rights reserved. + +import { + SizeDimensionsDTO, + createSizeDimensionsDTO, + isSizeDimensionsDTO, +} from "./SizeDimensionsDTO"; +import { + isSizeDTO, + SizeDTO, +} from "../size/SizeDTO"; +import { reduce } from "../../functions/reduce"; +import { SizeEntity } from "../size/SizeEntity"; +import { + SizeDimensions, + isSizeDimensions, +} from "./SizeDimensions"; +import { EntityFactoryImpl } from "../types/EntityFactoryImpl"; +import { VariableType } from "../types/EntityProperty"; +import { EntityPropertyImpl } from "../types/EntityPropertyImpl"; + +export const SizeDimensionsEntityFactory = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("width").setTypes(SizeEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("height").setTypes(SizeEntity, VariableType.UNDEFINED) ) +); + +export const BaseSizeDimensionsEntity = SizeDimensionsEntityFactory.createEntityType(); + +/** + * SizeDimensions entity. + */ +export class SizeDimensionsEntity + extends BaseSizeDimensionsEntity + implements SizeDimensions +{ + + public static create () : SizeDimensionsEntity; + + /** + * Creates a size box entity. + * + * @param width + * @param height + * @param bottom + * @param left + */ + public static create ( + width : SizeDTO, + height : SizeDTO, + ) : SizeDimensionsEntity; + + /** + * Creates a size box entity. + * + * @param width + * @param height + */ + public static create ( + width ?: SizeDTO | SizeDimensionsDTO | SizeDimensionsEntity, + height ?: SizeDTO, + ) : SizeDimensionsEntity { + if ( width === undefined && height === undefined ) { + return new SizeDimensionsEntity(); + } else if ( isSizeDimensionsDTO(width) ) { + return new SizeDimensionsEntity(width); + } else if ( isSizeDimensionsEntity(width) ) { + return new SizeDimensionsEntity(width.getDTO()); + } else if ( isSizeDimensions(width) ) { + return new SizeDimensionsEntity(width.getDTO()); + } else if ( isSizeDTO(width) && isSizeDTO(height) ) { + return new SizeDimensionsEntity( createSizeDimensionsDTO(width, height) ); + } else { + throw new TypeError(`Invalid arguments for create: ${width}, ${height}`); + } + } + + /** + * Creates a size box entity from DTO. + * + * @param value + */ + public static createFromDTO ( + value : SizeDimensionsDTO, + ) : SizeDimensionsEntity { + return new SizeDimensionsEntity(value); + } + + public static merge ( + ...values: readonly (SizeDimensionsDTO | SizeDimensions | SizeDimensionsEntity)[] + ) : SizeDimensionsEntity { + return SizeDimensionsEntity.createFromDTO( + reduce( + values, + ( + prev: SizeDimensionsDTO, + item: SizeDimensionsDTO | SizeDimensions | SizeDimensionsEntity, + ) : SizeDimensionsDTO => { + const dto : SizeDimensionsDTO = this.toDTO(item); + return { + ...prev, + ...dto, + }; + }, + createSizeDimensionsDTO( + undefined, + undefined, + ), + ) + ); + } + + public static toDTO ( + value: SizeDimensionsDTO | SizeDimensions | SizeDimensionsEntity, + ) : SizeDimensionsDTO { + if (isSizeDimensionsEntity(value)) { + return value.getDTO(); + } else if (isSizeDimensions(value)) { + return value.getDTO(); + } else { + return value; + } + } + + protected constructor ( + value ?: SizeDimensionsDTO | SizeDimensions, + ) { + super( + isSizeDimensionsDTO(value) + ? value + : ( + isSizeDimensions(value) + ? value.getDTO() + : undefined + ) + ); + } + + /** + * @inheritDoc + */ + public getCssStyles (): string { + const width = (this.getWidth() ?? SizeEntity.createZero()).getCssStyles(); + const height = (this.getHeight() ?? SizeEntity.createZero()).getCssStyles(); + if ( width === height ) { + return `${ width }`; + } + return `${ width } ${ height }`; + } + +} + +export function isSizeDimensionsEntity (value: unknown): value is SizeDimensionsEntity { + return value instanceof SizeDimensionsEntity; +} diff --git a/entities/types/Style.ts b/entities/style/Style.ts similarity index 64% rename from entities/types/Style.ts rename to entities/style/Style.ts index d197212..695945f 100644 --- a/entities/types/Style.ts +++ b/entities/style/Style.ts @@ -1,29 +1,35 @@ // Copyright (c) 2023. Heusala Group Oy . All rights reserved. +import { BorderBoxDTO } from "../borderBox/BorderBoxDTO"; +import { SizeBoxDTO } from "../sizeBox/SizeBoxDTO"; import { ReadonlyJsonObject } from "../../Json"; import { isFunction } from "../../types/Function"; import { isObject } from "../../types/Object"; -import { BackgroundDTO } from "../../dto/BackgroundDTO"; -import { BorderDTO } from "../../dto/BorderDTO"; -import { ColorDTO } from "../../dto/ColorDTO"; -import { FontDTO } from "../../dto/FontDTO"; -import { SizeDTO } from "../../dto/SizeDTO"; -import { StyleDTO } from "../../dto/StyleDTO"; -import { TextDecorationDTO } from "../../dto/TextDecorationDTO"; -import { BoxSizing } from "../../dto/types/BoxSizing"; -import { TextAlign } from "../../dto/types/TextAlign"; -import { BackgroundEntity } from "../BackgroundEntity"; -import { BorderEntity } from "../BorderEntity"; -import { ColorEntity } from "../ColorEntity"; -import { FontEntity } from "../FontEntity"; -import { SizeEntity } from "../SizeEntity"; -import { TextDecorationEntity } from "../TextDecorationEntity"; -import { Background } from "./Background"; -import { Border } from "./Border"; -import { Entity } from "./Entity"; -import { Font } from "./Font"; -import { Size } from "./Size"; -import { TextDecoration } from "./TextDecoration"; +import { BackgroundDTO } from "../background/BackgroundDTO"; +import { BorderDTO } from "../border/BorderDTO"; +import { ColorDTO } from "../color/ColorDTO"; +import { FontDTO } from "../font/FontDTO"; +import { SizeDTO } from "../size/SizeDTO"; +import { StyleDTO } from "./StyleDTO"; +import { TextDecorationDTO } from "../textDecoration/TextDecorationDTO"; +import { BoxSizing } from "../types/BoxSizing"; +import { TextAlign } from "../types/TextAlign"; +import { BackgroundEntity } from "../background/BackgroundEntity"; +import { BorderBoxEntity } from "../borderBox/BorderBoxEntity"; +import { BorderEntity } from "../border/BorderEntity"; +import { ColorEntity } from "../color/ColorEntity"; +import { FontEntity } from "../font/FontEntity"; +import { SizeBoxEntity } from "../sizeBox/SizeBoxEntity"; +import { SizeEntity } from "../size/SizeEntity"; +import { TextDecorationEntity } from "../textDecoration/TextDecorationEntity"; +import { Background } from "../background/Background"; +import { Border } from "../border/Border"; +import { BorderBox } from "../borderBox/BorderBox"; +import { Entity } from "../types/Entity"; +import { Font } from "../font/Font"; +import { Size } from "../size/Size"; +import { SizeBox } from "../sizeBox/SizeBox"; +import { TextDecoration } from "../textDecoration/TextDecoration"; /** * Interface for Style entities. @@ -105,45 +111,47 @@ export interface Style */ getCssStyles () : ReadonlyJsonObject; - getMargin () : SizeDTO | [SizeDTO, SizeDTO] | [SizeDTO, SizeDTO, SizeDTO, SizeDTO] | undefined; - getTopMargin () : SizeDTO | undefined; - getBottomMargin () : SizeDTO | undefined; - getRightMargin () : SizeDTO | undefined; - getLeftMargin () : SizeDTO | undefined; + getMargin () : Size | SizeBox | undefined; + getTopMargin () : Size | undefined; + getBottomMargin () : Size | undefined; + getRightMargin () : Size | undefined; + getLeftMargin () : Size | undefined; - setMargin (value: SizeEntity | SizeDTO | number | undefined) : this; - setTopMargin (value: SizeEntity | SizeDTO | number | undefined) : this; - setBottomMargin (value: SizeEntity | SizeDTO | number | undefined) : this; - setRightMargin (value: SizeEntity | SizeDTO | number | undefined) : this; - setLeftMargin (value: SizeEntity | SizeDTO | number | undefined) : this; + setMargin (value: SizeEntity | Size | number | undefined) : this; + setTopMargin (value: SizeEntity | Size | number | undefined) : this; + setBottomMargin (value: SizeEntity | Size | number | undefined) : this; + setRightMargin (value: SizeEntity | Size | number | undefined) : this; + setLeftMargin (value: SizeEntity | Size | number | undefined) : this; - getPadding () : SizeDTO | [SizeDTO, SizeDTO] | [SizeDTO, SizeDTO, SizeDTO, SizeDTO] | undefined; - setPadding (value: SizeEntity | SizeDTO | number | undefined) : this; + getPadding () : Size | SizeBox | undefined; + getPadding () : SizeDTO | SizeBoxDTO | undefined; + setPadding (value: SizeEntity | SizeBoxEntity | SizeDTO | SizeBoxDTO | number | undefined) : this; - getTopPadding () : SizeDTO | undefined; - getBottomPadding () : SizeDTO | undefined; - getRightPadding () : SizeDTO | undefined; - getLeftPadding () : SizeDTO | undefined; + getTopPadding () : Size | undefined; + getBottomPadding () : Size | undefined; + getRightPadding () : Size | undefined; + getLeftPadding () : Size | undefined; - setTopPadding (value: SizeEntity | SizeDTO | number | undefined) : this; - setBottomPadding (value: SizeEntity | SizeDTO | number | undefined) : this; - setRightPadding (value: SizeEntity | SizeDTO | number | undefined) : this; - setLeftPadding (value: SizeEntity | SizeDTO | number | undefined) : this; + setTopPadding (value: SizeEntity | Size | number | undefined) : this; + setBottomPadding (value: SizeEntity | Size | number | undefined) : this; + setRightPadding (value: SizeEntity | Size | number | undefined) : this; + setLeftPadding (value: SizeEntity | Size | number | undefined) : this; - getBorder () : BorderDTO | [BorderDTO, BorderDTO] | [BorderDTO, BorderDTO, BorderDTO, BorderDTO] | undefined; - setBorder (value : BorderEntity | BorderDTO | undefined) : this; + getBorder () : Border | BorderBox | undefined; + getBorderDTO () : BorderDTO | BorderBoxDTO | undefined; + setBorder (value : BorderEntity | BorderDTO | BorderBoxEntity | BorderBoxDTO | undefined) : this; - getTopBorder () : BorderDTO | undefined; - getBottomBorder () : BorderDTO | undefined; - getRightBorder () : BorderDTO | undefined; - getLeftBorder () : BorderDTO | undefined; + getTopBorder () : Border | undefined; + getBottomBorder () : Border | undefined; + getRightBorder () : Border | undefined; + getLeftBorder () : Border | undefined; - setTopBorder (value: Border | BorderDTO | number | undefined) : this; - setBottomBorder (value: Border | BorderDTO | number | undefined) : this; - setRightBorder (value: Border | BorderDTO | number | undefined) : this; - setLeftBorder (value: Border | BorderDTO | number | undefined) : this; + setTopBorder (value: Border | BorderEntity | number | undefined) : this; + setBottomBorder (value: Border | BorderEntity | number | undefined) : this; + setRightBorder (value: Border | BorderEntity | number | undefined) : this; + setLeftBorder (value: Border | BorderEntity | number | undefined) : this; getFontDTO () : FontDTO | undefined; getFont () : Font | undefined; diff --git a/dto/StyleDTO.ts b/entities/style/StyleDTO.ts similarity index 83% rename from dto/StyleDTO.ts rename to entities/style/StyleDTO.ts index 0187c49..4e3205b 100644 --- a/dto/StyleDTO.ts +++ b/entities/style/StyleDTO.ts @@ -1,39 +1,40 @@ // Copyright (c) 2023. Heusala Group Oy . All rights reserved. -import { explain, explainNot, explainOk, explainOr, explainProperty } from "../types/explain"; -import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../types/OtherKeys"; -import { explainRegularObject, isRegularObject } from "../types/RegularObject"; -import { isUndefined } from "../types/undefined"; -import { BackgroundDTO, explainBackgroundDTOOrUndefined, isBackgroundDTOOrUndefined } from "./BackgroundDTO"; -import { BorderDTO, explainMultiBorderDTOOrUndefined, isMultiBorderDTOOrUndefined } from "./BorderDTO"; -import { ColorDTO, explainColorDTOOrUndefined, isColorDTOOrUndefined } from "./ColorDTO"; -import { explainFontDTOOrUndefined, FontDTO, isFontDTOOrUndefined } from "./FontDTO"; +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; +import { isUndefined } from "../../types/undefined"; +import { BackgroundDTO, explainBackgroundDTOOrUndefined, isBackgroundDTOOrUndefined } from "../background/BackgroundDTO"; +import { BorderDTO, explainMultiBorderDTOOrUndefined, isMultiBorderDTOOrUndefined } from "../border/BorderDTO"; +import { ColorDTO, explainColorDTOOrUndefined, isColorDTOOrUndefined } from "../color/ColorDTO"; +import { explainFontDTOOrUndefined, FontDTO, isFontDTOOrUndefined } from "../font/FontDTO"; +import { SizeBoxDTO } from "../sizeBox/SizeBoxDTO"; import { explainMultiSizeDTOOrUndefined, explainSizeDTOOrUndefined, isMultiSizeDTOOrUndefined, isSizeDTOOrUndefined, SizeDTO -} from "./SizeDTO"; +} from "../size/SizeDTO"; import { explainTextDecorationDTOOrUndefined, isTextDecorationDTOOrUndefined, TextDecorationDTO, -} from "./TextDecorationDTO"; -import { BoxSizing, explainBoxSizingOrUndefined, isBoxSizingOrUndefined } from "./types/BoxSizing"; -import { DTO } from "./types/DTO"; -import { explainTextAlignOrUndefined, isTextAlignOrUndefined, TextAlign } from "./types/TextAlign"; +} from "../textDecoration/TextDecorationDTO"; +import { BoxSizing, explainBoxSizingOrUndefined, isBoxSizingOrUndefined } from "../types/BoxSizing"; +import { DTO } from "../types/DTO"; +import { explainTextAlignOrUndefined, isTextAlignOrUndefined, TextAlign } from "../types/TextAlign"; export interface StyleDTO extends DTO { - readonly textAlign ?: TextAlign; - readonly textColor ?: ColorDTO; - readonly width ?: SizeDTO; - readonly height ?: SizeDTO; - readonly margin ?: SizeDTO | [SizeDTO, SizeDTO] | [SizeDTO, SizeDTO, SizeDTO, SizeDTO]; - readonly padding ?: SizeDTO | [SizeDTO, SizeDTO] | [SizeDTO, SizeDTO, SizeDTO, SizeDTO]; - readonly border ?: BorderDTO | [BorderDTO, BorderDTO] | [BorderDTO, BorderDTO, BorderDTO, BorderDTO]; - readonly font ?: FontDTO; - readonly textDecoration ?: TextDecorationDTO; - readonly background ?: BackgroundDTO; + readonly textAlign ?: TextAlign; + readonly textColor ?: ColorDTO; + readonly width ?: SizeDTO; + readonly height ?: SizeDTO; + readonly margin ?: SizeDTO | SizeBoxDTO; + readonly padding ?: SizeDTO | SizeBoxDTO; + readonly border ?: BorderDTO | [BorderDTO, BorderDTO] | [BorderDTO, BorderDTO, BorderDTO, BorderDTO]; + readonly font ?: FontDTO; + readonly textDecoration ?: TextDecorationDTO; + readonly background ?: BackgroundDTO; readonly minWidth ?: SizeDTO; readonly minHeight ?: SizeDTO; readonly maxWidth ?: SizeDTO; @@ -46,8 +47,8 @@ export function createStyleDTO ( background : BackgroundDTO | undefined, width : SizeDTO | undefined, height : SizeDTO | undefined, - margin : SizeDTO | [SizeDTO, SizeDTO] | [SizeDTO, SizeDTO, SizeDTO, SizeDTO] | undefined, - padding : SizeDTO | [SizeDTO, SizeDTO] | [SizeDTO, SizeDTO, SizeDTO, SizeDTO] | undefined, + margin : SizeDTO | SizeBoxDTO | undefined, + padding : SizeDTO | SizeBoxDTO | undefined, border : BorderDTO | [BorderDTO, BorderDTO] | [BorderDTO, BorderDTO, BorderDTO, BorderDTO] | undefined, font : FontDTO | undefined, textDecoration : TextDecorationDTO | undefined, diff --git a/entities/StyleEntity.test.ts b/entities/style/StyleEntity.test.ts similarity index 97% rename from entities/StyleEntity.test.ts rename to entities/style/StyleEntity.test.ts index 66c5eee..7f5e68b 100644 --- a/entities/StyleEntity.test.ts +++ b/entities/style/StyleEntity.test.ts @@ -2,7 +2,7 @@ import { describe, it, expect } from '@jest/globals'; import { StyleEntity } from "./StyleEntity"; -import { UnitType } from "./types/UnitType"; +import { UnitType } from "../types/UnitType"; describe('StyleEntity', () => { diff --git a/entities/style/StyleEntity.ts b/entities/style/StyleEntity.ts new file mode 100644 index 0000000..6cea9bd --- /dev/null +++ b/entities/style/StyleEntity.ts @@ -0,0 +1,509 @@ +// Copyright (c) 2023. Heusala Group Oy . All rights reserved. + +import { BackgroundDTO } from "../background/BackgroundDTO"; +import { + BorderDTO, + createBorderDTO, + isBorderDTO, +} from "../border/BorderDTO"; +import { + ColorDTO, + createColorDTO, +} from "../color/ColorDTO"; +import { + createFontDTO, + FontDTO, +} from "../font/FontDTO"; +import { + createSizeDTO, + isSizeDTO, + SizeDTO, +} from "../size/SizeDTO"; +import { + createStyleDTO, + StyleDTO, +} from "./StyleDTO"; +import { BorderStyle } from "../types/BorderStyle"; +import { BoxSizing } from "../types/BoxSizing"; +import { TextAlign } from "../types/TextAlign"; +import { map } from "../../functions/map"; +import { reduce } from "../../functions/reduce"; +import { ReadonlyJsonObject } from "../../Json"; +import { isArray } from "../../types/Array"; +import { isNumber } from "../../types/Number"; +import { isString } from "../../types/String"; +import { + BackgroundEntity, + isBackgroundEntity, +} from "../background/BackgroundEntity"; +import { BorderBoxEntity } from "../borderBox/BorderBoxEntity"; +import { + BorderEntity, + isBorderEntity, +} from "../border/BorderEntity"; +import { + ColorEntity, + isColorEntity, +} from "../color/ColorEntity"; +import { + FontEntity, + isFontEntity, +} from "../font/FontEntity"; +import { SizeBoxEntity } from "../sizeBox/SizeBoxEntity"; +import { + isSizeEntity, + SizeEntity, +} from "../size/SizeEntity"; +import { + TextDecorationEntity, +} from "../textDecoration/TextDecorationEntity"; +import { + isBackground, +} from "../background/Background"; +import { + Border, + isBorder, +} from "../border/Border"; +import { isBorderBox } from "../borderBox/BorderBox"; +import { EntityFactoryImpl } from "../types/EntityFactoryImpl"; +import { VariableType } from "../types/EntityProperty"; +import { EntityPropertyImpl } from "../types/EntityPropertyImpl"; +import { + Font, + isFont, +} from "../font/Font"; +import { + isSize, + Size, +} from "../size/Size"; +import { + isStyle, + Style, +} from "./Style"; +import { UnitType } from "../types/UnitType"; + +const TOP_AND_BOTTOM_MARGIN_INDEX = 0; +const LEFT_AND_RIGHT_MARGIN_INDEX = 1; +const TOP_MARGIN_INDEX = 0; +const RIGHT_MARGIN_INDEX = 1; +const BOTTOM_MARGIN_INDEX = 2; +const LEFT_MARGIN_INDEX = 3; + +export const StyleEntityFactory = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("textAlign").setTypes(TextAlign, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("textColor").setTypes(ColorEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("width").setTypes(SizeEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("height").setTypes(SizeEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("margin").setTypes(SizeEntity, SizeBoxEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("padding").setTypes(SizeEntity, SizeBoxEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("border").setTypes(BorderEntity, BorderBoxEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("font").setTypes(FontEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("textDecoration").setTypes(TextDecorationEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("background").setTypes(BackgroundEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("minWidth").setTypes(SizeEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("minHeight").setTypes(SizeEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("maxWidth").setTypes(SizeEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("maxHeight").setTypes(SizeEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("boxSizing").setTypes(BoxSizing, VariableType.UNDEFINED) ) +); + +export const BaseStyleEntity = StyleEntityFactory.createEntityType(); + + +/** + * Style entity. + */ +export class StyleEntity + extends BaseStyleEntity + implements Style +{ + + public static create ( + ) : StyleEntity { + return new this(); + } + + /** + * Construct a style entity. + * + * @param style + */ + public static createFromDTO ( + style : StyleDTO, + ) : StyleEntity { + return new this( style ); + } + + /** + * Construct a style entity. + */ + public constructor ( + style ?: StyleDTO | StyleEntity | Style, + ) { + super( + isStyleEntity(style) ? style.getDTO() : style + ); + } + + public static prepareBackgroundDTO ( + value : BackgroundEntity | BackgroundDTO | undefined + ) : BackgroundDTO | undefined { + if (value === undefined) return undefined; + if (isBackgroundEntity(value)) return value.getDTO(); + if (isBackground(value)) return value.getDTO(); + return value; + } + + public static prepareColorDTO ( + value : ColorEntity | ColorDTO | string | undefined + ) : ColorDTO | undefined { + if (value === undefined) return undefined; + if (isString(value)) return createColorDTO(value); + if (isColorEntity(value)) return value.getDTO(); + return value; + } + + public static prepareSizeDTO ( + value : SizeEntity | Size | SizeDTO | number | undefined + ) : SizeDTO | undefined { + if (value === undefined) return undefined; + if (isNumber(value)) return createSizeDTO(value, UnitType.PX); + if (isSizeEntity(value)) return value.getDTO(); + if (isSize(value)) return value.getDTO(); + return value; + } + + public static prepareFontDTO ( + value : Font | FontEntity | FontDTO | number | string | undefined + ) : FontDTO | undefined { + if (value === undefined) return undefined; + if (isNumber(value)) { + return createFontDTO( + undefined, + undefined, + undefined, + SizeEntity.create(value).getDTO(), + undefined, + undefined, + ); + } + if (isString(value)) { + return createFontDTO( + undefined, + undefined, + undefined, + undefined, + undefined, + value, + ); + } + if (isFontEntity(value)) return value.getDTO(); + if (isFont(value)) return value.getDTO(); + return value; + } + + public static prepareBorderDTO ( + value : Border | BorderDTO | number | undefined + ) : BorderDTO | undefined { + if (value === undefined) return undefined; + if (isNumber(value)) { + return createBorderDTO( + createSizeDTO(value), + undefined, + undefined, + undefined, + ); + } + if (isBorderEntity(value)) return value.getDTO(); + if (isBorder(value)) return value.getDTO(); + return value; + } + + public static prepareSizeListDTO ( + value : ( + SizeEntity + | [ + SizeEntity | SizeDTO | number | undefined, + SizeEntity | SizeDTO | number | undefined, + ] + | [ + SizeEntity | SizeDTO | number | undefined, + SizeEntity | SizeDTO | number | undefined, + SizeEntity | SizeDTO | number | undefined, + SizeEntity | SizeDTO | number | undefined, + ] + | SizeDTO + | number + | undefined + ) + ) : SizeDTO | [SizeDTO, SizeDTO, SizeDTO, SizeDTO] | undefined { + if (value === undefined) return undefined; + if (isNumber(value)) return createSizeDTO(value, UnitType.PX); + if (isSizeEntity(value)) return value.getDTO(); + if (isArray(value)) { + + if (value.length === 2) { + const top_and_bottom : SizeDTO | undefined = StyleEntity.prepareSizeDTO(value[TOP_AND_BOTTOM_MARGIN_INDEX]); + if (!top_and_bottom) throw new TypeError(`prepareSizeListDTO: Invalid [undefined, *] array provided`); + const right_and_left: SizeDTO | undefined = StyleEntity.prepareSizeDTO(value[LEFT_AND_RIGHT_MARGIN_INDEX]); + if (!right_and_left) throw new TypeError(`prepareSizeListDTO: Invalid [SizeDTO, undefined] array provided`); + return [ + top_and_bottom, // top + right_and_left, // right + top_and_bottom, // bottom + right_and_left, // left + ]; + } + + if (value.length === 4) { + const top : SizeDTO | undefined = StyleEntity.prepareSizeDTO( value[TOP_MARGIN_INDEX] ); + if (!top) throw new TypeError(`prepareSizeListDTO: Invalid [undefined, *, *, *] array provided`); + const right : SizeDTO | undefined = StyleEntity.prepareSizeDTO( value[RIGHT_MARGIN_INDEX] ); + if (!right) throw new TypeError(`prepareSizeListDTO: Invalid [SizeDTO, undefined, *, *] array provided`); + const bottom : SizeDTO | undefined = StyleEntity.prepareSizeDTO( value[BOTTOM_MARGIN_INDEX] ); + if (!bottom) throw new TypeError(`prepareSizeListDTO: Invalid [SizeDTO, SizeDTO, undefined, *] array provided`); + const left : SizeDTO | undefined = StyleEntity.prepareSizeDTO( value[LEFT_MARGIN_INDEX] ); + if (!left) throw new TypeError(`prepareSizeListDTO: Invalid [SizeDTO, SizeDTO, SizeDTO, undefined] array provided`); + return [ + top, + right, + bottom, + left, + ]; + } + + // Runtime assert, should not happen. + // @ts-ignore + throw new TypeError(`prepareSizeListDTO: Incorrect array length: ${value.length}`); + + } + return value; + } + + public static prepareBorderListDTO ( + value : ( + Border + | [ + Border | BorderDTO | number | undefined, + Border | BorderDTO | number | undefined, + ] + | [ + Border | BorderDTO | number | undefined, + Border | BorderDTO | number | undefined, + Border | BorderDTO | number | undefined, + Border | BorderDTO | number | undefined, + ] + | BorderDTO + | number + | undefined + ) + ) : BorderDTO | [BorderDTO, BorderDTO, BorderDTO, BorderDTO] | undefined { + if (value === undefined) return undefined; + if (isNumber(value)) { + return createBorderDTO( + createSizeDTO( value ), + undefined, + undefined, + undefined, + ); + } + if (isBorderEntity(value)) return value.getDTO(); + if (isBorder(value)) return value.getDTO(); + if (isArray(value)) { + + if (value.length === 2) { + const top_and_bottom : BorderDTO | undefined = StyleEntity.prepareBorderDTO(value[TOP_AND_BOTTOM_MARGIN_INDEX]); + if (!top_and_bottom) throw new TypeError(`prepareBorderListDTO: Invalid [undefined, *] array provided`); + const right_and_left: BorderDTO | undefined = StyleEntity.prepareBorderDTO(value[LEFT_AND_RIGHT_MARGIN_INDEX]); + if (!right_and_left) throw new TypeError(`prepareBorderListDTO: Invalid [BorderDTO, undefined] array provided`); + return [ + top_and_bottom, // top + right_and_left, // right + top_and_bottom, // bottom + right_and_left, // left + ]; + } + + if (value.length === 4) { + const top : BorderDTO | undefined = StyleEntity.prepareBorderDTO( value[0] ); + if (!top) throw new TypeError(`prepareBorderListDTO: Invalid [undefined, *, *, *] array provided`); + const right : BorderDTO | undefined = StyleEntity.prepareBorderDTO( value[1] ); + if (!right) throw new TypeError(`prepareBorderListDTO: Invalid [BorderDTO, undefined, *, *] array provided`); + const bottom : BorderDTO | undefined = StyleEntity.prepareBorderDTO( value[2] ); + if (!bottom) throw new TypeError(`prepareBorderListDTO: Invalid [BorderDTO, BorderDTO, undefined, *] array provided`); + const left : BorderDTO | undefined = StyleEntity.prepareBorderDTO( value[3] ); + if (!left) throw new TypeError(`prepareBorderListDTO: Invalid [BorderDTO, BorderDTO, BorderDTO, undefined] array provided`); + return [ + top, + right, + bottom, + left, + ]; + } + + // Runtime assert, should not happen. + // @ts-ignore + throw new TypeError(`prepareBorderListDTO: Incorrect array length: ${value.length}`); + + } + return value; + } + + public static prepareSizeListCssStyles ( + key : string, + value : SizeDTO | [SizeDTO, SizeDTO, SizeDTO, SizeDTO] | undefined + ) : ReadonlyJsonObject { + + if (isSizeDTO(value)) { + return { + [key]: SizeEntity.createFromDTO(value).getCssStyles() + }; + } + + if (isArray(value)) { + return { + [key]: map( + value, + (item: SizeDTO) : string => SizeEntity.createFromDTO(item).getCssStyles() + ).join(' ') + }; + } + + return {}; + + } + + public static prepareBorderListCssStyles ( + value : BorderDTO | [BorderDTO, BorderDTO, BorderDTO, BorderDTO] | undefined + ) : ReadonlyJsonObject { + + if (isBorderDTO(value)) { + return { + border: BorderEntity.createFromDTO(value).getCssStyles() + }; + } + + if (isArray(value)) { + return { + borderStyle: map( + value, + (item: BorderDTO) : string => (BorderEntity.createFromDTO(item).getStyle() ?? BorderStyle.NONE), + ).join(' '), + borderWidth: map( + value, + (item: BorderDTO) : string => (BorderEntity.createFromDTO(item).getWidth() ?? SizeEntity.createZero()).getCssStyles(), + ).join(' '), + borderColor: map( + value, + (item: BorderDTO) : string => (BorderEntity.createFromDTO(item).getColor() ?? ColorEntity.createTransparent()).getCssStyles(), + ).join(' '), + }; + } + + return {}; + + } + + /** + * + * @param style + */ + public static getCssStyles ( + style: Style, + ) : ReadonlyJsonObject { + return style.getCssStyles(); + } + + public static merge ( + ...values: readonly (StyleDTO | Style | StyleEntity)[] + ) : StyleEntity { + return StyleEntity.createFromDTO( + reduce( + values, + ( + prev: StyleDTO, + item: StyleDTO | Style | StyleEntity, + ) : StyleDTO => { + const dto : StyleDTO = this.toDTO(item); + return { + ...prev, + ...dto, + }; + }, + createStyleDTO( + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + ), + ) + ); + } + + public static toDTO ( + value: StyleDTO | Style | StyleEntity, + ) : StyleDTO { + if (isStyleEntity(value)) { + return value.getDTO(); + } else if (isStyle(value)) { + return value.getDTO(); + } else { + return value; + } + } + + + public getCssStyles () : ReadonlyJsonObject { + + const textColor = this.getTextColor(); + const textAlign = this.getTextAlign(); + const boxSizing = this.getBoxSizing(); + const background = this.getBackground(); + const width = this.getWidth(); + const height = this.getHeight(); + const minWidth = this.getMinWidth(); + const minHeight = this.getMinHeight(); + const maxWidth = this.getMaxWidth(); + const maxHeight = this.getMaxHeight(); + const margin = this.getMargin(); + const padding = this.getPadding(); + const border = this.getBorder(); + const font = this.getFont(); + const textDecoration = this.getTextDecoration(); + + return { + ...(textColor ? { color: textColor.getCssStyles() } : {}), + ...(textAlign ? { textAlign: textAlign } : {}), + ...(boxSizing ? { boxSizing: boxSizing } : {}), + ...(background ? background.getCssStyles() : {}), + ...(width ? { width: width.getCssStyles() } : {}), + ...(height ? { height: height.getCssStyles() } : {}), + ...(minWidth ? { minWidth: minWidth.getCssStyles() } : {}), + ...(minHeight ? { minHeight: minHeight.getCssStyles() } : {}), + ...(maxWidth ? { maxWidth: maxWidth.getCssStyles() } : {}), + ...(maxHeight ? { maxHeight: maxHeight.getCssStyles() } : {}), + ...(margin? { margin: margin.getCssStyles() } : {}), + ...(padding ? { padding : padding.getCssStyles() } : {}), + ...(border ? border.getCssStyles() : {}), + ...(font ? font.getCssStyles() : {}), + ...(textDecoration ? textDecoration.getCssStyles() : {}), + }; + } + +} + +export function isStyleEntity (value: unknown): value is StyleEntity { + return value instanceof StyleEntity; +} diff --git a/entities/types/TextDecoration.ts b/entities/textDecoration/TextDecoration.ts similarity index 83% rename from entities/types/TextDecoration.ts rename to entities/textDecoration/TextDecoration.ts index 017573f..8139c11 100644 --- a/entities/types/TextDecoration.ts +++ b/entities/textDecoration/TextDecoration.ts @@ -3,16 +3,16 @@ import { ReadonlyJsonObject } from "../../Json"; import { isFunction } from "../../types/Function"; import { isObject } from "../../types/Object"; -import { ColorDTO } from "../../dto/ColorDTO"; -import { TextDecorationDTO } from "../../dto/TextDecorationDTO"; -import { SizeDTO } from "../../dto/SizeDTO"; -import { ColorEntity } from "../ColorEntity"; -import { SizeEntity } from "../SizeEntity"; -import { Color } from "./Color"; -import { Entity } from "./Entity"; -import { Size } from "./Size"; -import { TextDecorationLineType } from "./TextDecorationLineType"; -import { TextDecorationStyle } from "./TextDecorationStyle"; +import { ColorDTO } from "../color/ColorDTO"; +import { TextDecorationDTO } from "./TextDecorationDTO"; +import { SizeDTO } from "../size/SizeDTO"; +import { ColorEntity } from "../color/ColorEntity"; +import { SizeEntity } from "../size/SizeEntity"; +import { Color } from "../color/Color"; +import { Entity } from "../types/Entity"; +import { Size } from "../size/Size"; +import { TextDecorationLineType } from "../types/TextDecorationLineType"; +import { TextDecorationStyle } from "../types/TextDecorationStyle"; /** * Presents a font value. diff --git a/dto/TextDecorationDTO.ts b/entities/textDecoration/TextDecorationDTO.ts similarity index 90% rename from dto/TextDecorationDTO.ts rename to entities/textDecoration/TextDecorationDTO.ts index 54864e9..b4a8bab 100644 --- a/dto/TextDecorationDTO.ts +++ b/entities/textDecoration/TextDecorationDTO.ts @@ -6,37 +6,37 @@ import { explainOk, explainOr, explainProperty, -} from "../types/explain"; +} from "../../types/explain"; import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment, -} from "../types/OtherKeys"; +} from "../../types/OtherKeys"; import { explainRegularObject, isRegularObject, -} from "../types/RegularObject"; -import { isUndefined } from "../types/undefined"; +} from "../../types/RegularObject"; +import { isUndefined } from "../../types/undefined"; import { explainTextDecorationLineTypeOrUndefined, isTextDecorationLineTypeOrUndefined, TextDecorationLineType, -} from "../entities/types/TextDecorationLineType"; +} from "../types/TextDecorationLineType"; import { explainTextDecorationStyleOrUndefined, isTextDecorationStyleOrUndefined, TextDecorationStyle, -} from "../entities/types/TextDecorationStyle"; +} from "../types/TextDecorationStyle"; import { ColorDTO, explainColorDTOOrUndefined, isColorDTOOrUndefined, -} from "./ColorDTO"; +} from "../color/ColorDTO"; import { explainSizeDTOOrUndefined, isSizeDTOOrUndefined, SizeDTO, -} from "./SizeDTO"; -import { DTO } from "./types/DTO"; +} from "../size/SizeDTO"; +import { DTO } from "../types/DTO"; export interface TextDecorationDTO extends DTO { readonly lineType ?: TextDecorationLineType; diff --git a/entities/textDecoration/TextDecorationEntity.ts b/entities/textDecoration/TextDecorationEntity.ts new file mode 100644 index 0000000..628f9e3 --- /dev/null +++ b/entities/textDecoration/TextDecorationEntity.ts @@ -0,0 +1,132 @@ +// Copyright (c) 2023. Sendanor . All rights reserved. + +import { ReadonlyJsonObject } from "../../Json"; +import { + ColorDTO, +} from "../color/ColorDTO"; +import { + TextDecorationDTO, + createTextDecorationDTO, + isTextDecorationDTO, +} from "./TextDecorationDTO"; +import { SizeDTO } from "../size/SizeDTO"; +import { + ColorEntity, +} from "../color/ColorEntity"; +import { SizeEntity } from "../size/SizeEntity"; +import { EntityFactoryImpl } from "../types/EntityFactoryImpl"; +import { VariableType } from "../types/EntityProperty"; +import { EntityPropertyImpl } from "../types/EntityPropertyImpl"; +import { + isTextDecoration, + TextDecoration, +} from "./TextDecoration"; +import { + isTextDecorationLineType, + TextDecorationLineType, +} from "../types/TextDecorationLineType"; +import { TextDecorationStyle } from "../types/TextDecorationStyle"; + + +export const TextDecorationEntityFactory = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("lineType").setTypes(TextDecorationLineType, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("color").setTypes(ColorEntity, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("style").setTypes(TextDecorationStyle, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("thickness").setTypes(SizeEntity, VariableType.UNDEFINED) ) +); + +export const BaseTextDecorationEntity = TextDecorationEntityFactory.createEntityType(); + +/** + * Text decoration entity. + */ +export class TextDecorationEntity + extends BaseTextDecorationEntity +{ + + /** + * Creates a text decoration entity. + * + * @param lineType + */ + public static create ( + lineType ?: TextDecorationLineType | undefined, + ) : TextDecorationEntity { + return new TextDecorationEntity( + lineType, + undefined, + undefined, + undefined, + ); + } + + /** + * Creates a font entity from DTO. + * + * @param value + */ + public static createFromDTO ( + value : TextDecorationDTO, + ) : TextDecorationEntity { + return new TextDecorationEntity( value ); + } + + public constructor (); + + public constructor ( + dto: TextDecorationDTO + ); + + public constructor ( + lineType : TextDecorationLineType | undefined, + color : ColorDTO | undefined, + style : TextDecorationStyle | undefined, + thickness : SizeDTO | undefined, + ); + + public constructor ( + lineType ?: TextDecorationLineType | TextDecorationDTO | TextDecoration | undefined, + color ?: ColorDTO | undefined, + style ?: TextDecorationStyle | undefined, + thickness ?: SizeDTO | undefined, + ) { + if ( lineType === undefined && color === undefined && style === undefined && thickness === undefined ) { + super(); + } else if ( isTextDecorationDTO(lineType) && color === undefined && style === undefined && thickness === undefined ) { + super( lineType ); + } else if ( isTextDecoration(lineType) && color === undefined && style === undefined && thickness === undefined ) { + super( lineType.getDTO() ); + } else if ( isTextDecorationLineType(lineType) ) { + super( createTextDecorationDTO( + lineType, + color, + style, + thickness, + ) ); + } else { + throw new TypeError(`Unknown new TextDecorationEntity() signature: ${lineType}, ${color}, ${style}, ${thickness}`); + } + } + + /** + * @inheritDoc + */ + public getCssStyles (): ReadonlyJsonObject { + const lineType = this.getLineType(); + const color = this.getColorDTO(); + const style = this.getStyle(); + const thickness = this.getThicknessDTO(); + return { + ...(lineType ? { textDecorationLine: lineType } : {}), + ...(color ? { textDecorationColor: ColorEntity.createFromDTO(color).getCssStyles() } : {}), + ...(style ? { textDecorationStyle: style } : {}), + ...(thickness ? { textDecorationThickness: SizeEntity.createFromDTO( thickness ).getCssStyles() } : {}), + }; + } + +} + +export function isTextDecorationEntity (value: unknown): value is TextDecorationEntity { + return value instanceof TextDecorationEntity; +} diff --git a/dto/types/BackgroundAttachment.ts b/entities/types/BackgroundAttachment.ts similarity index 100% rename from dto/types/BackgroundAttachment.ts rename to entities/types/BackgroundAttachment.ts diff --git a/dto/types/BackgroundBlendMode.ts b/entities/types/BackgroundBlendMode.ts similarity index 100% rename from dto/types/BackgroundBlendMode.ts rename to entities/types/BackgroundBlendMode.ts diff --git a/dto/types/BackgroundClip.ts b/entities/types/BackgroundClip.ts similarity index 100% rename from dto/types/BackgroundClip.ts rename to entities/types/BackgroundClip.ts diff --git a/dto/types/BackgroundOrigin.ts b/entities/types/BackgroundOrigin.ts similarity index 100% rename from dto/types/BackgroundOrigin.ts rename to entities/types/BackgroundOrigin.ts diff --git a/dto/types/BackgroundPosition.ts b/entities/types/BackgroundPosition.ts similarity index 100% rename from dto/types/BackgroundPosition.ts rename to entities/types/BackgroundPosition.ts diff --git a/dto/types/BackgroundPositionOptions.ts b/entities/types/BackgroundPositionOptions.ts similarity index 98% rename from dto/types/BackgroundPositionOptions.ts rename to entities/types/BackgroundPositionOptions.ts index b44221e..2f34f2e 100644 --- a/dto/types/BackgroundPositionOptions.ts +++ b/entities/types/BackgroundPositionOptions.ts @@ -3,8 +3,8 @@ import { isPairArrayOf, isTetradArrayOf, isTripletArrayOf } from "../../types/Array"; import { explainNot, explainOk, explainOr } from "../../types/explain"; import { isUndefined } from "../../types/undefined"; -import { SizeEntity } from "../../entities/SizeEntity"; -import { isSizeDTO, SizeDTO } from "../SizeDTO"; +import { SizeEntity } from "../size/SizeEntity"; +import { isSizeDTO, SizeDTO } from "../size/SizeDTO"; import { BackgroundPosition, isBackgroundPosition } from "./BackgroundPosition"; export type BackgroundPositionOptions = ( diff --git a/dto/types/BackgroundRepeatType.ts b/entities/types/BackgroundRepeatType.ts similarity index 100% rename from dto/types/BackgroundRepeatType.ts rename to entities/types/BackgroundRepeatType.ts diff --git a/dto/types/BackgroundSizeOptions.ts b/entities/types/BackgroundSizeOptions.ts similarity index 94% rename from dto/types/BackgroundSizeOptions.ts rename to entities/types/BackgroundSizeOptions.ts index cc12c6e..8505c15 100644 --- a/dto/types/BackgroundSizeOptions.ts +++ b/entities/types/BackgroundSizeOptions.ts @@ -3,9 +3,9 @@ import { isPairArrayOf } from "../../types/Array"; import { explainNot, explainOk, explainOr } from "../../types/explain"; import { isUndefined } from "../../types/undefined"; -import { SizeEntity } from "../../entities/SizeEntity"; -import { isSizeDTO, SizeDTO } from "../SizeDTO"; -import { BackgroundSize, isBackgroundSize } from "./BackgroundSize"; +import { SizeEntity } from "../size/SizeEntity"; +import { isSizeDTO, SizeDTO } from "../size/SizeDTO"; +import { BackgroundSize, isBackgroundSize } from "../backgroundSize/BackgroundSize"; export type BackgroundSizeOptions = ( BackgroundSize diff --git a/entities/types/BaseEntity.ts b/entities/types/BaseEntity.ts index 9881d0c..176b398 100644 --- a/entities/types/BaseEntity.ts +++ b/entities/types/BaseEntity.ts @@ -5,7 +5,7 @@ import { isReadonlyJsonAny, ReadonlyJsonObject, } from "../../Json"; -import { DTO } from "../../dto/types/DTO"; +import { DTO } from "./DTO"; import { Entity } from "./Entity"; import { EntityType } from "./EntityType"; diff --git a/dto/types/BorderStyle.ts b/entities/types/BorderStyle.ts similarity index 100% rename from dto/types/BorderStyle.ts rename to entities/types/BorderStyle.ts diff --git a/dto/types/BoxSizing.ts b/entities/types/BoxSizing.ts similarity index 100% rename from dto/types/BoxSizing.ts rename to entities/types/BoxSizing.ts diff --git a/entities/types/ComponentType.ts b/entities/types/ComponentType.ts index 48086b2..460a17b 100644 --- a/entities/types/ComponentType.ts +++ b/entities/types/ComponentType.ts @@ -2,7 +2,7 @@ import { isFunction } from "../../types/Function"; import { isObject } from "../../types/Object"; -import { ComponentEntity } from "../ComponentEntity"; +import { ComponentEntity } from "../component/ComponentEntity"; /** * Public interface of static `ComponentEntity`. diff --git a/dto/types/DTO.ts b/entities/types/DTO.ts similarity index 100% rename from dto/types/DTO.ts rename to entities/types/DTO.ts diff --git a/dto/types/DTOWithContent.ts b/entities/types/DTOWithContent.ts similarity index 100% rename from dto/types/DTOWithContent.ts rename to entities/types/DTOWithContent.ts diff --git a/dto/types/DTOWithName.ts b/entities/types/DTOWithName.ts similarity index 100% rename from dto/types/DTOWithName.ts rename to entities/types/DTOWithName.ts diff --git a/dto/types/DTOWithOptionalExtend.ts b/entities/types/DTOWithOptionalExtend.ts similarity index 100% rename from dto/types/DTOWithOptionalExtend.ts rename to entities/types/DTOWithOptionalExtend.ts diff --git a/dto/types/DTOWithOptionalLanguage.ts b/entities/types/DTOWithOptionalLanguage.ts similarity index 100% rename from dto/types/DTOWithOptionalLanguage.ts rename to entities/types/DTOWithOptionalLanguage.ts diff --git a/dto/types/DTOWithOptionalPublicUrl.ts b/entities/types/DTOWithOptionalPublicUrl.ts similarity index 100% rename from dto/types/DTOWithOptionalPublicUrl.ts rename to entities/types/DTOWithOptionalPublicUrl.ts diff --git a/entities/types/Entity.ts b/entities/types/Entity.ts index 2aa4cc9..bc6939b 100644 --- a/entities/types/Entity.ts +++ b/entities/types/Entity.ts @@ -3,7 +3,7 @@ import { ReadonlyJsonObject } from "../../Json"; import { isFunction } from "../../types/Function"; import { isObject } from "../../types/Object"; -import { DTO } from "../../dto/types/DTO"; +import { DTO } from "./DTO"; import { EntityType } from "./EntityType"; import { JsonSerializable } from "./JsonSerializable"; diff --git a/entities/types/EntityFactory.ts b/entities/types/EntityFactory.ts index 487d5f2..a6c664f 100644 --- a/entities/types/EntityFactory.ts +++ b/entities/types/EntityFactory.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. import { ReadonlyJsonObject } from "../../Json"; -import { DTO } from "../../dto/types/DTO"; +import { DTO } from "./DTO"; import { BaseEntity } from "./BaseEntity"; import { Entity } from "./Entity"; import { @@ -9,7 +9,7 @@ import { EntityPropertyType, } from "./EntityProperty"; import { EntityType } from "./EntityType"; -import { IsDTO } from "./IsDTO"; +import { IsDTOTestFunction } from "./IsDTOTestFunction"; export type ArrayMapMethod< I = any, @@ -32,6 +32,10 @@ export interface TypeCheckFn { (value: unknown): boolean; } +export interface TypeExplainFn { + (value: unknown): string; +} + export interface PropertyTypeCheckFn { (value: ReadonlyJsonObject): boolean; } @@ -79,12 +83,13 @@ export interface EntityFactory< /** * Creates a test function for DTO object. */ - createIsDTO () : IsDTO; + createIsDTO () : IsDTOTestFunction; /** * Creates an entity constructor. */ createEntityType ( + name : string, opts : { immutable ?: boolean } ) : EntityType; diff --git a/entities/types/EntityFactoryImpl.test.ts b/entities/types/EntityFactoryImpl.test.ts index ad60665..84812b6 100644 --- a/entities/types/EntityFactoryImpl.test.ts +++ b/entities/types/EntityFactoryImpl.test.ts @@ -5,8 +5,8 @@ import { describe, } from "@jest/globals"; import "../../../testing/jest/matchers/index"; -import { DTO } from "../../dto/types/DTO"; import { BaseEntity } from "./BaseEntity"; +import { DTO } from "./DTO"; import { Entity } from "./Entity"; import { EntityFactoryImpl } from "./EntityFactoryImpl"; import { @@ -50,6 +50,87 @@ describe('EntityFactoryImpl', () => { expect( properties[0].getTypes() ).toStrictEqual(["string", "undefined"]); }); + it('can create an entity factory instance with an enum property', () => { + + enum CarType { + AUTOMATIC = "AUTOMATIC", + MANUAL = "MANUAL" + } + + const item = ( + EntityFactoryImpl + .create() + .add( "name", VariableType.STRING) + .add( "type", CarType ) + ); + const properties = item.getProperties(); + expect( properties?.length ).toBe(2); + expect( properties[0].getPropertyName() ).toBe("name"); + expect( properties[0].getTypes() ).toStrictEqual(["string"]); + expect( properties[1].getPropertyName() ).toBe("type"); + expect( properties[1].getTypes() ).toStrictEqual([ + { + "AUTOMATIC" : "AUTOMATIC", + "MANUAL": "MANUAL", + } + ]); + }); + + + it('can create an entity factory instance with an array of enums', () => { + + enum CarType { + AUTOMATIC = "AUTOMATIC", + MANUAL = "MANUAL" + } + + const item = ( + EntityFactoryImpl + .create() + .add( "name", VariableType.STRING) + .add( EntityFactoryImpl.createArrayProperty("types").setTypes(CarType) ) + ); + const properties = item.getProperties(); + expect( properties?.length ).toBe(2); + expect( properties[0].getPropertyName() ).toBe("name"); + expect( properties[0].getTypes() ).toStrictEqual(["string"]); + expect( properties[1].isArray() ).toBe(true); + expect( properties[1].getPropertyName() ).toBe("types"); + expect( properties[1].getTypes() ).toStrictEqual([ + { + "AUTOMATIC" : "AUTOMATIC", + "MANUAL": "MANUAL", + } + ]); + }); + + it('can create an entity factory instance with an optional enum property', () => { + + enum CarType { + AUTOMATIC = "AUTOMATIC", + MANUAL = "MANUAL" + } + + const item = ( + EntityFactoryImpl + .create() + .add( "name", VariableType.STRING, VariableType.UNDEFINED) + .add( "type", CarType, VariableType.UNDEFINED) + ); + const properties = item.getProperties(); + expect( properties?.length ).toBe(2); + expect( properties[0].getPropertyName() ).toBe("name"); + expect( properties[0].getTypes() ).toStrictEqual(["string", "undefined"]); + expect( properties[1].getPropertyName() ).toBe("type"); + expect( properties[1].getTypes() ).toStrictEqual([ + { + "AUTOMATIC" : "AUTOMATIC", + "MANUAL": "MANUAL", + }, + "undefined" + ]); + }); + }); describe('#createTypeCheckFn', () => { @@ -179,6 +260,294 @@ describe('EntityFactoryImpl', () => { expect( fn("hello world") ).toBe(false); }); + it('can create a test function for enum values', () => { + + enum FooOrBarType { + FOO = "foo", + BAR = "bar" + } + + const fn = EntityFactoryImpl.createTypeCheckFn( FooOrBarType ); + + expect( fn({name : 'John', age: 20}) ).toBe(false); + expect( fn({name : 'John', age: null}) ).toBe(false); + expect( fn({name : 123, age: 30}) ).toBe(false); + expect( fn({age: 30}) ).toBe(false); + expect( fn({name : 123}) ).toBe(false); + expect( fn(123) ).toBe(false); + expect( fn(123.456) ).toBe(false); + expect( fn(null) ).toBe(false); + expect( fn(undefined) ).toBe(false); + expect( fn({}) ).toBe(false); + expect( fn([]) ).toBe(false); + expect( fn(true) ).toBe(false); + expect( fn(false) ).toBe(false); + expect( fn("hello world") ).toBe(false); + + expect( fn("foo") ).toBe(true); + expect( fn("bar") ).toBe(true); + }); + + it('can create a test function for entity values', () => { + + enum GearType { + AUTOMATIC = "AUTOMATIC", + MANUAL = "MANUAL" + } + + interface CarDTO extends DTO { + readonly model: string; + readonly gear: GearType; + } + + interface Car extends Entity { + getModel() : string; + setModel(model: string) : this; + getGear() : GearType; + setGear(model: GearType) : this; + } + + const carFactory = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("model").setDefaultValue("Ford") ) + .add( EntityPropertyImpl.create("gear").setTypes(GearType).setDefaultValue(GearType.AUTOMATIC) ) + ); + + const CarEntity = carFactory.createEntityType('CarEntity'); + + const fn = EntityFactoryImpl.createTypeCheckFn( CarEntity ); + + expect( fn( CarEntity.create() ) ) .toBe(true); + + expect( fn({name : 'John', age: 20}) ).toBe(false); + expect( fn({name : 'John', age: null}) ).toBe(false); + expect( fn({name : 123, age: 30}) ).toBe(false); + expect( fn({age: 30}) ).toBe(false); + expect( fn({name : 123}) ).toBe(false); + expect( fn(123) ).toBe(false); + expect( fn(123.456) ).toBe(false); + expect( fn(null) ).toBe(false); + expect( fn(undefined) ).toBe(false); + expect( fn({}) ).toBe(false); + expect( fn([]) ).toBe(false); + expect( fn(true) ).toBe(false); + expect( fn(false) ).toBe(false); + expect( fn("hello world") ).toBe(false); + expect( fn("foo") ).toBe(false); + expect( fn("bar") ).toBe(false); + }); + + }); + + describe('#createTypeExplainFn', () => { + + it('can create an explain function for null values', () => { + const fn = EntityFactoryImpl.createTypeExplainFn(VariableType.NULL); + expect( fn({name : 'John', age: 20}) ).toBe('not null'); + expect( fn({name : 'John', age: null}) ).toBe('not null'); + expect( fn({name : 123, age: 30}) ).toBe('not null'); + expect( fn({age: 30}) ).toBe('not null'); + expect( fn({name : 123}) ).toBe('not null'); + expect( fn(123) ).toBe('not null'); + expect( fn(null) ).toBe('OK'); + expect( fn(undefined) ).toBe('not null'); + expect( fn({}) ).toBe('not null'); + expect( fn([]) ).toBe('not null'); + expect( fn(true) ).toBe('not null'); + expect( fn(false) ).toBe('not null'); + expect( fn("hello world") ).toBe('not null'); + }); + + it('can create an explain function for undefined values', () => { + const fn = EntityFactoryImpl.createTypeExplainFn(VariableType.UNDEFINED); + expect( fn({name : 'John', age: 20}) ).toBe('not undefined'); + expect( fn({name : 'John', age: null}) ).toBe('not undefined'); + expect( fn({name : 123, age: 30}) ).toBe('not undefined'); + expect( fn({age: 30}) ).toBe('not undefined'); + expect( fn({name : 123}) ).toBe('not undefined'); + expect( fn(123) ).toBe('not undefined'); + expect( fn(123.456) ).toBe('not undefined'); + expect( fn(null) ).toBe('not undefined'); + expect( fn(undefined) ).toBe('OK'); + expect( fn({}) ).toBe('not undefined'); + expect( fn([]) ).toBe('not undefined'); + expect( fn(true) ).toBe('not undefined'); + expect( fn(false) ).toBe('not undefined'); + expect( fn("hello world") ).toBe('not undefined'); + }); + + it('can create an explain function for boolean values', () => { + const fn = EntityFactoryImpl.createTypeExplainFn(VariableType.BOOLEAN); + expect( fn({name : 'John', age: 20}) ).toBe('not boolean'); + expect( fn({name : 'John', age: null}) ).toBe('not boolean'); + expect( fn({name : 123, age: 30}) ).toBe('not boolean'); + expect( fn({age: 30}) ).toBe('not boolean'); + expect( fn({name : 123}) ).toBe('not boolean'); + expect( fn(123) ).toBe('not boolean'); + expect( fn(123.456) ).toBe('not boolean'); + expect( fn(null) ).toBe('not boolean'); + expect( fn(undefined) ).toBe('not boolean'); + expect( fn({}) ).toBe('not boolean'); + expect( fn([]) ).toBe('not boolean'); + expect( fn(true) ).toBe('OK'); + expect( fn(false) ).toBe('OK'); + expect( fn("hello world") ).toBe('not boolean'); + }); + + it('can create an explain function for number values', () => { + const fn = EntityFactoryImpl.createTypeExplainFn(VariableType.NUMBER); + expect( fn({name : 'John', age: 20}) ).toBe('not number'); + expect( fn({name : 'John', age: null}) ).toBe('not number'); + expect( fn({name : 123, age: 30}) ).toBe('not number'); + expect( fn({age: 30}) ).toBe('not number'); + expect( fn({name : 123}) ).toBe('not number'); + expect( fn(123) ).toBe('OK'); + expect( fn(123.456) ).toBe('OK'); + expect( fn(null) ).toBe('not number'); + expect( fn(undefined) ).toBe('not number'); + expect( fn({}) ).toBe('not number'); + expect( fn([]) ).toBe('not number'); + expect( fn(true) ).toBe('not number'); + expect( fn(false) ).toBe('not number'); + expect( fn("hello world") ).toBe('not number'); + }); + + it('can create an explain function for integer values', () => { + const fn = EntityFactoryImpl.createTypeExplainFn(VariableType.INTEGER); + expect( fn({name : 'John', age: 20}) ).toBe('not integer'); + expect( fn({name : 'John', age: null}) ).toBe('not integer'); + expect( fn({name : 123, age: 30}) ).toBe('not integer'); + expect( fn({age: 30}) ).toBe('not integer'); + expect( fn({name : 123}) ).toBe('not integer'); + expect( fn(123) ).toBe('OK'); + expect( fn(123.456) ).toBe('not integer'); + expect( fn(null) ).toBe('not integer'); + expect( fn(undefined) ).toBe('not integer'); + expect( fn({}) ).toBe('not integer'); + expect( fn([]) ).toBe('not integer'); + expect( fn(true) ).toBe('not integer'); + expect( fn(false) ).toBe('not integer'); + expect( fn("hello world") ).toBe('not integer'); + }); + + it('can create an explain function for integer or string values', () => { + const fn = EntityFactoryImpl.createTypeExplainFn(VariableType.INTEGER, VariableType.STRING); + expect( fn({name : 'John', age: 20}) ).toBe(`not one of:\n - integer\n - string`); + expect( fn({name : 'John', age: null}) ).toBe(`not one of:\n - integer\n - string`); + expect( fn({name : 123, age: 30}) ).toBe(`not one of:\n - integer\n - string`); + expect( fn({age: 30}) ).toBe(`not one of:\n - integer\n - string`); + expect( fn({name : 123}) ).toBe(`not one of:\n - integer\n - string`); + expect( fn(123) ).toBe('OK'); + expect( fn(123.456) ).toBe(`not one of:\n - integer\n - string`); + expect( fn(null) ).toBe(`not one of:\n - integer\n - string`); + expect( fn(undefined) ).toBe(`not one of:\n - integer\n - string`); + expect( fn({}) ).toBe(`not one of:\n - integer\n - string`); + expect( fn([]) ).toBe(`not one of:\n - integer\n - string`); + expect( fn(true) ).toBe(`not one of:\n - integer\n - string`); + expect( fn(false) ).toBe(`not one of:\n - integer\n - string`); + expect( fn("hello world") ).toBe('OK'); + }); + + it('can create an explain function for integer or undefined values', () => { + const fn = EntityFactoryImpl.createTypeExplainFn(VariableType.INTEGER, VariableType.UNDEFINED); + expect( fn({name : 'John', age: 20}) ).toBe(`not one of:\n - integer\n - undefined`); + expect( fn({name : 'John', age: null}) ).toBe(`not one of:\n - integer\n - undefined`); + expect( fn({name : 123, age: 30}) ).toBe(`not one of:\n - integer\n - undefined`); + expect( fn({age: 30}) ).toBe(`not one of:\n - integer\n - undefined`); + expect( fn({name : 123}) ).toBe(`not one of:\n - integer\n - undefined`); + expect( fn(123) ).toBe('OK'); + expect( fn(123.456) ).toBe(`not one of:\n - integer\n - undefined`); + expect( fn(null) ).toBe(`not one of:\n - integer\n - undefined`); + expect( fn(undefined) ).toBe('OK'); + expect( fn({}) ).toBe(`not one of:\n - integer\n - undefined`); + expect( fn([]) ).toBe(`not one of:\n - integer\n - undefined`); + expect( fn(true) ).toBe(`not one of:\n - integer\n - undefined`); + expect( fn(false) ).toBe(`not one of:\n - integer\n - undefined`); + expect( fn("hello world") ).toBe(`not one of:\n - integer\n - undefined`); + }); + + it('can create an explain function for enum values', () => { + + enum FooOrBarType { + FOO = "foo", + BAR = "bar" + } + + const fn = EntityFactoryImpl.createTypeExplainFn( FooOrBarType ); + + expect( fn({name : 'John', age: 20}) ).toBe('not enum (foo | bar)'); + expect( fn({name : 'John', age: null}) ).toBe('not enum (foo | bar)'); + expect( fn({name : 123, age: 30}) ).toBe('not enum (foo | bar)'); + expect( fn({age: 30}) ).toBe('not enum (foo | bar)'); + expect( fn({name : 123}) ).toBe('not enum (foo | bar)'); + expect( fn(123) ).toBe('not enum (foo | bar)'); + expect( fn(123.456) ).toBe('not enum (foo | bar)'); + expect( fn(null) ).toBe('not enum (foo | bar)'); + expect( fn(undefined) ).toBe('not enum (foo | bar)'); + expect( fn({}) ).toBe('not enum (foo | bar)'); + expect( fn([]) ).toBe('not enum (foo | bar)'); + expect( fn(true) ).toBe('not enum (foo | bar)'); + expect( fn(false) ).toBe('not enum (foo | bar)'); + expect( fn("hello world") ).toBe('not enum (foo | bar)'); + + expect( fn("foo") ).toBe('OK'); + expect( fn("bar") ).toBe('OK'); + }); + + it('can create an explain function for entity values', () => { + + enum GearType { + AUTOMATIC = "AUTOMATIC", + MANUAL = "MANUAL" + } + + interface CarDTO extends DTO { + readonly model: string; + readonly gear: GearType; + } + + interface Car extends Entity { + getModel() : string; + setModel(model: string) : this; + getGear() : GearType; + setGear(model: GearType) : this; + } + + const carFactory = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("model").setDefaultValue("Ford") ) + .add( EntityPropertyImpl.create("gear").setTypes(GearType).setDefaultValue(GearType.AUTOMATIC) ) + ); + + const CarEntity = carFactory.createEntityType('CarEntity'); + + const fn = EntityFactoryImpl.createTypeExplainFn( CarEntity ); + + const car = CarEntity.create(); + const dto = car.getDTO(); + + expect( fn( car ) ) .toBe('OK'); + + expect( fn( dto ) ) .toBe('not CarEntity'); + expect( fn({name : 'John', age: 20}) ).toBe('not CarEntity'); + expect( fn({name : 'John', age: null}) ).toBe('not CarEntity'); + expect( fn({name : 123, age: 30}) ).toBe('not CarEntity'); + expect( fn({age: 30}) ).toBe('not CarEntity'); + expect( fn({name : 123}) ).toBe('not CarEntity'); + expect( fn(123) ).toBe('not CarEntity'); + expect( fn(123.456) ).toBe('not CarEntity'); + expect( fn(null) ).toBe('not CarEntity'); + expect( fn(undefined) ).toBe('not CarEntity'); + expect( fn({}) ).toBe('not CarEntity'); + expect( fn([]) ).toBe('not CarEntity'); + expect( fn(true) ).toBe('not CarEntity'); + expect( fn(false) ).toBe('not CarEntity'); + expect( fn("hello world") ).toBe('not CarEntity'); + expect( fn("foo") ).toBe('not CarEntity'); + expect( fn("bar") ).toBe('not CarEntity'); + }); + + }); describe('.createDefaultDTO', () => { @@ -343,6 +712,123 @@ describe('EntityFactoryImpl', () => { }); + describe('.createIsDTOOr', () => { + + it('can create a test function for DTOs and undefined', () => { + + const item = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("age").setTypes(VariableType.INTEGER).setDefaultValue(30) ) + .add( EntityPropertyImpl.create("name").setTypes(VariableType.STRING).setDefaultValue('Smith') ) + ); + + const fn = item.createIsDTOOr(VariableType.UNDEFINED); + + expect( fn({name : 'John', age: 20}) ).toBe(true); + expect( fn(undefined) ).toBe(true); + + expect( fn({name : 'John', age: null}) ).toBe(false); + expect( fn({name : 123, age: 30}) ).toBe(false); + expect( fn({age: 30}) ).toBe(false); + expect( fn({name : 123}) ).toBe(false); + expect( fn(123) ).toBe(false); + expect( fn(null) ).toBe(false); + expect( fn({}) ).toBe(false); + expect( fn([]) ).toBe(false); + expect( fn(true) ).toBe(false); + expect( fn(false) ).toBe(false); + expect( fn("hello world") ).toBe(false); + + }); + + it('can create a test function for DTOs, undefined, and null', () => { + + const item = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("age").setTypes(VariableType.INTEGER).setDefaultValue(30) ) + .add( EntityPropertyImpl.create("name").setTypes(VariableType.STRING).setDefaultValue('Smith') ) + ); + + const fn = item.createIsDTOOr(VariableType.UNDEFINED, VariableType.NULL); + + expect( fn({name : 'John', age: 20}) ).toBe(true); + expect( fn(undefined) ).toBe(true); + expect( fn(null) ).toBe(true); + + expect( fn({name : 'John', age: null}) ).toBe(false); + expect( fn({name : 123, age: 30}) ).toBe(false); + expect( fn({age: 30}) ).toBe(false); + expect( fn({name : 123}) ).toBe(false); + expect( fn(123) ).toBe(false); + expect( fn({}) ).toBe(false); + expect( fn([]) ).toBe(false); + expect( fn(true) ).toBe(false); + expect( fn(false) ).toBe(false); + expect( fn("hello world") ).toBe(false); + + }); + + it('can create a test function for DTOs, number, undefined, and null', () => { + + const item = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("age").setTypes(VariableType.INTEGER).setDefaultValue(30) ) + .add( EntityPropertyImpl.create("name").setTypes(VariableType.STRING).setDefaultValue('Smith') ) + ); + + const fn = item.createIsDTOOr(VariableType.NUMBER, VariableType.UNDEFINED, VariableType.NULL); + + expect( fn({name : 'John', age: 20}) ).toBe(true); + expect( fn(undefined) ).toBe(true); + expect( fn(null) ).toBe(true); + expect( fn(123) ).toBe(true); + + expect( fn({name : 'John', age: null}) ).toBe(false); + expect( fn({name : 123, age: 30}) ).toBe(false); + expect( fn({age: 30}) ).toBe(false); + expect( fn({name : 123}) ).toBe(false); + expect( fn({}) ).toBe(false); + expect( fn([]) ).toBe(false); + expect( fn(true) ).toBe(false); + expect( fn(false) ).toBe(false); + expect( fn("hello world") ).toBe(false); + + }); + + it('can create a test function for DTOs, string, number, undefined, and null', () => { + + const item = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("age").setTypes(VariableType.INTEGER).setDefaultValue(30) ) + .add( EntityPropertyImpl.create("name").setTypes(VariableType.STRING).setDefaultValue('Smith') ) + ); + + const fn = item.createIsDTOOr( + VariableType.STRING, + VariableType.NUMBER, + VariableType.UNDEFINED, + VariableType.NULL, + ); + + expect( fn({name : 'John', age: 20}) ).toBe(true); + expect( fn(undefined) ).toBe(true); + expect( fn(null) ).toBe(true); + expect( fn(123) ).toBe(true); + expect( fn("hello world") ).toBe(true); + + expect( fn({name : 'John', age: null}) ).toBe(false); + expect( fn({name : 123, age: 30}) ).toBe(false); + expect( fn({age: 30}) ).toBe(false); + expect( fn({name : 123}) ).toBe(false); + expect( fn({}) ).toBe(false); + expect( fn([]) ).toBe(false); + expect( fn(true) ).toBe(false); + expect( fn(false) ).toBe(false); + + }); + + }); + describe('.createEntityType', () => { interface MyDTO extends DTO { @@ -377,14 +863,16 @@ describe('EntityFactoryImpl', () => { describe('.getName and .getAge', () => { it('can create an entity constructor with .getName and .getAge', () => { - const MyType = factory.createEntityType(); + const MyType = factory.createEntityType('MyType'); const entity = MyType.create(); expect( entity.getName() ).toBe('Smith'); expect( entity.getAge() ).toBe(30); }); it('can create an entity constructor with readonly entities', () => { - const ReadonlyEntityType = factory.createEntityType({ + const ReadonlyEntityType = factory.createEntityType( + 'ReadonlyEntityType', + { immutable: true }); const entity = ReadonlyEntityType.create(); @@ -399,7 +887,7 @@ describe('EntityFactoryImpl', () => { describe('.setName and .setAge', () => { it('can create an entity constructor with writable entities with .setName and .setAge', () => { - const EntityType = factory.createEntityType(); + const EntityType = factory.createEntityType('EntityType'); const entity = EntityType.create(); expect( entity.getName() ).toBe('Smith'); expect( entity.getAge() ).toBe(30); @@ -413,7 +901,7 @@ describe('EntityFactoryImpl', () => { describe('.name and .age', () => { it('can create an entity constructor with writable entities with .name and .age', () => { - const EntityType = factory.createEntityType(); + const EntityType = factory.createEntityType('EntityType'); const entity = EntityType.create(); expect( entity.getName() ).toBe('Smith'); expect( entity.getAge() ).toBe(30); @@ -427,7 +915,7 @@ describe('EntityFactoryImpl', () => { describe('.getDTO', () => { it('can create an entity constructor with .getDTO', () => { - const EntityType = factory.createEntityType(); + const EntityType = factory.createEntityType('EntityType'); const entity = EntityType.create(); expect( entity.getDTO() ).toStrictEqual({name: 'Smith', age: 30}); }); @@ -437,7 +925,7 @@ describe('EntityFactoryImpl', () => { describe('.toJSON', () => { it('can create an entity constructor with .toJSON', () => { - const EntityType = factory.createEntityType(); + const EntityType = factory.createEntityType('EntityType'); const entity = EntityType.create(); expect( entity.toJSON() ).toStrictEqual({name: 'Smith', age: 30}); }); @@ -447,7 +935,7 @@ describe('EntityFactoryImpl', () => { describe('.valueOf', () => { it('can create an entity constructor with .valueOf', () => { - const EntityType = factory.createEntityType(); + const EntityType = factory.createEntityType('EntityType'); const entity = EntityType.create(); expect( entity.valueOf() ).toStrictEqual({name: 'Smith', age: 30}); }); @@ -458,7 +946,9 @@ describe('EntityFactoryImpl', () => { it('can create a test function for readonly DTOs', () => { - const ReadonlyEntityType = factory.createEntityType({ + const ReadonlyEntityType = factory.createEntityType( + 'ReadonlyEntityType', + { immutable: true }); @@ -480,7 +970,7 @@ describe('EntityFactoryImpl', () => { it('can create a test function for DTOs', () => { - const EntityType = factory.createEntityType(); + const EntityType = factory.createEntityType('EntityType'); expect( EntityType.isDTO({name : 'John', age: 30}) ).toBe(true); expect( EntityType.isDTO({name : 'John', age: null}) ).toBe(false); @@ -505,7 +995,9 @@ describe('EntityFactoryImpl', () => { it('can create a test function for readonly entities', () => { - const ReadonlyEntityType = factory.createEntityType({ + const ReadonlyEntityType = factory.createEntityType( + 'ReadonlyEntityType', + { immutable: true }); const entity = ReadonlyEntityType.create(); @@ -529,7 +1021,7 @@ describe('EntityFactoryImpl', () => { it('can create a test function for entities', () => { - const EntityType = factory.createEntityType(); + const EntityType = factory.createEntityType('EntityType'); const entity = EntityType.create(); expect( EntityType.isEntity(entity) ).toBe(true); @@ -554,7 +1046,7 @@ describe('EntityFactoryImpl', () => { describe('#createFromDTO', () => { it('can create an entity from DTO', () => { - const EntityType = factory.createEntityType(); + const EntityType = factory.createEntityType('EntityType'); const entity = EntityType.createFromDTO({name:'Jack', age:38}); expect( entity.getName() ).toBe('Jack'); expect( entity.getAge() ).toBe(38); @@ -565,7 +1057,7 @@ describe('EntityFactoryImpl', () => { describe('#getProperties', () => { it('can get entity properties', () => { - const EntityType = factory.createEntityType(); + const EntityType = factory.createEntityType('EntityType'); const entity = EntityType.getProperties(); expect( entity.length ).toBe(2); expect( entity[0].getPropertyName()).toBe('age'); @@ -579,13 +1071,21 @@ describe('EntityFactoryImpl', () => { describe('with inner entities', () => { + enum GearType { + AUTOMATIC = "AUTOMATIC", + MANUAL = "MANUAL" + } + interface CarDTO extends DTO { readonly model: string; + readonly gear: GearType; } interface Car extends Entity { getModel() : string; setModel(model: string) : this; + getGear() : GearType; + setGear(model: GearType) : this; } interface DriverDTO extends DTO { @@ -611,8 +1111,9 @@ describe('EntityFactoryImpl', () => { carFactory = ( EntityFactoryImpl.create() .add( EntityPropertyImpl.create("model").setDefaultValue("Ford") ) + .add( EntityPropertyImpl.create("gear").setTypes(GearType).setDefaultValue(GearType.MANUAL) ) ); - CarType = carFactory.createEntityType(); + CarType = carFactory.createEntityType('CarType'); driverFactory = ( EntityFactoryImpl.create() @@ -620,7 +1121,7 @@ describe('EntityFactoryImpl', () => { .add( EntityPropertyImpl.create("name").setDefaultValue('Smith') ) .add( EntityPropertyImpl.create("car").setTypes(CarType) ) ); - DriverType = driverFactory.createEntityType(); + DriverType = driverFactory.createEntityType('DriverType'); }); @@ -630,7 +1131,7 @@ describe('EntityFactoryImpl', () => { expect( driverFactory.createDefaultDTO() ).toStrictEqual({ name : 'Smith', age: 30, - car: {model: "Ford"} + car: {model: "Ford", gear: "MANUAL"} }); }); @@ -640,24 +1141,27 @@ describe('EntityFactoryImpl', () => { it('can create a entity with DTO getters for an inner entity property .getCar()', () => { const driver : Driver = DriverType.create(); - expect( driver.getCar().getDTO() ).toStrictEqual({model: "Ford"}); + expect( driver.getCar().getDTO() ).toStrictEqual({model: "Ford", gear: "MANUAL"}); }); it('can create a entity with DTO getters for an inner entity property .getCarDTO()', () => { const driver : Driver = DriverType.create(); - expect( driver.getCarDTO() ).toStrictEqual({model: "Ford"}); + expect( driver.getCarDTO() ).toStrictEqual({model: "Ford", gear: "MANUAL"}); }); it('can create a entity with DTO getters for an inner entity property .setCar()', () => { const driver : Driver = DriverType.create(); expect( driver.setCar( CarType.create().setModel('Tesla') ) ).toBe(driver); - expect( driver.getCar().getDTO() ).toStrictEqual({model: "Tesla"}); + expect( driver.getCar().getDTO() ).toStrictEqual({model: "Tesla", gear: "MANUAL"}); }); it('can create a entity with DTO getters for an inner entity property .setCarDTO()', () => { const driver : Driver = DriverType.create(); expect( driver.setCar( CarType.create().setModel('Tesla') ) ).toBe(driver); - expect( driver.getCarDTO() ).toStrictEqual({model: "Tesla"}); + expect( driver.getCarDTO() ).toStrictEqual({ + model: "Tesla", + gear: "MANUAL", + }); }); it('can create an type which can be used as a base class', () => { @@ -678,7 +1182,10 @@ describe('EntityFactoryImpl', () => { expect( driver.getFoo() ).toBe('hello world'); expect( driver.setCar( CarType.create().setModel('Tesla') ) ).toBe(driver); - expect( driver.getCarDTO() ).toStrictEqual({model: "Tesla"}); + expect( driver.getCarDTO() ).toStrictEqual({ + model: "Tesla", + gear: "MANUAL", + }); }); }); @@ -728,7 +1235,7 @@ describe('EntityFactoryImpl', () => { EntityFactoryImpl.create() .add( EntityPropertyImpl.create("model").setDefaultValue("Ford") ) ); - CarType = carFactory.createEntityType(); + CarType = carFactory.createEntityType('CarType'); driverFactory = ( EntityFactoryImpl.create() @@ -737,7 +1244,7 @@ describe('EntityFactoryImpl', () => { .add( EntityPropertyImpl.createArray("cars").setTypes(CarType) ) .add( EntityPropertyImpl.createOptionalArray("lendCars").setTypes(CarType) ) ); - DriverType = driverFactory.createEntityType(); + DriverType = driverFactory.createEntityType('DriverType'); }); @@ -884,7 +1391,7 @@ describe('EntityFactoryImpl', () => { EntityFactoryImpl.create() .add( EntityPropertyImpl.create("model").setDefaultValue("Ford") ) ); - CarEntity = carFactory.createEntityType(); + CarEntity = carFactory.createEntityType('CarEntity'); }); describe('#createPropertyGetter', () => { diff --git a/entities/types/EntityFactoryImpl.ts b/entities/types/EntityFactoryImpl.ts index 6f5915d..5d01c6d 100644 --- a/entities/types/EntityFactoryImpl.ts +++ b/entities/types/EntityFactoryImpl.ts @@ -1,5 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. +import { EnumUtils } from "../../EnumUtils"; import { filter } from "../../functions/filter"; import { forEach } from "../../functions/forEach"; import { has } from "../../functions/has"; @@ -10,17 +11,43 @@ import { ReadonlyJsonObject, } from "../../Json"; import { isArray } from "../../types/Array"; -import { isBoolean } from "../../types/Boolean"; -import { isNull } from "../../types/Null"; +import { + isBoolean, +} from "../../types/Boolean"; +import { + EnumType, + isEnum, + isEnumType, +} from "../../types/Enum"; +import { + explain, + explainNot, + explainOk, + explainProperty, +} from "../../types/explain"; +import { + isNull, +} from "../../types/Null"; import { isInteger, isNumber, } from "../../types/Number"; -import { hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; -import { isRegularObject } from "../../types/RegularObject"; -import { isString } from "../../types/String"; -import { isUndefined } from "../../types/undefined"; -import { DTO } from "../../dto/types/DTO"; +import { + explainNoOtherKeysInDevelopment, + hasNoOtherKeysInDevelopment, +} from "../../types/OtherKeys"; +import { + explainRegularObject, + isRegularObject, +} from "../../types/RegularObject"; +import { + isString, + isStringOrNumber, +} from "../../types/String"; +import { + isUndefined, +} from "../../types/undefined"; +import { DTO } from "./DTO"; import { BaseEntity } from "./BaseEntity"; import { Entity, @@ -37,6 +64,7 @@ import { PropertyTypeCheckFn, SetterMethod, TypeCheckFn, + TypeExplainFn, } from "./EntityFactory"; import { EntityProperty, @@ -45,7 +73,11 @@ import { VariableType, } from "./EntityProperty"; import { EntityPropertyImpl } from "./EntityPropertyImpl"; -import { IsDTO } from "./IsDTO"; +import { + IsDTOExplainFunction, + IsDTOTestFunction, + IsDTOOrTestFunction, +} from "./IsDTOTestFunction"; export interface PropertyGetterOptions { readonly entityAsDTO ?: boolean; @@ -138,6 +170,9 @@ export class EntityFactoryImpl< if (isEntityType(item)) { return (value: unknown) : boolean => prev(value) || item.isEntity(value); } + if (isEnumType(item)) { + return (value: unknown) : boolean => prev(value) || isEnum(item, value); + } switch (item) { case VariableType.BOOLEAN: return (value: unknown) : boolean => prev(value) || isBoolean(value); case VariableType.STRING: return (value: unknown) : boolean => prev(value) || isString(value); @@ -153,6 +188,65 @@ export class EntityFactoryImpl< } + //////////////////////////////////////////////////////////////////////////// + /////////////////////////// #createTypeExplainFn ///////////////////////// + //////////////////////////////////////////////////////////////////////////// + + + /** + * @inheritDoc + * @param types + * @fixme This creates a new isType function which could be reused from cache + */ + public static createTypeExplainFn ( + ...types: readonly EntityPropertyType[] + ) : TypeExplainFn { + + if (!types.length) throw new TypeError(`createTypeExplainFn: There must be at least one type`); + + const isType = this.createTypeCheckFn(...types); + + type Fn = () => string; + + const explainFunctions : Fn[] = map( + types, + (item: EntityPropertyType) : Fn => { + if (isEntityType(item)) { + const typeName = item.getEntityName(); + return () : string => typeName; + } + if (isEnumType(item)) { + const isType = (value: unknown) : boolean => isEnum(item, value); + return () : string => `enum (${EnumUtils.getValues(item).join(' | ')})`; + } + switch (item) { + case VariableType.BOOLEAN: return () : string => 'boolean'; + case VariableType.STRING: return () : string => 'string'; + case VariableType.INTEGER: return () : string => 'integer'; + case VariableType.NUMBER: return () : string => 'number'; + case VariableType.NULL: return () : string => 'null'; + case VariableType.UNDEFINED: return () : string => 'undefined'; + default: throw new TypeError(`createTypeExplainFn: Unknown variable type: ${item}`); + } + }, + ); + + const explainNotOneOf : string = explainFunctions.length >= 2 ? explainNot( + `one of:\n${ + map( + explainFunctions, + (item: Fn) : string => ` - ${item()}` + ).join('\n') + }` + ) : explainNot(explainFunctions[0]()); + + return (value : unknown) : string => { + return isType(value) ? explainOk() : explainNotOneOf; + }; + + } + + //////////////////////////////////////////////////////////////////////////// /////////////////////////// #createPropertyGetter ///////////////////////// //////////////////////////////////////////////////////////////////////////// @@ -186,6 +280,11 @@ export class EntityFactoryImpl< propertyName, type, ); + } else if (isEnumType(type, isStringOrNumber)) { + fn = this.createEnumPropertyGetter( + propertyName, + type, + ); } else { fn = this.createScalarPropertyGetter( propertyName, @@ -288,6 +387,32 @@ export class EntityFactoryImpl< } + //////////////////////////////////////////////////////////////////////////// + ////////////////////// #createScalarPropertyGetter //////////////////////// + //////////////////////////////////////////////////////////////////////////// + + + /** + * Implementation. + * + * @param propertyName + * @param type + */ + public static createEnumPropertyGetter< + D extends DTO, + T extends BaseEntity, + > ( + propertyName : string, + type: EnumType, + ): GetterMethod { + return function enumGetterMethod ( + this: T, + ) : any { + return this._getPropertyValue(propertyName); + }; + } + + //////////////////////////////////////////////////////////////////////////// ////////////////////// #createEntityPropertyGetter //////////////////////// //////////////////////////////////////////////////////////////////////////// @@ -327,7 +452,7 @@ export class EntityFactoryImpl< * @param opts */ public static createArrayItemGetter ( - Type: EntityType | VariableType, + Type: EntityType | EnumType | VariableType, opts ?: PropertyGetterOptions | undefined, ): ArrayMapMethod { const entityAsDTO = !!opts?.entityAsDTO; @@ -529,8 +654,9 @@ export class EntityFactoryImpl< /** * @inheritDoc + * @fixme Cache the value and use it so that multiple calls do not generate new ones unless state changes */ - public createIsDTO () : IsDTO { + public createIsDTO () : IsDTOTestFunction { const properties : readonly EntityProperty[] = this.getProperties(); @@ -558,6 +684,66 @@ export class EntityFactoryImpl< }; } + /** + * @inheritDoc + * @fixme Cache the value and use it so that multiple calls do not generate new ones unless state changes + */ + public createExplainDTO () : IsDTOExplainFunction { + + const properties : readonly EntityProperty[] = this.getProperties(); + + const propertyNames : readonly string[] = map( + properties, + (item : EntityProperty) : string => item.getPropertyName() + ); + + const checkProperties = reduce( + properties, + (prev: PropertyTypeCheckFn, item: EntityProperty): PropertyTypeCheckFn => { + const propertyName = item.getPropertyName(); + const isType = EntityFactoryImpl.createTypeCheckFn(...item.getTypes()); + return (value: ReadonlyJsonObject) : boolean => prev(value) && isType(value[propertyName]); + }, + (): boolean => true, + ); + + const explainProperties = map( + properties, + (item: EntityProperty): IsDTOExplainFunction => { + const propertyName = item.getPropertyName(); + const explainFunction = EntityFactoryImpl.createTypeExplainFn(...item.getTypes()); + return (value : unknown) : string => { + return explainProperty(propertyName, explainFunction((value as any)[propertyName])) + }; + } + ) + + return (value : unknown) : string => { + return explain( + [ + explainRegularObject(value), + explainNoOtherKeysInDevelopment(value, propertyNames), + ...map( + explainProperties, + (item) => item(value) + ), + ] + ); + }; + } + + /** + * @inheritDoc + * @fixme Cache the value and use it so that multiple calls do not generate new ones unless state changes + */ + public createIsDTOOr (...types : EntityPropertyType[]) : IsDTOOrTestFunction { + const isDTO = this.createIsDTO(); + const anotherFn = EntityFactoryImpl.createTypeCheckFn( + ...types, + ) as unknown as IsDTOOrTestFunction; + return (value: unknown) : value is D | T => isDTO( value ) || anotherFn( value ); + } + /** * @inheritDoc */ @@ -602,6 +788,7 @@ export class EntityFactoryImpl< * @inheritDoc */ public createEntityType ( + name : string, opts : { immutable ?: boolean } = {} ) : EntityType { @@ -633,10 +820,20 @@ export class EntityFactoryImpl< return map(properties, (item: EntityProperty) : EntityProperty => item); } + public static getEntityName () : string { + return name; + } + public static isEntity (value: unknown) : value is FinalType { return value instanceof FinalType; } + public static explainEntity (value: unknown) : string { + return value instanceof FinalType ? explainOk() : ( + explainNot('EntityType') + ); + } + public static isDTO (value: unknown) : value is D { return isDTO(value); } diff --git a/entities/types/EntityProperty.ts b/entities/types/EntityProperty.ts index 19ba1fa..764667d 100644 --- a/entities/types/EntityProperty.ts +++ b/entities/types/EntityProperty.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { DTO } from "../../dto/types/DTO"; +import { Enum } from "../../types/Enum"; import { Entity } from "./Entity"; import { EntityType } from "./EntityType"; @@ -16,12 +16,12 @@ export enum VariableType { /** * */ -export type EntityPropertyType = EntityType> | VariableType; +export type EntityPropertyType = EntityType> | Enum | VariableType; /** * */ -export type EntityPropertyValue = Entity | string | number | boolean | null | undefined | EntityPropertyValue[]; +export type EntityPropertyValue = Entity | string | number | boolean | null | undefined | Enum | EntityPropertyValue[]; /** * Presents a property of an entity or entity DTO with a name and type(s). @@ -33,6 +33,12 @@ export interface EntityProperty { */ getPropertyName () : string; + /** + * Returns a list of method aliases. These are in the format of properties, + * e.g. `"unitType"` creates `getUnitType()` alias for `getUnit()`. + */ + getMethodAliases () : readonly string[]; + /** * Accepted type(s) of the property. */ diff --git a/entities/types/EntityPropertyImpl.test.ts b/entities/types/EntityPropertyImpl.test.ts index 43cd3be..3d81fd3 100644 --- a/entities/types/EntityPropertyImpl.test.ts +++ b/entities/types/EntityPropertyImpl.test.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. import { beforeEach } from "@jest/globals"; -import { DTO } from "../../dto/types/DTO"; +import { DTO } from "./DTO"; import { Entity } from "./Entity"; import { EntityFactoryImpl } from "./EntityFactoryImpl"; import { VariableType } from "./EntityProperty"; diff --git a/entities/types/EntityPropertyImpl.ts b/entities/types/EntityPropertyImpl.ts index c0e24ed..a809244 100644 --- a/entities/types/EntityPropertyImpl.ts +++ b/entities/types/EntityPropertyImpl.ts @@ -17,7 +17,7 @@ import { } from "../../types/Number"; import { isString } from "../../types/String"; import { isUndefined } from "../../types/undefined"; -import { DTO } from "../../dto/types/DTO"; +import { DTO } from "./DTO"; import { isEntity, } from "./Entity"; @@ -47,12 +47,15 @@ export class EntityPropertyImpl * Create an entity property. * * @param name The name of the property + * @param aliases The method aliases of the property */ public static create ( - name : string + name : string, + ...aliases : readonly string[] ) : EntityPropertyImpl { return new EntityPropertyImpl( name, + aliases, [], undefined, false, @@ -70,12 +73,15 @@ export class EntityPropertyImpl * Create an array property. * * @param name The name of the property + * @param aliases The method aliases of the property */ public static createArray ( name : string, + ...aliases : readonly string[] ) : EntityPropertyImpl { return new EntityPropertyImpl( name, + aliases, [], [], true, @@ -88,12 +94,15 @@ export class EntityPropertyImpl * Create an array property which may be undefined. * * @param name The name of the property + * @param aliases The method aliases of the property */ public static createOptionalArray ( name : string, + ...aliases : readonly string[] ) : EntityPropertyImpl { return new EntityPropertyImpl( name, + aliases, [], undefined, true, @@ -161,6 +170,16 @@ export class EntityPropertyImpl */ private readonly _name : string; + /** + * Alias names of methods. + * + * These aliases are only used for methods. It will not create support for + * alias DTO properties. + * + * @private + */ + private readonly _methodAliases : readonly string[]; + /** * Type(s) of the property. * @@ -206,12 +225,14 @@ export class EntityPropertyImpl */ protected constructor ( name : string, + methodAliases : readonly string[], types : readonly EntityPropertyType[], defaultValue : EntityPropertyValue, isArray : boolean, isOptional : boolean, ) { this._name = name; + this._methodAliases = methodAliases; this._types = types; this._defaultValue = defaultValue; this._isArray = isArray; @@ -232,6 +253,13 @@ export class EntityPropertyImpl return this._name; } + /** + * @inheritDoc + */ + public getMethodAliases () : readonly string[] { + return this._methodAliases; + } + /** * @inheritDoc */ @@ -336,6 +364,10 @@ export class EntityPropertyImpl const getterName : string = `get${ upperFirst(propertyName) }`; return [ getterName, + ...(map( + this.getMethodAliases(), + (alias) => `get${ upperFirst( alias ) }` + )), ]; } @@ -344,13 +376,18 @@ export class EntityPropertyImpl */ public getSetterNames () : readonly string[] { const propertyName : string = this.getPropertyName(); - const setterName : string = `set${ upperFirst(propertyName) }`; - const setterName2 : string = `${ propertyName }`; return [ - setterName, - setterName2, + `set${ upperFirst(propertyName) }`, + ...(map( + this.getMethodAliases(), + (alias) => `set${ upperFirst( alias ) }` + )), + `${ propertyName }`, + ...(map( + this.getMethodAliases(), + (alias) => `${ alias }` + )), ]; } - } diff --git a/entities/types/EntityType.ts b/entities/types/EntityType.ts index 3453a7d..247efed 100644 --- a/entities/types/EntityType.ts +++ b/entities/types/EntityType.ts @@ -2,7 +2,7 @@ import { isFunction } from "../../types/Function"; import { isObject } from "../../types/Object"; -import { DTO } from "../../dto/types/DTO"; +import { DTO } from "./DTO"; import { Entity } from "./Entity"; import { EntityProperty } from "./EntityProperty"; @@ -20,6 +20,11 @@ export interface EntityType< */ new (dto ?: D | undefined) : T; + /** + * The name of the entity. + */ + getEntityName() : string; + /** * Creates an entity with default values. */ @@ -46,6 +51,13 @@ export interface EntityType< */ isEntity (value: unknown): value is T; + /** + * Returns a string explaining why the value is not a type of this entity, or otherwise that it is. + * + * @param value + */ + explainEntity (value: unknown): string; + /** * Returns `true` if value is type of the entity DTO object. * diff --git a/dto/types/ExtendableDTO.ts b/entities/types/ExtendableDTO.ts similarity index 100% rename from dto/types/ExtendableDTO.ts rename to entities/types/ExtendableDTO.ts diff --git a/entities/types/ExtendableEntity.ts b/entities/types/ExtendableEntity.ts index c797683..afba0f7 100644 --- a/entities/types/ExtendableEntity.ts +++ b/entities/types/ExtendableEntity.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { DTO } from "../../dto/types/DTO"; +import { DTO } from "./DTO"; import { Entity } from "./Entity"; import { Extendable } from "./Extendable"; diff --git a/dto/types/HyperComponent.ts b/entities/types/HyperComponent.ts similarity index 100% rename from dto/types/HyperComponent.ts rename to entities/types/HyperComponent.ts diff --git a/entities/types/IsDTO.ts b/entities/types/IsDTO.ts deleted file mode 100644 index b50f383..0000000 --- a/entities/types/IsDTO.ts +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2023. Sendanor . All rights reserved. - -import { DTO } from "../../dto/types/DTO"; - -/** - * Type for DTO test function. - * @returns `true` if value is type of T. - */ -export interface IsDTO { - (value : unknown) : value is T; -} diff --git a/entities/types/IsDTOTestFunction.ts b/entities/types/IsDTOTestFunction.ts new file mode 100644 index 0000000..3fcfa03 --- /dev/null +++ b/entities/types/IsDTOTestFunction.ts @@ -0,0 +1,29 @@ +// Copyright (c) 2023. Sendanor . All rights reserved. + +import { DTO } from "./DTO"; + +/** + * Type for DTO test function. + * @returns `true` if value is type of T. + */ +export interface IsDTOTestFunction { + (value : unknown) : value is T; +} + +/** + * Type for DTO test function which supports other types. + * + * @returns `true` if value is type of D or T. + */ +export interface IsDTOOrTestFunction { + (value : unknown) : value is D | T; +} + +/** + * A function which explains results of DTO test functions. + * + * @returns Human readable explanation why a type check wasn't accepted or if it was. + */ +export interface IsDTOExplainFunction { + (value : unknown) : string; +} diff --git a/dto/types/TextAlign.ts b/entities/types/TextAlign.ts similarity index 100% rename from dto/types/TextAlign.ts rename to entities/types/TextAlign.ts diff --git a/entities/types/View.ts b/entities/view/View.ts similarity index 86% rename from entities/types/View.ts rename to entities/view/View.ts index 4c91215..fb38752 100644 --- a/entities/types/View.ts +++ b/entities/view/View.ts @@ -1,13 +1,13 @@ // Copyright (c) 2023. Sendanor . All rights reserved. import { ReadonlyJsonObject } from "../../Json"; -import { ComponentDTO } from "../../dto/ComponentDTO"; -import { StyleDTO } from "../../dto/StyleDTO"; -import { ViewDTO } from "../../dto/ViewDTO"; -import { ComponentEntity } from "../ComponentEntity"; -import { StyleEntity } from "../StyleEntity"; -import { ExtendableEntity } from "./ExtendableEntity"; -import { Style } from "./Style"; +import { ComponentDTO } from "../component/ComponentDTO"; +import { StyleDTO } from "../style/StyleDTO"; +import { ViewDTO } from "./ViewDTO"; +import { ComponentEntity } from "../component/ComponentEntity"; +import { StyleEntity } from "../style/StyleEntity"; +import { ExtendableEntity } from "../types/ExtendableEntity"; +import { Style } from "../style/Style"; /** * Interface for Hyper views. diff --git a/dto/ViewDTO.ts b/entities/view/ViewDTO.ts similarity index 86% rename from dto/ViewDTO.ts rename to entities/view/ViewDTO.ts index 151aa8a..131808a 100644 --- a/dto/ViewDTO.ts +++ b/entities/view/ViewDTO.ts @@ -1,18 +1,18 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { explainReadonlyJsonObjectOrUndefined, isReadonlyJsonObjectOrUndefined, ReadonlyJsonObject } from "../Json"; -import { explain, explainNot, explainOk, explainOr, explainProperty } from "../types/explain"; -import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../types/OtherKeys"; -import { explainRegularObject, isRegularObject } from "../types/RegularObject"; -import { explainString, explainStringOrUndefined, isString, isStringOrUndefined } from "../types/String"; -import { isUndefined } from "../types/undefined"; -import { DTO } from "./types/DTO"; -import { ExtendableDTO } from "./types/ExtendableDTO"; -import { explainComponentContentOrUndefined, ComponentContent, isComponentContentOrUndefined } from "./ComponentDTO"; -import { explainSeoDTOOrUndefined, SeoDTO, isSeoDTOOrUndefined } from "./SeoDTO"; -import { explainStyleDTOOrUndefined, StyleDTO, isStyleDTOOrUndefined } from "./StyleDTO"; -import { DTOWithOptionalExtend } from "./types/DTOWithOptionalExtend"; -import { DTOWithName } from "./types/DTOWithName"; +import { explainReadonlyJsonObjectOrUndefined, isReadonlyJsonObjectOrUndefined, ReadonlyJsonObject } from "../../Json"; +import { explain, explainNot, explainOk, explainOr, explainProperty } from "../../types/explain"; +import { explainNoOtherKeysInDevelopment, hasNoOtherKeysInDevelopment } from "../../types/OtherKeys"; +import { explainRegularObject, isRegularObject } from "../../types/RegularObject"; +import { explainString, explainStringOrUndefined, isString, isStringOrUndefined } from "../../types/String"; +import { isUndefined } from "../../types/undefined"; +import { DTO } from "../types/DTO"; +import { ExtendableDTO } from "../types/ExtendableDTO"; +import { explainComponentContentOrUndefined, ComponentContent, isComponentContentOrUndefined } from "../component/ComponentDTO"; +import { explainSeoDTOOrUndefined, SeoDTO, isSeoDTOOrUndefined } from "../seo/SeoDTO"; +import { explainStyleDTOOrUndefined, StyleDTO, isStyleDTOOrUndefined } from "../style/StyleDTO"; +import { DTOWithOptionalExtend } from "../types/DTOWithOptionalExtend"; +import { DTOWithName } from "../types/DTOWithName"; export interface ViewDTO extends DTO, diff --git a/entities/ViewEntity.ts b/entities/view/ViewEntity.ts similarity index 77% rename from entities/ViewEntity.ts rename to entities/view/ViewEntity.ts index 9f81d4b..ef3a9b6 100644 --- a/entities/ViewEntity.ts +++ b/entities/view/ViewEntity.ts @@ -1,21 +1,37 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { map } from "../functions/map"; -import { ReadonlyJsonObject } from "../Json"; -import { isArray } from "../types/Array"; -import { ComponentContent, ComponentDTO } from "../dto/ComponentDTO"; -import { SeoDTO } from "../dto/SeoDTO"; -import { StyleDTO } from "../dto/StyleDTO"; -import { createViewDTO, ViewDTO } from "../dto/ViewDTO"; -import { ComponentEntity, isComponentEntity } from "./ComponentEntity"; -import { isStyleEntity, StyleEntity } from "./StyleEntity"; -import { isStyle, Style } from "./types/Style"; -import { View } from "./types/View"; +import { SizeDTO } from "../size/SizeDTO"; +import { map } from "../../functions/map"; +import { ReadonlyJsonObject } from "../../Json"; +import { isArray } from "../../types/Array"; +import { ComponentContent, ComponentDTO } from "../component/ComponentDTO"; +import { SeoDTO } from "../seo/SeoDTO"; +import { StyleDTO } from "../style/StyleDTO"; +import { createViewDTO, ViewDTO } from "./ViewDTO"; +import { ComponentEntity, isComponentEntity } from "../component/ComponentEntity"; +import { isStyleEntity, StyleEntity } from "../style/StyleEntity"; +import { EntityFactoryImpl } from "../types/EntityFactoryImpl"; +import { VariableType } from "../types/EntityProperty"; +import { EntityPropertyImpl } from "../types/EntityPropertyImpl"; +import { isStyle, Style } from "../style/Style"; +import { View } from "./View"; + + +export const BaseViewEntityFactory = ( + EntityFactoryImpl.create() + .add( EntityPropertyImpl.create("name").setTypes(VariableType.STRING) ) + .add( EntityPropertyImpl.create("extend").setTypes(VariableType.STRING, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("publicUrl").setTypes(VariableType.STRING, VariableType.UNDEFINED) ) + .add( EntityPropertyImpl.create("language").setTypes(VariableType.STRING, VariableType.UNDEFINED) ) +); + +export const BaseViewEntity = BaseViewEntityFactory.createEntityType(); /** * Entity for Hyper views. */ export class ViewEntity + extends BaseViewEntity implements View { diff --git a/samples/loading/LoadingAppDefinition.ts b/samples/loading/LoadingAppDefinition.ts index 2bf4c35..be781f9 100644 --- a/samples/loading/LoadingAppDefinition.ts +++ b/samples/loading/LoadingAppDefinition.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createAppDTO, AppDTO } from "../../dto/AppDTO"; +import { createAppDTO, AppDTO } from "../../entities/app/AppDTO"; import { createAnyRoute } from "./routes/AnyRoute"; import { createLoadingRoute } from "./routes/LoadingRoute"; import { createTextComponent } from "./components/TextComponent"; diff --git a/samples/loading/components/Text.ts b/samples/loading/components/Text.ts index 6071a8f..a020546 100644 --- a/samples/loading/components/Text.ts +++ b/samples/loading/components/Text.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../../dto/ComponentDTO"; +import { createComponentDTO, ComponentDTO } from "../../../entities/component/ComponentDTO"; import { TEXT_COMPONENT_NAME } from "./TextComponent"; export type Text = ComponentDTO; diff --git a/samples/loading/components/TextComponent.ts b/samples/loading/components/TextComponent.ts index bff6ae4..29ec60b 100644 --- a/samples/loading/components/TextComponent.ts +++ b/samples/loading/components/TextComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../../dto/ComponentDTO"; -import { HyperComponent } from "../../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../../entities/types/HyperComponent"; export const TEXT_COMPONENT_NAME: string = 'TextComponent'; diff --git a/samples/loading/routes/AnyRoute.ts b/samples/loading/routes/AnyRoute.ts index 36def86..2778c23 100644 --- a/samples/loading/routes/AnyRoute.ts +++ b/samples/loading/routes/AnyRoute.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createRouteDTO, RouteDTO } from "../../../dto/RouteDTO"; +import { createRouteDTO, RouteDTO } from "../../../entities/route/RouteDTO"; export const ANY_ROUTE_NAME : string = 'AnyRoute'; diff --git a/samples/loading/routes/LoadingRoute.ts b/samples/loading/routes/LoadingRoute.ts index a14c6d9..45476bd 100644 --- a/samples/loading/routes/LoadingRoute.ts +++ b/samples/loading/routes/LoadingRoute.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createRouteDTO, RouteDTO } from "../../../dto/RouteDTO"; +import { createRouteDTO, RouteDTO } from "../../../entities/route/RouteDTO"; import { LOADING_VIEW_NAME } from "../views/LoadingView"; export type LoadingRoute = RouteDTO; diff --git a/samples/loading/views/DefaultView.ts b/samples/loading/views/DefaultView.ts index 2ad1387..231740a 100644 --- a/samples/loading/views/DefaultView.ts +++ b/samples/loading/views/DefaultView.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createViewDTO, ViewDTO } from "../../../dto/ViewDTO"; -import { StyleEntity } from "../../../entities/StyleEntity"; +import { createViewDTO, ViewDTO } from "../../../entities/view/ViewDTO"; +import { StyleEntity } from "../../../entities/style/StyleEntity"; import { DARK_BACKGROUND_COLOR, DARK_TEXT_COLOR } from "../constants/colors"; export const DEFAULT_VIEW_NAME: string = 'DefaultView'; diff --git a/samples/loading/views/LoadingView.ts b/samples/loading/views/LoadingView.ts index d15ff64..1e8ea5b 100644 --- a/samples/loading/views/LoadingView.ts +++ b/samples/loading/views/LoadingView.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createViewDTO, ViewDTO } from "../../../dto/ViewDTO"; +import { createViewDTO, ViewDTO } from "../../../entities/view/ViewDTO"; import { createText } from "../components/Text"; import { DEFAULT_VIEW_NAME } from "./DefaultView"; diff --git a/samples/order/OrderAppDefinition.ts b/samples/order/OrderAppDefinition.ts index f3d19ae..033e982 100644 --- a/samples/order/OrderAppDefinition.ts +++ b/samples/order/OrderAppDefinition.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createAppDTO, AppDTO } from "../../dto/AppDTO"; +import { createAppDTO, AppDTO } from "../../entities/app/AppDTO"; import { createAnyRoute } from "./routes/AnyRoute"; import { createLoginRoute } from "./routes/LoginRoute"; import { createTextComponent } from "./components/TextComponent"; diff --git a/samples/order/components/Text.ts b/samples/order/components/Text.ts index 6071a8f..a020546 100644 --- a/samples/order/components/Text.ts +++ b/samples/order/components/Text.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../../dto/ComponentDTO"; +import { createComponentDTO, ComponentDTO } from "../../../entities/component/ComponentDTO"; import { TEXT_COMPONENT_NAME } from "./TextComponent"; export type Text = ComponentDTO; diff --git a/samples/order/components/TextComponent.ts b/samples/order/components/TextComponent.ts index bff6ae4..29ec60b 100644 --- a/samples/order/components/TextComponent.ts +++ b/samples/order/components/TextComponent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createComponentDTO, ComponentDTO } from "../../../dto/ComponentDTO"; -import { HyperComponent } from "../../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentDTO } from "../../../entities/component/ComponentDTO"; +import { HyperComponent } from "../../../entities/types/HyperComponent"; export const TEXT_COMPONENT_NAME: string = 'TextComponent'; diff --git a/samples/order/routes/AnyRoute.ts b/samples/order/routes/AnyRoute.ts index 36def86..2778c23 100644 --- a/samples/order/routes/AnyRoute.ts +++ b/samples/order/routes/AnyRoute.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createRouteDTO, RouteDTO } from "../../../dto/RouteDTO"; +import { createRouteDTO, RouteDTO } from "../../../entities/route/RouteDTO"; export const ANY_ROUTE_NAME : string = 'AnyRoute'; diff --git a/samples/order/routes/LoginRoute.ts b/samples/order/routes/LoginRoute.ts index e165333..9319f94 100644 --- a/samples/order/routes/LoginRoute.ts +++ b/samples/order/routes/LoginRoute.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createRouteDTO, RouteDTO } from "../../../dto/RouteDTO"; +import { createRouteDTO, RouteDTO } from "../../../entities/route/RouteDTO"; import { LOGIN_VIEW_NAME } from "../views/LoginView"; export type LoginRoute = RouteDTO; diff --git a/samples/order/views/DefaultView.ts b/samples/order/views/DefaultView.ts index fb7e5c2..a2eb425 100644 --- a/samples/order/views/DefaultView.ts +++ b/samples/order/views/DefaultView.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createViewDTO, ViewDTO } from "../../../dto/ViewDTO"; -import { StyleEntity } from "../../../entities/StyleEntity"; +import { createViewDTO, ViewDTO } from "../../../entities/view/ViewDTO"; +import { StyleEntity } from "../../../entities/style/StyleEntity"; import { DARK_BACKGROUND_COLOR, DARK_TEXT_COLOR } from "../constants/colors"; export const DEFAULT_VIEW_NAME: string = 'DefaultView'; diff --git a/samples/order/views/LoginView.ts b/samples/order/views/LoginView.ts index 6493bb5..9a183c2 100644 --- a/samples/order/views/LoginView.ts +++ b/samples/order/views/LoginView.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createViewDTO, ViewDTO } from "../../../dto/ViewDTO"; +import { createViewDTO, ViewDTO } from "../../../entities/view/ViewDTO"; import { createText } from "../components/Text"; import { DEFAULT_VIEW_NAME } from "./DefaultView"; diff --git a/services/ComponentFactory.ts b/services/ComponentFactory.ts index f87f359..8c39149 100644 --- a/services/ComponentFactory.ts +++ b/services/ComponentFactory.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ComponentDTO } from "../dto/ComponentDTO"; +import { ComponentDTO } from "../entities/component/ComponentDTO"; /** * Type of Component DTO factory function. diff --git a/services/ComponentFactoryImpl.ts b/services/ComponentFactoryImpl.ts index 0a62751..817ef4c 100644 --- a/services/ComponentFactoryImpl.ts +++ b/services/ComponentFactoryImpl.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. import { has } from "../functions/has"; -import { ComponentDTO } from "../dto/ComponentDTO"; +import { ComponentDTO } from "../entities/component/ComponentDTO"; import { ComponentFactoryService } from "./ComponentFactoryService"; import { ComponentFactoryFunction, ComponentFactory } from "./ComponentFactory"; diff --git a/services/ComponentFactoryService.ts b/services/ComponentFactoryService.ts index 687fe4d..7466720 100644 --- a/services/ComponentFactoryService.ts +++ b/services/ComponentFactoryService.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. import { has } from "../functions/has"; -import { ComponentDTO } from "../dto/ComponentDTO"; +import { ComponentDTO } from "../entities/component/ComponentDTO"; import { ComponentFactoryImpl } from "./ComponentFactoryImpl"; import { ComponentFactoryFunction, ComponentFactory } from "./ComponentFactory"; diff --git a/types/Enum.ts b/types/Enum.ts index d931b32..580eb1d 100644 --- a/types/Enum.ts +++ b/types/Enum.ts @@ -1,9 +1,18 @@ // Copyright (c) 2020-2023. Heusala Group Oy . All rights reserved. -import { TestCallbackNonStandard } from "./TestCallback"; +import { + isRegularObjectOf, +} from "./RegularObject"; +import { + TestCallback, + TestCallbackNonStandard, +} from "./TestCallback"; import { EXPLAIN_OK } from "./explain"; import { join } from "../functions/join"; -import { isString } from "./String"; +import { + isString, + isStringOrNumber, +} from "./String"; import { isNumber } from "./Number"; import { indexOf } from "../functions/indexOf"; import { map } from "../functions/map"; @@ -14,17 +23,61 @@ export interface Enum { readonly [key: string]: T; } +export type EnumType = Enum; + /** - * Checks the given value is of the given enum. + * Checks the given type is of the given enum type object. * - * @template EnumType - The type of the enum. - * @param {Enum} type - The enum. + * @template EnumType - The type of the enum's key. + * @param type - The enum object. + * @param isValue - The value to explain. + * @returns True if the type is an enum type object. + */ +export function isEnumType ( + type: unknown, + isValue: TestCallback = isStringOrNumber, +): type is Enum { + return isRegularObjectOf( + type, + isString, + isValue, + ); +} + +/** + * Explain the given value with respect to the given enum. + * + * @template EnumType - The type of the enum's value. + * @param name - The name of the enum. + * @param {Enum} type - The enum type object. + * @param type - The value to explain. + * @param isValue - A function that tests if a key is of the correct type. + * @returns {string} A string explaining the value with respect to the enum. + */ +export function explainEnumType ( + name: string, + type: unknown, + isValue: TestCallback = isStringOrNumber, +): string { + if ( !isEnumType(type, isValue) ) { + return `incorrect enum object for ${name}: ${JSON.stringify(type)}`; + } else { + return EXPLAIN_OK; + } +} + + +/** + * Checks the given value is part of the given enum. + * + * @template EnumType - The type of the enum's key. + * @param {Enum} type - The enum type object. * @param {unknown} value - The value to explain. * @returns {string} A string explaining the value with respect to the enum. */ export function isEnum ( type: Enum, - value: unknown + value: unknown, ): value is T { if ( isNumber(value) || isString(value) ) { return indexOf(EnumUtils.getValues(type), value as T) >= 0; @@ -47,7 +100,7 @@ export function explainEnum ( name: string, type: Enum, isType: TestCallbackNonStandard, - value: unknown + value: unknown, ): string { if ( !isType(value) ) { return `incorrect enum value "${value}" for ${name}: Accepted values ${join(EnumUtils.getValues(type), ', ')}`; @@ -63,7 +116,7 @@ export function explainEnum ( */ export function stringifyEnum ( type : Enum, - value : T + value : T, ) : string { const enumValues = EnumUtils.getValues(type); const enumKeys = EnumUtils.getKeys(type); diff --git a/types/String.ts b/types/String.ts index 9f2cbbb..bd396c4 100644 --- a/types/String.ts +++ b/types/String.ts @@ -19,6 +19,16 @@ export function isString (value: unknown): value is string { return _isString(value); } +/** + * + * @param value + * @__PURE__ + * @nosideeffects + */ +export function explainString (value: any): string { + return isString(value) ? explainOk() : explainNot('string'); +} + /** * * @param value @@ -35,18 +45,19 @@ export function isStringOrFalse (value: unknown): value is string | false { * @__PURE__ * @nosideeffects */ -export function isNonEmptyString (value: unknown): value is string { - return _isString(value) && !!value; +export function explainStringOrFalse (value: any): string { + return isStringOrFalse(value) ? explainOk() : explainNot(explainOr(['string', 'false'])); } + /** * * @param value * @__PURE__ * @nosideeffects */ -export function explainString (value: any): string { - return isString(value) ? explainOk() : explainNot('string'); +export function isStringOrNumber (value: unknown): value is string | number { + return isString(value) || isNumber(value); } /** @@ -55,8 +66,18 @@ export function explainString (value: any): string { * @__PURE__ * @nosideeffects */ -export function explainStringOrFalse (value: any): string { - return isStringOrFalse(value) ? explainOk() : explainNot(explainOr(['string', 'false'])); +export function explainStringOrNumber (value: unknown): string { + return isStringOrNumber(value) ? explainOk() : explainNot(explainOr(['string', 'number'])); +} + +/** + * + * @param value + * @__PURE__ + * @nosideeffects + */ +export function isNonEmptyString (value: unknown): value is string { + return _isString(value) && !!value; } /** diff --git a/utils/components/mergeComponentContent.ts b/utils/components/mergeComponentContent.ts index 8fa48b5..1c42863 100644 --- a/utils/components/mergeComponentContent.ts +++ b/utils/components/mergeComponentContent.ts @@ -1,7 +1,7 @@ // Copyright (c) 2023. Sendanor . All rights reserved. import { isArray } from "../../types/Array"; -import { ComponentContent } from "../../dto/ComponentDTO"; +import { ComponentContent } from "../../entities/component/ComponentDTO"; export function mergeComponentContent ( a: ComponentContent | undefined, diff --git a/utils/components/populateComponentDTO.ts b/utils/components/populateComponentDTO.ts index afb91c8..71d3ad3 100644 --- a/utils/components/populateComponentDTO.ts +++ b/utils/components/populateComponentDTO.ts @@ -1,8 +1,8 @@ // Copyright (c) 2023. Sendanor . All rights reserved. import { find } from "../../functions/find"; -import { createComponentDTO, ComponentContent, ComponentDTO } from "../../dto/ComponentDTO"; -import { isHyperComponent } from "../../dto/types/HyperComponent"; +import { createComponentDTO, ComponentContent, ComponentDTO } from "../../entities/component/ComponentDTO"; +import { isHyperComponent } from "../../entities/types/HyperComponent"; import { mergeComponentContent } from "./mergeComponentContent"; export function populateComponentDTO ( diff --git a/utils/populateAppDTO.ts b/utils/populateAppDTO.ts index cfe13a5..2ccacc0 100644 --- a/utils/populateAppDTO.ts +++ b/utils/populateAppDTO.ts @@ -1,13 +1,13 @@ // Copyright (c) 2023. Sendanor . All rights reserved. import { some } from "../functions/some"; -import { explainViewDTO, ViewDTO, isViewDTO } from "../dto/ViewDTO"; -import { AppDTO } from "../dto/AppDTO"; +import { explainViewDTO, ViewDTO, isViewDTO } from "../entities/view/ViewDTO"; +import { AppDTO } from "../entities/app/AppDTO"; import { HttpService } from "../HttpService"; import { LogService } from "../LogService"; import { ReadonlyJsonAny } from "../Json"; -import { explainComponentDTO, ComponentDTO, isComponentDTO } from "../dto/ComponentDTO"; -import { explainRouteDTO, RouteDTO, isRouteDTO } from "../dto/RouteDTO"; +import { explainComponentDTO, ComponentDTO, isComponentDTO } from "../entities/component/ComponentDTO"; +import { explainRouteDTO, RouteDTO, isRouteDTO } from "../entities/route/RouteDTO"; const LOG = LogService.createLogger('populateAppDTO'); diff --git a/utils/views/findAndPopulateViewDTO.test.ts b/utils/views/findAndPopulateViewDTO.test.ts index 76924f9..082f370 100644 --- a/utils/views/findAndPopulateViewDTO.test.ts +++ b/utils/views/findAndPopulateViewDTO.test.ts @@ -1,6 +1,6 @@ import { findAndPopulateViewDTO } from "./findAndPopulateViewDTO"; import { isArrayOf } from "../../types/Array"; -import { createViewDTO } from '../../dto/ViewDTO'; +import { createViewDTO } from '../../entities/view/ViewDTO'; describe('findAndPopulateViewDTO', () => { diff --git a/utils/views/findAndPopulateViewDTO.ts b/utils/views/findAndPopulateViewDTO.ts index 8ff93a7..c5b0c94 100644 --- a/utils/views/findAndPopulateViewDTO.ts +++ b/utils/views/findAndPopulateViewDTO.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { ViewDTO } from "../../dto/ViewDTO"; +import { ViewDTO } from "../../entities/view/ViewDTO"; import { findViewDTO } from "./findViewDTO"; import { populateViewDTO } from "./populateViewDTO"; diff --git a/utils/views/findViewDTO.test.ts b/utils/views/findViewDTO.test.ts index 7440ca3..d6b32ff 100644 --- a/utils/views/findViewDTO.test.ts +++ b/utils/views/findViewDTO.test.ts @@ -1,5 +1,5 @@ import { findViewDTO } from "./findViewDTO"; -import { createViewDTO } from '../../dto/ViewDTO'; +import { createViewDTO } from '../../entities/view/ViewDTO'; describe('findViewDTO', () => { const hyperView1 = createViewDTO('View1', undefined, undefined, undefined, undefined, undefined, undefined, undefined); diff --git a/utils/views/findViewDTO.ts b/utils/views/findViewDTO.ts index a9e6c49..02cbd25 100644 --- a/utils/views/findViewDTO.ts +++ b/utils/views/findViewDTO.ts @@ -5,7 +5,7 @@ import { LogService } from "../../LogService"; import { createViewDTO, ViewDTO, -} from "../../dto/ViewDTO"; +} from "../../entities/view/ViewDTO"; const LOG = LogService.createLogger( 'findHyperViewDTO' ); diff --git a/utils/views/populateViewDTO.test.ts b/utils/views/populateViewDTO.test.ts index f63d758..24e68b9 100644 --- a/utils/views/populateViewDTO.test.ts +++ b/utils/views/populateViewDTO.test.ts @@ -3,7 +3,7 @@ import { LogLevel } from "../../types/LogLevel"; import { populateViewDTO } from "./populateViewDTO"; import { isArrayOf } from "../../types/Array"; -import { createViewDTO } from '../../dto/ViewDTO'; +import { createViewDTO } from '../../entities/view/ViewDTO'; describe('populateViewDTO', () => { diff --git a/utils/views/populateViewDTO.ts b/utils/views/populateViewDTO.ts index f1b952f..b37b709 100644 --- a/utils/views/populateViewDTO.ts +++ b/utils/views/populateViewDTO.ts @@ -3,8 +3,8 @@ import { find } from "../../functions/find"; import { LogService } from "../../LogService"; import { LogLevel } from "../../types/LogLevel"; -import { ComponentContent } from "../../dto/ComponentDTO"; -import { createViewDTO, ViewDTO } from "../../dto/ViewDTO"; +import { ComponentContent } from "../../entities/component/ComponentDTO"; +import { createViewDTO, ViewDTO } from "../../entities/view/ViewDTO"; import { mergeComponentContent } from "../components/mergeComponentContent"; const LOG = LogService.createLogger( 'populateViewDTO' ); diff --git a/views/extend/ExtendViewDTO.ts b/views/extend/ExtendViewDTO.ts index 3430b34..4764af4 100644 --- a/views/extend/ExtendViewDTO.ts +++ b/views/extend/ExtendViewDTO.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createViewDTO, ViewDTO } from "../../dto/ViewDTO"; +import { createViewDTO, ViewDTO } from "../../entities/view/ViewDTO"; import { ExtendView } from "./ExtendView"; export const EXTEND_VIEW_NAME: string = 'ExtendView'; diff --git a/views/redirect/RedirectViewDTO.ts b/views/redirect/RedirectViewDTO.ts index 2ab48fc..7505aea 100644 --- a/views/redirect/RedirectViewDTO.ts +++ b/views/redirect/RedirectViewDTO.ts @@ -1,6 +1,6 @@ // Copyright (c) 2023. Sendanor . All rights reserved. -import { createViewDTO, ViewDTO } from "../../dto/ViewDTO"; +import { createViewDTO, ViewDTO } from "../../entities/view/ViewDTO"; import { RedirectView } from "./RedirectView"; export const REDIRECT_VIEW_NAME: string = 'RedirectView';