Skip to content

Commit

Permalink
refactorings in parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
undergroundwires committed Jan 6, 2020
1 parent 5ccc7c5 commit 2aa3742
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 122 deletions.
120 changes: 0 additions & 120 deletions src/application/ApplicationParser.ts

This file was deleted.

29 changes: 29 additions & 0 deletions src/application/Parser/ApplicationParser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Category } from '../../domain/Category';
import { Application } from '../../domain/Application';
import { Script } from '@/domain/Script';
import applicationFile from 'js-yaml-loader!./../application.yaml';
import { parseCategory } from './CategoryParser';

interface ApplicationResult {
readonly application: Application;
readonly selectedScripts: Script[];
}

export function buildApplication(): ApplicationResult {
const name = applicationFile.name as string;
const version = applicationFile.version as number;
const categories = new Array<Category>();
const selectedScripts = new Array<Script>();
if (!applicationFile.actions || applicationFile.actions.length <= 0) {
throw new Error('Application does not define any action');
}
for (const action of applicationFile.actions) {
const category = parseCategory({
category: action,
selectedScripts,
});
categories.push(category);
}
const app = new Application(name, version, categories);
return { application: app, selectedScripts };
}
70 changes: 70 additions & 0 deletions src/application/Parser/CategoryParser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { YamlCategory, YamlScript } from 'js-yaml-loader!./application.yaml';
import { Script } from '@/domain/Script';
import { Category } from '../../domain/Category';
import { parseDocUrls } from './DocumentationParser';

let categoryIdCounter: number = 0;

interface IParsingContext {
category: YamlCategory;
selectedScripts: Script[];
}

interface ICategoryChildren {
subCategories: Category[];
subScripts: Script[];
}

export function parseCategory(context: IParsingContext): Category {
if (!context.category.children || context.category.children.length <= 0) {
throw Error('Category has no children');
}
const children: ICategoryChildren = {
subCategories: new Array<Category>(),
subScripts: new Array<Script>(),
};
for (const categoryOrScript of context.category.children) {
parseCategoryChild(categoryOrScript, children, context);
}
return new Category(
/*id*/ categoryIdCounter++,
/*name*/ context.category.category,
/*docs*/ parseDocUrls(context.category),
/*categories*/ children.subCategories,
/*scripts*/ children.subScripts,
);
}

function parseCategoryChild(
categoryOrScript: any, children: ICategoryChildren, parent: IParsingContext) {
if (isCategory(categoryOrScript)) {
const subCategory = parseCategory(
{
category: categoryOrScript as YamlCategory,
selectedScripts: parent.selectedScripts,
});
children.subCategories.push(subCategory);
} else if (isScript(categoryOrScript)) {
const yamlScript = categoryOrScript as YamlScript;
const script = new Script(
/* name */ yamlScript.name,
/* code */ yamlScript.code,
/* docs */ parseDocUrls(yamlScript));
children.subScripts.push(script);
if (yamlScript.default === true) {
parent.selectedScripts.push(script);
}
} else {
throw new Error(`Child element is neither a category or a script.
Parent: ${parent.category.category}, element: ${categoryOrScript}`);
}
}


function isScript(categoryOrScript: any): boolean {
return categoryOrScript.code && categoryOrScript.code.length > 0;
}

function isCategory(categoryOrScript: any): boolean {
return categoryOrScript.category && categoryOrScript.category.length > 0;
}
49 changes: 49 additions & 0 deletions src/application/Parser/DocumentationParser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { YamlDocumentable } from 'js-yaml-loader!./application.yaml';

export function parseDocUrls(documentable: YamlDocumentable): ReadonlyArray<string> {
const docs = documentable.docs;
if (!docs) {
return [];
}
const result = new DocumentationUrls();
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);
}
} 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();
}

class DocumentationUrls {
private readonly urls = new Array<string>();

public add(url: string) {
validateUrl(url);
this.urls.push(url);
}

public getAll(): ReadonlyArray<string> {
return this.urls;
}
}

function validateUrl(docUrl: string): void {
if (!docUrl) {
throw new Error('Documentation url is null or empty');
}
if (docUrl.includes('\n')) {
throw new Error('Documentation url cannot be multi-lined.');
}
const res = docUrl.match(
/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g);
if (res == null) {
throw new Error(`Invalid documentation url: ${docUrl}`);
}
}
4 changes: 2 additions & 2 deletions src/application/State/ApplicationState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { IUserSelection } from './Selection/IUserSelection';
import { AsyncLazy } from '../../infrastructure/Threading/AsyncLazy';
import { Signal } from '../../infrastructure/Events/Signal';
import { ICategory } from '../../domain/ICategory';
import { ApplicationParser } from '../ApplicationParser';
import { buildApplication } from '../Parser/ApplicationParser';
import { IApplicationState } from './IApplicationState';
import { Script } from '../../domain/Script';
import { Application } from '../../domain/Application';
Expand All @@ -21,7 +21,7 @@ export class ApplicationState implements IApplicationState {

/** Application instance with all scripts. */
private static instance = new AsyncLazy<IApplicationState>(() => {
const app = ApplicationParser.buildApplication();
const app = buildApplication();
const state = new ApplicationState(app.application, app.selectedScripts);
return Promise.resolve(state);
});
Expand Down

0 comments on commit 2aa3742

Please sign in to comment.