refactorings

This commit is contained in:
undergroundwires
2020-08-07 22:16:10 +01:00
parent a5dbe66fc1
commit 66d4d39d5b
7 changed files with 129 additions and 84 deletions

View File

@@ -8,19 +8,11 @@ export class DetectorBuilder {
constructor(private readonly os: OperatingSystem) { } constructor(private readonly os: OperatingSystem) { }
public mustInclude(str: string): DetectorBuilder { public mustInclude(str: string): DetectorBuilder {
if (!str) { return this.add(str, this.existingPartsInUserAgent);
throw new Error('part to include is empty or undefined');
}
this.existingPartsInUserAgent.push(str);
return this;
} }
public mustNotInclude(str: string): DetectorBuilder { public mustNotInclude(str: string): DetectorBuilder {
if (!str) { return this.add(str, this.notExistingPartsInUserAgent);
throw new Error('part to not include is empty or undefined');
}
this.notExistingPartsInUserAgent.push(str);
return this;
} }
public build(): IBrowserOsDetector { public build(): IBrowserOsDetector {
@@ -28,22 +20,34 @@ export class DetectorBuilder {
throw new Error('Must include at least a part'); throw new Error('Must include at least a part');
} }
return { return {
detect: (userAgent) => { detect: (agent) => this.detect(agent),
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;
},
}; };
} }
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;
}
} }

View File

