refactor application.yaml to become an os definition #40

This commit is contained in:
undergroundwires
2020-09-08 21:47:18 +01:00
parent e4b6cdfb18
commit f7557bcc0f
62 changed files with 1926 additions and 573 deletions

View File

@@ -1,9 +1,12 @@
import { getEnumNames, getEnumValues } from '@/application/Common/Enum';
import { IEntity } from '../infrastructure/Entity/IEntity';
import { ICategory } from './ICategory';
import { IScript } from './IScript';
import { IApplication } from './IApplication';
import { IProjectInformation } from './IProjectInformation';
import { RecommendationLevel, RecommendationLevelNames, RecommendationLevels } from './RecommendationLevel';
import { RecommendationLevel } from './RecommendationLevel';
import { OperatingSystem } from './OperatingSystem';
import { IScriptingDefinition } from './IScriptingDefinition';
export class Application implements IApplication {
public get totalScripts(): number { return this.queryable.allScripts.length; }
@@ -12,12 +15,18 @@ export class Application implements IApplication {
private readonly queryable: IQueryableApplication;
constructor(
public readonly os: OperatingSystem,
public readonly info: IProjectInformation,
public readonly actions: ReadonlyArray<ICategory>) {
public readonly actions: ReadonlyArray<ICategory>,
public readonly scripting: IScriptingDefinition) {
if (!info) {
throw new Error('info is undefined');
throw new Error('undefined info');
}
if (!scripting) {
throw new Error('undefined scripting definition');
}
this.queryable = makeQueryable(actions);
ensureValidOs(os);
ensureValid(this.queryable);
ensureNoDuplicates(this.queryable.allCategories);
ensureNoDuplicates(this.queryable.allScripts);
@@ -50,13 +59,25 @@ export class Application implements IApplication {
}
}
function ensureValidOs(os: OperatingSystem): void {
if (os === undefined) {
throw new Error('undefined os');
}
if (os === OperatingSystem.Unknown) {
throw new Error('unknown os');
}
if (!(os in OperatingSystem)) {
throw new Error(`os "${os}" is out of range`);
}
}
function ensureNoDuplicates<TKey>(entities: ReadonlyArray<IEntity<TKey>>) {
const totalOccurencesById = new Map<TKey, number>();
const totalOccurrencesById = new Map<TKey, number>();
for (const entity of entities) {
totalOccurencesById.set(entity.id, (totalOccurencesById.get(entity.id) || 0) + 1);
totalOccurrencesById.set(entity.id, (totalOccurrencesById.get(entity.id) || 0) + 1);
}
const duplicatedIds = new Array<TKey>();
totalOccurencesById.forEach((index, id) => {
totalOccurrencesById.forEach((index, id) => {
if (index > 1) {
duplicatedIds.push(id);
}
@@ -89,7 +110,7 @@ function ensureValidScripts(allScripts: readonly IScript[]) {
if (!allScripts || allScripts.length === 0) {
throw new Error('Application must consist of at least one script');
}
for (const level of RecommendationLevels) {
for (const level of getEnumValues(RecommendationLevel)) {
if (allScripts.every((script) => script.level !== level)) {
throw new Error(`none of the scripts are recommended as ${RecommendationLevel[level]}`);
}
@@ -143,7 +164,7 @@ function makeQueryable(
function groupByLevel(allScripts: readonly IScript[]): Map<RecommendationLevel, readonly IScript[]> {
const map = new Map<RecommendationLevel, readonly IScript[]>();
for (const levelName of RecommendationLevelNames) {
for (const levelName of getEnumNames(RecommendationLevel)) {
const level = RecommendationLevel[levelName];
const scripts = allScripts.filter((script) => script.level !== undefined && script.level <= level);
map.set(level, scripts);

View File

@@ -2,9 +2,14 @@ import { IScript } from '@/domain/IScript';
import { ICategory } from '@/domain/ICategory';
import { IProjectInformation } from './IProjectInformation';
import { RecommendationLevel } from './RecommendationLevel';
import { OperatingSystem } from './OperatingSystem';
import { IScriptingDefinition } from './IScriptingDefinition';
export interface IApplication {
readonly info: IProjectInformation;
readonly scripting: IScriptingDefinition;
readonly os: OperatingSystem;
readonly totalScripts: number;
readonly totalCategories: number;
readonly actions: ReadonlyArray<ICategory>;

View File

@@ -0,0 +1,8 @@
import { ScriptingLanguage } from './ScriptingLanguage';
export interface IScriptingDefinition {
readonly fileExtension: string;
readonly language: ScriptingLanguage;
readonly startCode: string;
readonly endCode: string;
}

View File

@@ -2,10 +2,3 @@ export enum RecommendationLevel {
Standard = 0,
Strict = 1,
}
export const RecommendationLevelNames = Object
.values(RecommendationLevel)
.filter((level) => typeof level === 'string') as string[];
export const RecommendationLevels = RecommendationLevelNames
.map((level) => RecommendationLevel[level]) as RecommendationLevel[];

View File

@@ -0,0 +1,32 @@
import { ScriptingLanguage } from './ScriptingLanguage';
import { IScriptingDefinition } from './IScriptingDefinition';
export class ScriptingDefinition implements IScriptingDefinition {
public readonly fileExtension: string;
constructor(
public readonly language: ScriptingLanguage,
public readonly startCode: string,
public readonly endCode: string,
) {
this.fileExtension = findExtension(language);
validateCode(startCode, 'start code');
validateCode(endCode, 'end code');
}
}
function findExtension(language: ScriptingLanguage): string {
switch (language) {
case ScriptingLanguage.bash:
return 'sh';
case ScriptingLanguage.batchfile:
return 'bat';
default:
throw new Error(`unsupported language: ${language}`);
}
}
function validateCode(code: string, name: string) {
if (!code) {
throw new Error(`undefined ${name}`);
}
}

View File

@@ -0,0 +1,4 @@
export enum ScriptingLanguage {
batchfile = 0,
bash = 1,
}