From 66d4d39d5bf3db305450514c6b6224654dafbfb2 Mon Sep 17 00:00:00 2001 From: undergroundwires Date: Fri, 7 Aug 2020 22:16:10 +0100 Subject: [PATCH] refactorings --- .../Environment/BrowserOs/DetectorBuilder.ts | 56 +++++++++--------- src/application/Parser/DocumentationParser.ts | 35 ++++++----- src/application/application.yaml.d.ts | 2 +- src/domain/Application.ts | 58 +++++++++++-------- .../Bootstrapping/Modules/IconBootstrapper.ts | 2 +- .../Scripts/ScriptsTree/ScriptNodeParser.ts | 35 +++++++---- .../SelectableTree/NodeTranslator.ts | 15 +++-- 7 files changed, 124 insertions(+), 79 deletions(-) diff --git a/src/application/Environment/BrowserOs/DetectorBuilder.ts b/src/application/Environment/BrowserOs/DetectorBuilder.ts index 403f0ac6..133915a4 100644 --- a/src/application/Environment/BrowserOs/DetectorBuilder.ts +++ b/src/application/Environment/BrowserOs/DetectorBuilder.ts @@ -8,19 +8,11 @@ export class DetectorBuilder { constructor(private readonly os: OperatingSystem) { } public mustInclude(str: string): DetectorBuilder { - if (!str) { - throw new Error('part to include is empty or undefined'); - } - this.existingPartsInUserAgent.push(str); - return this; + return this.add(str, this.existingPartsInUserAgent); } public mustNotInclude(str: string): DetectorBuilder { - if (!str) { - throw new Error('part to not include is empty or undefined'); - } - this.notExistingPartsInUserAgent.push(str); - return this; + return this.add(str, this.notExistingPartsInUserAgent); } public build(): IBrowserOsDetector { @@ -28,22 +20,34 @@ export class DetectorBuilder { throw new Error('Must include at least a part'); } return { - detect: (userAgent) => { - if (!userAgent) { - throw new Error('User agent is null or undefined'); - } - for (const exitingPart of this.existingPartsInUserAgent) { - if (!userAgent.includes(exitingPart)) { - return OperatingSystem.Unknown; - } - } - for (const notExistingPart of this.notExistingPartsInUserAgent) { - if (userAgent.includes(notExistingPart)) { - return OperatingSystem.Unknown; - } - } - return this.os; - }, + detect: (agent) => this.detect(agent), }; } + + private detect(userAgent: string): OperatingSystem { + if (!userAgent) { + throw new Error('User agent is null or undefined'); + } + if (this.existingPartsInUserAgent.some((part) => !userAgent.includes(part))) { + return OperatingSystem.Unknown; + } + if (this.notExistingPartsInUserAgent.some((part) => userAgent.includes(part))) { + return OperatingSystem.Unknown; + } + return this.os; + } + + private add(part: string, array: string[]): DetectorBuilder { + if (!part) { + throw new Error('part is empty or undefined'); + } + if (this.existingPartsInUserAgent.includes(part)) { + throw new Error(`part ${part} is already included as existing part`); + } + if (this.notExistingPartsInUserAgent.includes(part)) { + throw new Error(`part ${part} is already included as not existing part`); + } + array.push(part); + return this; + } } diff --git a/src/application/Parser/DocumentationParser.ts b/src/application/Parser/DocumentationParser.ts index d535a773..e67b8737 100644 --- a/src/application/Parser/DocumentationParser.ts +++ b/src/application/Parser/DocumentationParser.ts @@ -1,37 +1,46 @@ -import { YamlDocumentable } from 'js-yaml-loader!./application.yaml'; +import { YamlDocumentable, DocumentationUrls } from 'js-yaml-loader!./application.yaml'; export function parseDocUrls(documentable: YamlDocumentable): ReadonlyArray { if (!documentable) { throw new Error('documentable is null or undefined'); } const docs = documentable.docs; - if (!docs) { + if (!docs || !docs.length) { return []; } - const result = new DocumentationUrls(); + let result = new DocumentationUrlContainer(); + result = addDocs(docs, result); + return result.getAll(); +} + +function addDocs(docs: DocumentationUrls, urls: DocumentationUrlContainer): DocumentationUrlContainer { if (docs instanceof Array) { - for (const doc of docs) { - if (typeof doc !== 'string') { - throw new Error('Docs field (documentation url) must be an array of strings'); - } - result.add(doc); - } + urls.addUrls(docs); } else if (typeof docs === 'string') { - result.add(docs); + urls.addUrl(docs); } else { throw new Error('Docs field (documentation url) must a string or array of strings'); } - return result.getAll(); + return urls; } -class DocumentationUrls { +class DocumentationUrlContainer { private readonly urls = new Array(); - public add(url: string) { + public addUrl(url: string) { validateUrl(url); this.urls.push(url); } + public addUrls(urls: any[]) { + for (const url of urls) { + if (typeof url !== 'string') { + throw new Error('Docs field (documentation url) must be an array of strings'); + } + this.addUrl(url); + } + } + public getAll(): ReadonlyArray { return this.urls; } diff --git a/src/application/application.yaml.d.ts b/src/application/application.yaml.d.ts index 6d93c903..5bb0e611 100644 --- a/src/application/application.yaml.d.ts +++ b/src/application/application.yaml.d.ts @@ -1,6 +1,6 @@ declare module 'js-yaml-loader!*' { export type CategoryOrScript = YamlCategory | YamlScript; - type DocumentationUrls = ReadonlyArray | string; + export type DocumentationUrls = ReadonlyArray | string; export interface YamlDocumentable { docs?: DocumentationUrls; diff --git a/src/domain/Application.ts b/src/domain/Application.ts index 36bf83cf..cae194c9 100644 --- a/src/domain/Application.ts +++ b/src/domain/Application.ts @@ -18,15 +18,7 @@ export class Application implements IApplication { if (!repositoryUrl) { throw Error('Application has no repository url'); } if (!version) { throw Error('Version cannot be empty'); } this.flattened = flatten(actions); - if (this.flattened.allCategories.length === 0) { - throw new Error('Application must consist of at least one category'); - } - if (this.flattened.allScripts.length === 0) { - throw new Error('Application must consist of at least one script'); - } - if (this.flattened.allScripts.filter((script) => script.isRecommended).length === 0) { - throw new Error('Application must consist of at least one recommended script'); - } + ensureValid(this.flattened); ensureNoDuplicates(this.flattened.allCategories); ensureNoDuplicates(this.flattened.allScripts); } @@ -75,30 +67,50 @@ interface IFlattenedApplication { allScripts: IScript[]; } -function flattenRecursive( +function ensureValid(application: IFlattenedApplication) { + if (!application.allCategories || application.allCategories.length === 0) { + throw new Error('Application must consist of at least one category'); + } + if (!application.allScripts || application.allScripts.length === 0) { + throw new Error('Application must consist of at least one script'); + } + if (application.allScripts.filter((script) => script.isRecommended).length === 0) { + throw new Error('Application must consist of at least one recommended script'); + } +} + +function flattenCategories( categories: ReadonlyArray, - flattened: IFlattenedApplication) { + flattened: IFlattenedApplication): IFlattenedApplication { + if (!categories || categories.length === 0) { + return flattened; + } for (const category of categories) { flattened.allCategories.push(category); - if (category.scripts) { - for (const script of category.scripts) { - flattened.allScripts.push(script); - } - } - if (category.subCategories && category.subCategories.length > 0) { - flattenRecursive( - category.subCategories as ReadonlyArray, - flattened); - } + flattened = flattenScripts(category.scripts, flattened); + flattened = flattenCategories(category.subCategories, flattened); + } + return flattened; +} + +function flattenScripts( + scripts: ReadonlyArray, + flattened: IFlattenedApplication): IFlattenedApplication { + if (!scripts) { + return flattened; } + for (const script of scripts) { + flattened.allScripts.push(script); + } + return flattened; } function flatten( categories: ReadonlyArray): IFlattenedApplication { - const flattened: IFlattenedApplication = { + let flattened: IFlattenedApplication = { allCategories: new Array(), allScripts: new Array(), }; - flattenRecursive(categories, flattened); + flattened = flattenCategories(categories, flattened); return flattened; } diff --git a/src/presentation/Bootstrapping/Modules/IconBootstrapper.ts b/src/presentation/Bootstrapping/Modules/IconBootstrapper.ts index f1879bf1..4a1519fc 100644 --- a/src/presentation/Bootstrapping/Modules/IconBootstrapper.ts +++ b/src/presentation/Bootstrapping/Modules/IconBootstrapper.ts @@ -4,7 +4,7 @@ import { faGithub } from '@fortawesome/free-brands-svg-icons'; /** BRAND ICONS (PREFIX: fab) */ import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; /** REGULAR ICONS (PREFIX: far) */ -import { faFolderOpen, faFolder, faComment, faSmile } from '@fortawesome/free-regular-svg-icons'; +import { faFolderOpen, faFolder, faSmile } from '@fortawesome/free-regular-svg-icons'; /** SOLID ICONS (PREFIX: fas (default)) */ import { faTimes, faFileDownload, faCopy, faSearch, faInfoCircle, faUserSecret, faDesktop, faTag, faGlobe } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/presentation/Scripts/ScriptsTree/ScriptNodeParser.ts b/src/presentation/Scripts/ScriptsTree/ScriptNodeParser.ts index 708968ff..73220850 100644 --- a/src/presentation/Scripts/ScriptsTree/ScriptNodeParser.ts +++ b/src/presentation/Scripts/ScriptsTree/ScriptNodeParser.ts @@ -30,19 +30,32 @@ export function getCategoryNodeId(category: ICategory): string { function parseCategoryRecursively( parentCategory: ICategory): INode[] { - if (!parentCategory) { throw new Error('parentCategory is undefined'); } + if (!parentCategory) { + throw new Error('parentCategory is undefined'); + } + let nodes = new Array(); + nodes = addCategories(parentCategory.subCategories, nodes); + nodes = addScripts(parentCategory.scripts, nodes); + return nodes; +} - const nodes = new Array(); - if (parentCategory.subCategories && parentCategory.subCategories.length > 0) { - for (const subCategory of parentCategory.subCategories) { - const subCategoryNodes = parseCategoryRecursively(subCategory); - nodes.push(convertCategoryToNode(subCategory, subCategoryNodes)); - } +function addScripts(scripts: ReadonlyArray, nodes: INode[]): INode[] { + if (!scripts || scripts.length === 0) { + return nodes; + } + for (const script of scripts) { + nodes.push(convertScriptToNode(script)); + } + return nodes; +} + +function addCategories(categories: ReadonlyArray, nodes: INode[]): INode[] { + if (!categories || categories.length === 0) { + return nodes; } - if (parentCategory.scripts && parentCategory.scripts.length > 0) { - for (const script of parentCategory.scripts) { - nodes.push(convertScriptToNode(script)); - } + for (const category of categories) { + const subCategoryNodes = parseCategoryRecursively(category); + nodes.push(convertCategoryToNode(category, subCategoryNodes)); } return nodes; } diff --git a/src/presentation/Scripts/ScriptsTree/SelectableTree/NodeTranslator.ts b/src/presentation/Scripts/ScriptsTree/SelectableTree/NodeTranslator.ts index 0489aec2..ad449c69 100644 --- a/src/presentation/Scripts/ScriptsTree/SelectableTree/NodeTranslator.ts +++ b/src/presentation/Scripts/ScriptsTree/SelectableTree/NodeTranslator.ts @@ -9,8 +9,7 @@ export function convertExistingToNode(liquorTreeNode: ILiquorTreeExistingNode): id: liquorTreeNode.id, text: liquorTreeNode.data.text, // selected: liquorTreeNode.states && liquorTreeNode.states.checked, - children: (!liquorTreeNode.children || liquorTreeNode.children.length === 0) - ? [] : liquorTreeNode.children.map((childNode) => convertExistingToNode(childNode)), + children: convertChildren(liquorTreeNode.children, convertExistingToNode), documentationUrls: liquorTreeNode.data.documentationUrls, isReversible : liquorTreeNode.data.isReversible, }; @@ -24,11 +23,19 @@ export function toNewLiquorTreeNode(node: INode): ILiquorTreeNewNode { state: { checked: false, }, - children: (!node.children || node.children.length === 0) ? [] : - node.children.map((childNode) => toNewLiquorTreeNode(childNode)), + children: convertChildren(node.children, toNewLiquorTreeNode), data: { documentationUrls: node.documentationUrls, isReversible: node.isReversible, }, }; } + +function convertChildren( + oldChildren: readonly TOldNode[], + callback: (value: TOldNode) => TNewNode): TNewNode[] { + if (!oldChildren || oldChildren.length === 0) { + return []; + } + return oldChildren.map((childNode) => callback(childNode)); +}