Skip to content

Commit

Permalink
refactorings
Browse files Browse the repository at this point in the history
  • Loading branch information
undergroundwires committed Aug 9, 2020
1 parent a5dbe66 commit 66d4d39
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 79 deletions.
56 changes: 30 additions & 26 deletions src/application/Environment/BrowserOs/DetectorBuilder.ts
Expand Up @@ -8,42 +8,46 @@ 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 {
if (!this.existingPartsInUserAgent.length) {
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;
}
}
35 changes: 22 additions & 13 deletions 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<string> {
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<string>();

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<string> {
return this.urls;
}
Expand Down
2 changes: 1 addition & 1 deletion src/application/application.yaml.d.ts
@@ -1,6 +1,6 @@
declare module 'js-yaml-loader!*' {
export type CategoryOrScript = YamlCategory | YamlScript;
type DocumentationUrls = ReadonlyArray<string> | string;
export type DocumentationUrls = ReadonlyArray<string> | string;

export interface YamlDocumentable {
docs?: DocumentationUrls;
Expand Down
58 changes: 35 additions & 23 deletions src/domain/Application.ts
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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<ICategory>,
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<ICategory>,
flattened);
}
flattened = flattenScripts(category.scripts, flattened);
flattened = flattenCategories(category.subCategories, flattened);
}
return flattened;
}

function flattenScripts(
scripts: ReadonlyArray<IScript>,
flattened: IFlattenedApplication): IFlattenedApplication {
if (!scripts) {
return flattened;
}
for (const script of scripts) {
flattened.allScripts.push(script);
}
return flattened;
}

function flatten(
categories: ReadonlyArray<ICategory>): IFlattenedApplication {
const flattened: IFlattenedApplication = {
let flattened: IFlattenedApplication = {
allCategories: new Array<ICategory>(),
allScripts: new Array<IScript>(),
};
flattenRecursive(categories, flattened);
flattened = flattenCategories(categories, flattened);
return flattened;
}
2 changes: 1 addition & 1 deletion src/presentation/Bootstrapping/Modules/IconBootstrapper.ts
Expand Up @@ -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';

Expand Down
35 changes: 24 additions & 11 deletions src/presentation/Scripts/ScriptsTree/ScriptNodeParser.ts
Expand Up @@ -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<INode>();
nodes = addCategories(parentCategory.subCategories, nodes);
nodes = addScripts(parentCategory.scripts, nodes);
return nodes;
}

const nodes = new Array<INode>();
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<IScript>, 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<ICategory>, 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;
}
Expand Down
Expand Up @@ -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,
};
Expand All @@ -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<TOldNode, TNewNode>(
oldChildren: readonly TOldNode[],
callback: (value: TOldNode) => TNewNode): TNewNode[] {
if (!oldChildren || oldChildren.length === 0) {
return [];
}
return oldChildren.map((childNode) => callback(childNode));
}

0 comments on commit 66d4d39

Please sign in to comment.