@@ -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> { export function parseDocUrls(documentable: YamlDocumentable): ReadonlyArray<string> {
if (!documentable) { if (!documentable) {
throw new Error('documentable is null or undefined'); throw new Error('documentable is null or undefined');
} }
const docs = documentable.docs; const docs = documentable.docs;
if (!docs) { if (!docs || !docs.length) {
return []; return [];
} }
const result = new DocumentationUrls(); let result = new DocumentationUrlContainer();
if (docs instanceof Array) { result = addDocs(docs, result);
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);
}
} else if (typeof docs === 'string') {
result.add(docs);
} else {
throw new Error('Docs field (documentation url) must a string or array of strings');
}
return result.getAll(); return result.getAll();
} }
class DocumentationUrls { function addDocs(docs: DocumentationUrls, urls: DocumentationUrlContainer): DocumentationUrlContainer {
if (docs instanceof Array) {
urls.addUrls(docs);
} else if (typeof docs === 'string') {
urls.addUrl(docs);
} else {
throw new Error('Docs field (documentation url) must a string or array of strings');
}
return urls;
}
class DocumentationUrlContainer {
private readonly urls = new Array<string>(); private readonly urls = new Array<string>();
public add(url: string) { public addUrl(url: string) {
validateUrl(url); validateUrl(url);
this.urls.push(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> { public getAll(): ReadonlyArray<string> {
return this.urls; return this.urls;
} }

View File

@@ -1,6 +1,6 @@
declare module 'js-yaml-loader!*' { declare module 'js-yaml-loader!*' {
export type CategoryOrScript = YamlCategory | YamlScript; export type CategoryOrScript = YamlCategory | YamlScript;
type DocumentationUrls = ReadonlyArray<string> | string; export type DocumentationUrls = ReadonlyArray<string> | string;
export interface YamlDocumentable { export interface YamlDocumentable {
docs?: DocumentationUrls; docs?: DocumentationUrls;

View File

@@ -18,15 +18,7 @@ export class Application implements IApplication {
if (!repositoryUrl) { throw Error('Application has no repository url'); } if (!repositoryUrl) { throw Error('Application has no repository url'); }
if (!version) { throw Error('Version cannot be empty'); } if (!version) { throw Error('Version cannot be empty'); }
this.flattened = flatten(actions); this.flattened = flatten(actions);
if (this.flattened.allCategories.length === 0) { ensureValid(this.flattened);
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');
}
ensureNoDuplicates(this.flattened.allCategories); ensureNoDuplicates(this.flattened.allCategories);
ensureNoDuplicates(this.flattened.allScripts); ensureNoDuplicates(this.flattened.allScripts);
} }
@@ -75,30 +67,50 @@ interface IFlattenedApplication {
allScripts: IScript[]; 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>, categories: ReadonlyArray<ICategory>,
flattened: IFlattenedApplication) { flattened: IFlattenedApplication): IFlattenedApplication {
if (!categories || categories.length === 0) {
return flattened;
}
for (const category of categories) { for (const category of categories) {
flattened.allCategories.push(category); flattened.allCategories.push(category);
if (category.scripts) { flattened = flattenScripts(category.scripts, flattened);
for (const script of category.scripts) { flattened = flattenCategories(category.subCategories, flattened);
flattened.allScripts.push(script);
}
}
if (category.subCategories && category.subCategories.length > 0) {
flattenRecursive(
category.subCategories as ReadonlyArray<ICategory>,
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( function flatten(
categories: ReadonlyArray<ICategory>): IFlattenedApplication { categories: ReadonlyArray<ICategory>): IFlattenedApplication {
const flattened: IFlattenedApplication = { let flattened: IFlattenedApplication = {
allCategories: new Array<ICategory>(), allCategories: new Array<ICategory>(),
allScripts: new Array<IScript>(), allScripts: new Array<IScript>(),
}; };
flattenRecursive(categories, flattened); flattened = flattenCategories(categories, flattened);
return flattened; return flattened;
} }

View File

@@ -4,7 +4,7 @@ import { faGithub } from '@fortawesome/free-brands-svg-icons';
/** BRAND ICONS (PREFIX: fab) */ /** BRAND ICONS (PREFIX: fab) */
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
/** REGULAR ICONS (PREFIX: far) */ /** 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)) */ /** SOLID ICONS (PREFIX: fas (default)) */
import { faTimes, faFileDownload, faCopy, faSearch, faInfoCircle, faUserSecret, faDesktop, faTag, faGlobe } from '@fortawesome/free-solid-svg-icons'; import { faTimes, faFileDownload, faCopy, faSearch, faInfoCircle, faUserSecret, faDesktop, faTag, faGlobe } from '@fortawesome/free-solid-svg-icons';

View File

@@ -30,19 +30,32 @@ export function getCategoryNodeId(category: ICategory): string {
function parseCategoryRecursively( function parseCategoryRecursively(
parentCategory: ICategory): INode[] { parentCategory: ICategory): INode[] {
if (!parentCategory) { throw new Error('parentCategory is undefined'); } if (!parentCategory) {
throw new Error('parentCategory is undefined');
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));
}
} }
if (parentCategory.scripts && parentCategory.scripts.length > 0) { let nodes = new Array<INode>();
for (const script of parentCategory.scripts) { nodes = addCategories(parentCategory.subCategories, nodes);
nodes.push(convertScriptToNode(script)); nodes = addScripts(parentCategory.scripts, nodes);
} return nodes;
}
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;
}
for (const category of categories) {
const subCategoryNodes = parseCategoryRecursively(category);
nodes.push(convertCategoryToNode(category, subCategoryNodes));
} }
return nodes; return nodes;
} }

View File

@@ -9,8 +9,7 @@ export function convertExistingToNode(liquorTreeNode: ILiquorTreeExistingNode):
id: liquorTreeNode.id, id: liquorTreeNode.id,
text: liquorTreeNode.data.text, text: liquorTreeNode.data.text,
// selected: liquorTreeNode.states && liquorTreeNode.states.checked, // selected: liquorTreeNode.states && liquorTreeNode.states.checked,
children: (!liquorTreeNode.children || liquorTreeNode.children.length === 0) children: convertChildren(liquorTreeNode.children, convertExistingToNode),
? [] : liquorTreeNode.children.map((childNode) => convertExistingToNode(childNode)),
documentationUrls: liquorTreeNode.data.documentationUrls, documentationUrls: liquorTreeNode.data.documentationUrls,
isReversible : liquorTreeNode.data.isReversible, isReversible : liquorTreeNode.data.isReversible,
}; };
@@ -24,11 +23,19 @@ export function toNewLiquorTreeNode(node: INode): ILiquorTreeNewNode {
state: { state: {
checked: false, checked: false,
}, },
children: (!node.children || node.children.length === 0) ? [] : children: convertChildren(node.children, toNewLiquorTreeNode),
node.children.map((childNode) => toNewLiquorTreeNode(childNode)),
data: { data: {
documentationUrls: node.documentationUrls, documentationUrls: node.documentationUrls,
isReversible: node.isReversible, 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));
}