From 784a67afff681bc19147d03c947de0e165d97e87 Mon Sep 17 00:00:00 2001 From: undergroundwires Date: Tue, 22 Sep 2020 20:41:12 +0100 Subject: [PATCH] refactor to read more from package.json --- package.json | 5 + .../BrowserOs/BrowserOsDetector.ts | 2 +- .../Environment/BrowserOs/DetectorBuilder.ts | 2 +- .../BrowserOs/IBrowserOsDetector.ts | 2 +- src/application/Environment/Environment.ts | 2 +- src/application/Environment/IEnvironment.ts | 2 +- src/application/Parser/ApplicationParser.ts | 19 ++- src/application/State/ApplicationState.ts | 2 +- src/application/application.yaml | 2 - src/application/application.yaml.d.ts | 2 - src/domain/Application.ts | 11 +- src/domain/IApplication.ts | 5 +- src/domain/IProjectInformation.ts | 11 ++ .../Environment => domain}/OperatingSystem.ts | 0 src/domain/ProjectInformation.ts | 55 ++++++++ src/presentation/Scripts/TheScripts.vue | 2 +- .../TheFooter/DownloadUrlList.vue | 2 +- .../TheFooter/DownloadUrlListItem.vue | 16 +-- src/presentation/TheFooter/PrivacyPolicy.vue | 4 +- src/presentation/TheFooter/TheFooter.vue | 14 +- src/presentation/TheHeader.vue | 2 +- .../BrowserOs/BrowserOsDetector.spec.ts | 2 +- .../BrowserOs/BrowserOsTestCases.ts | 2 +- .../Environment/DesktopOsTestCases.ts | 2 +- .../Environment/Environment.spec.ts | 2 +- .../Parser/ApplicationParser.spec.ts | 117 ++++++++-------- tests/unit/domain/Application.spec.ts | 105 ++++++++------ tests/unit/domain/ProjectInformation.spec.ts | 128 ++++++++++++++++++ tests/unit/stubs/ApplicationStub.ts | 5 +- vue.config.js | 7 +- 30 files changed, 374 insertions(+), 158 deletions(-) create mode 100644 src/domain/IProjectInformation.ts rename src/{application/Environment => domain}/OperatingSystem.ts (100%) create mode 100644 src/domain/ProjectInformation.ts create mode 100644 tests/unit/domain/ProjectInformation.spec.ts diff --git a/package.json b/package.json index 8485ffe5..06a43fd1 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,12 @@ "version": "0.7.5", "author": "undergroundwires", "description": "Enforce privacy & security best-practices on Windows, because privacy is sexy 🍑🍆", + "homepage": "https://privacy.sexy", "private": true, + "repository": { + "type": "git", + "url": "https://github.com/undergroundwires/privacy.sexy.git" + }, "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", diff --git a/src/application/Environment/BrowserOs/BrowserOsDetector.ts b/src/application/Environment/BrowserOs/BrowserOsDetector.ts index fecac280..10889a71 100644 --- a/src/application/Environment/BrowserOs/BrowserOsDetector.ts +++ b/src/application/Environment/BrowserOs/BrowserOsDetector.ts @@ -1,4 +1,4 @@ -import { OperatingSystem } from '../OperatingSystem'; +import { OperatingSystem } from '@/domain/OperatingSystem'; import { DetectorBuilder } from './DetectorBuilder'; import { IBrowserOsDetector } from './IBrowserOsDetector'; diff --git a/src/application/Environment/BrowserOs/DetectorBuilder.ts b/src/application/Environment/BrowserOs/DetectorBuilder.ts index 133915a4..243e3332 100644 --- a/src/application/Environment/BrowserOs/DetectorBuilder.ts +++ b/src/application/Environment/BrowserOs/DetectorBuilder.ts @@ -1,5 +1,5 @@ import { IBrowserOsDetector } from './IBrowserOsDetector'; -import { OperatingSystem } from '../OperatingSystem'; +import { OperatingSystem } from '@/domain/OperatingSystem'; export class DetectorBuilder { private readonly existingPartsInUserAgent = new Array(); diff --git a/src/application/Environment/BrowserOs/IBrowserOsDetector.ts b/src/application/Environment/BrowserOs/IBrowserOsDetector.ts index 57c14f42..c327584e 100644 --- a/src/application/Environment/BrowserOs/IBrowserOsDetector.ts +++ b/src/application/Environment/BrowserOs/IBrowserOsDetector.ts @@ -1,4 +1,4 @@ -import { OperatingSystem } from '../OperatingSystem'; +import { OperatingSystem } from '@/domain/OperatingSystem'; export interface IBrowserOsDetector { detect(userAgent: string): OperatingSystem; diff --git a/src/application/Environment/Environment.ts b/src/application/Environment/Environment.ts index eb7c2c04..c0fb8816 100644 --- a/src/application/Environment/Environment.ts +++ b/src/application/Environment/Environment.ts @@ -1,7 +1,7 @@ import { BrowserOsDetector } from './BrowserOs/BrowserOsDetector'; import { IBrowserOsDetector } from './BrowserOs/IBrowserOsDetector'; import { IEnvironment } from './IEnvironment'; -import { OperatingSystem } from './OperatingSystem'; +import { OperatingSystem } from '@/domain/OperatingSystem'; interface IEnvironmentVariables { readonly window: Window & typeof globalThis; diff --git a/src/application/Environment/IEnvironment.ts b/src/application/Environment/IEnvironment.ts index c90d4a2f..14e53ca6 100644 --- a/src/application/Environment/IEnvironment.ts +++ b/src/application/Environment/IEnvironment.ts @@ -1,4 +1,4 @@ -import { OperatingSystem } from './OperatingSystem'; +import { OperatingSystem } from '@/domain/OperatingSystem'; export interface IEnvironment { isDesktop: boolean; diff --git a/src/application/Parser/ApplicationParser.ts b/src/application/Parser/ApplicationParser.ts index 3dc912b6..c4d499ea 100644 --- a/src/application/Parser/ApplicationParser.ts +++ b/src/application/Parser/ApplicationParser.ts @@ -1,24 +1,35 @@ import { Category } from '@/domain/Category'; import { Application } from '@/domain/Application'; import { IApplication } from '@/domain/IApplication'; +import { IProjectInformation } from '@/domain/IProjectInformation'; import { ApplicationYaml } from 'js-yaml-loader!./../application.yaml'; import { parseCategory } from './CategoryParser'; +import { ProjectInformation } from '../../domain/ProjectInformation'; -export function parseApplication(content: ApplicationYaml): IApplication { + +export function parseApplication(content: ApplicationYaml, env: NodeJS.ProcessEnv = process.env): IApplication { validate(content); const categories = new Array(); for (const action of content.actions) { const category = parseCategory(action); categories.push(category); } + const info = readAppInformation(env); const app = new Application( - content.name, - content.repositoryUrl, - process.env.VUE_APP_VERSION, + info, categories); return app; } +function readAppInformation(environment): IProjectInformation { + return new ProjectInformation( + environment.VUE_APP_NAME, + environment.VUE_APP_VERSION, + environment.VUE_APP_REPOSITORY_URL, + environment.VUE_APP_HOMEPAGE_URL, + ); +} + function validate(content: ApplicationYaml): void { if (!content) { throw new Error('application is null or undefined'); diff --git a/src/application/State/ApplicationState.ts b/src/application/State/ApplicationState.ts index 0d09e824..be9207fc 100644 --- a/src/application/State/ApplicationState.ts +++ b/src/application/State/ApplicationState.ts @@ -39,7 +39,7 @@ export class ApplicationState implements IApplicationState { /** Initially selected scripts */ public readonly defaultScripts: Script[]) { this.selection = new UserSelection(app, defaultScripts.map((script) => new SelectedScript(script, false))); - this.code = new ApplicationCode(this.selection, app.version); + this.code = new ApplicationCode(this.selection, app.info.version); this.filter = new UserFilter(app); } } diff --git a/src/application/application.yaml b/src/application/application.yaml index 0307b81c..ba822689 100644 --- a/src/application/application.yaml +++ b/src/application/application.yaml @@ -1,6 +1,4 @@ # Structure documented in "./application.yaml.d.ts" (as code) -name: privacy.sexy -repositoryUrl: https://github.com/undergroundwires/privacy.sexy actions: - category: Privacy cleanup diff --git a/src/application/application.yaml.d.ts b/src/application/application.yaml.d.ts index 5bb0e611..701bf973 100644 --- a/src/application/application.yaml.d.ts +++ b/src/application/application.yaml.d.ts @@ -19,8 +19,6 @@ declare module 'js-yaml-loader!*' { } export interface ApplicationYaml { - name: string; - repositoryUrl: string; actions: ReadonlyArray; } diff --git a/src/domain/Application.ts b/src/domain/Application.ts index cae194c9..7578165d 100644 --- a/src/domain/Application.ts +++ b/src/domain/Application.ts @@ -2,6 +2,7 @@ import { IEntity } from '../infrastructure/Entity/IEntity'; import { ICategory } from './ICategory'; import { IScript } from './IScript'; import { IApplication } from './IApplication'; +import { IProjectInformation } from './IProjectInformation'; export class Application implements IApplication { public get totalScripts(): number { return this.flattened.allScripts.length; } @@ -10,13 +11,11 @@ export class Application implements IApplication { private readonly flattened: IFlattenedApplication; constructor( - public readonly name: string, - public readonly repositoryUrl: string, - public readonly version: string, + public readonly info: IProjectInformation, public readonly actions: ReadonlyArray) { - if (!name) { throw Error('Application has no name'); } - if (!repositoryUrl) { throw Error('Application has no repository url'); } - if (!version) { throw Error('Version cannot be empty'); } + if (!info) { + throw new Error('info is undefined'); + } this.flattened = flatten(actions); ensureValid(this.flattened); ensureNoDuplicates(this.flattened.allCategories); diff --git a/src/domain/IApplication.ts b/src/domain/IApplication.ts index 74bb3dd1..a84d7ce1 100644 --- a/src/domain/IApplication.ts +++ b/src/domain/IApplication.ts @@ -1,10 +1,9 @@ import { IScript } from '@/domain/IScript'; import { ICategory } from '@/domain/ICategory'; +import { IProjectInformation } from './IProjectInformation'; export interface IApplication { - readonly name: string; - readonly repositoryUrl: string; - readonly version: string; + readonly info: IProjectInformation; readonly totalScripts: number; readonly totalCategories: number; readonly actions: ReadonlyArray; diff --git a/src/domain/IProjectInformation.ts b/src/domain/IProjectInformation.ts new file mode 100644 index 00000000..c6fc6d63 --- /dev/null +++ b/src/domain/IProjectInformation.ts @@ -0,0 +1,11 @@ +import { OperatingSystem } from './OperatingSystem'; +export interface IProjectInformation { + readonly name: string; + readonly version: string; + readonly repositoryUrl: string; + readonly homepage: string; + readonly feedbackUrl: string; + readonly releaseUrl: string; + readonly repositoryWebUrl: string; + getDownloadUrl(os: OperatingSystem): string; +} diff --git a/src/application/Environment/OperatingSystem.ts b/src/domain/OperatingSystem.ts similarity index 100% rename from src/application/Environment/OperatingSystem.ts rename to src/domain/OperatingSystem.ts diff --git a/src/domain/ProjectInformation.ts b/src/domain/ProjectInformation.ts new file mode 100644 index 00000000..4ed0f6e3 --- /dev/null +++ b/src/domain/ProjectInformation.ts @@ -0,0 +1,55 @@ +import { IProjectInformation } from './IProjectInformation'; +import { OperatingSystem } from './OperatingSystem'; + +export class ProjectInformation implements IProjectInformation { + public readonly repositoryWebUrl: string; + constructor( + public readonly name: string, + public readonly version: string, + public readonly repositoryUrl: string, + public readonly homepage: string, + ) { + if (!name) { + throw new Error('name is undefined'); + } + if (!version || +version <= 0) { + throw new Error('version should be higher than zero'); + } + if (!repositoryUrl) { + throw new Error('repositoryUrl is undefined'); + } + if (!homepage) { + throw new Error('homepage is undefined'); + } + this.repositoryWebUrl = getWebUrl(this.repositoryUrl); + } + public getDownloadUrl(os: OperatingSystem): string { + return `${this.repositoryWebUrl}/releases/download/${this.version}/${getFileName(os, this.version)}`; + } + public get feedbackUrl(): string { + return `${this.repositoryWebUrl}/issues`; + } + public get releaseUrl(): string { + return `${this.repositoryWebUrl}/releases/tag/${this.version}`; + } +} + +function getWebUrl(gitUrl: string) { + if (gitUrl.endsWith('.git')) { + return gitUrl.substring(0, gitUrl.length - 4); + } + return gitUrl; +} + +function getFileName(os: OperatingSystem, version: string): string { + switch (os) { + case OperatingSystem.Linux: + return `privacy.sexy-${version}.AppImage`; + case OperatingSystem.macOS: + return `privacy.sexy-${version}.dmg`; + case OperatingSystem.Windows: + return `privacy.sexy-Setup-${version}.exe`; + default: + throw new Error(`Unsupported os: ${OperatingSystem[os]}`); + } +} diff --git a/src/presentation/Scripts/TheScripts.vue b/src/presentation/Scripts/TheScripts.vue index e14fa7de..f657fa9a 100644 --- a/src/presentation/Scripts/TheScripts.vue +++ b/src/presentation/Scripts/TheScripts.vue @@ -74,7 +74,7 @@ public async mounted() { const state = await this.getCurrentStateAsync(); - this.repositoryUrl = state.app.repositoryUrl; + this.repositoryUrl = state.app.info.repositoryWebUrl; state.filter.filterRemoved.on(() => { this.isSearching = false; }); diff --git a/src/presentation/TheFooter/DownloadUrlList.vue b/src/presentation/TheFooter/DownloadUrlList.vue index 54a74620..230c5a1a 100644 --- a/src/presentation/TheFooter/DownloadUrlList.vue +++ b/src/presentation/TheFooter/DownloadUrlList.vue @@ -17,7 +17,7 @@