refactor to read more from package.json
This commit is contained in:
@@ -3,7 +3,12 @@
|
|||||||
"version": "0.7.5",
|
"version": "0.7.5",
|
||||||
"author": "undergroundwires",
|
"author": "undergroundwires",
|
||||||
"description": "Enforce privacy & security best-practices on Windows, because privacy is sexy 🍑🍆",
|
"description": "Enforce privacy & security best-practices on Windows, because privacy is sexy 🍑🍆",
|
||||||
|
"homepage": "https://privacy.sexy",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/undergroundwires/privacy.sexy.git"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
"build": "vue-cli-service build",
|
"build": "vue-cli-service build",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { OperatingSystem } from '../OperatingSystem';
|
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||||
import { DetectorBuilder } from './DetectorBuilder';
|
import { DetectorBuilder } from './DetectorBuilder';
|
||||||
import { IBrowserOsDetector } from './IBrowserOsDetector';
|
import { IBrowserOsDetector } from './IBrowserOsDetector';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { IBrowserOsDetector } from './IBrowserOsDetector';
|
import { IBrowserOsDetector } from './IBrowserOsDetector';
|
||||||
import { OperatingSystem } from '../OperatingSystem';
|
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||||
|
|
||||||
export class DetectorBuilder {
|
export class DetectorBuilder {
|
||||||
private readonly existingPartsInUserAgent = new Array<string>();
|
private readonly existingPartsInUserAgent = new Array<string>();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { OperatingSystem } from '../OperatingSystem';
|
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||||
|
|
||||||
export interface IBrowserOsDetector {
|
export interface IBrowserOsDetector {
|
||||||
detect(userAgent: string): OperatingSystem;
|
detect(userAgent: string): OperatingSystem;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { BrowserOsDetector } from './BrowserOs/BrowserOsDetector';
|
import { BrowserOsDetector } from './BrowserOs/BrowserOsDetector';
|
||||||
import { IBrowserOsDetector } from './BrowserOs/IBrowserOsDetector';
|
import { IBrowserOsDetector } from './BrowserOs/IBrowserOsDetector';
|
||||||
import { IEnvironment } from './IEnvironment';
|
import { IEnvironment } from './IEnvironment';
|
||||||
import { OperatingSystem } from './OperatingSystem';
|
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||||
|
|
||||||
interface IEnvironmentVariables {
|
interface IEnvironmentVariables {
|
||||||
readonly window: Window & typeof globalThis;
|
readonly window: Window & typeof globalThis;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { OperatingSystem } from './OperatingSystem';
|
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||||
|
|
||||||
export interface IEnvironment {
|
export interface IEnvironment {
|
||||||
isDesktop: boolean;
|
isDesktop: boolean;
|
||||||
|
|||||||
@@ -1,24 +1,35 @@
|
|||||||
import { Category } from '@/domain/Category';
|
import { Category } from '@/domain/Category';
|
||||||
import { Application } from '@/domain/Application';
|
import { Application } from '@/domain/Application';
|
||||||
import { IApplication } from '@/domain/IApplication';
|
import { IApplication } from '@/domain/IApplication';
|
||||||
|
import { IProjectInformation } from '@/domain/IProjectInformation';
|
||||||
import { ApplicationYaml } from 'js-yaml-loader!./../application.yaml';
|
import { ApplicationYaml } from 'js-yaml-loader!./../application.yaml';
|
||||||
import { parseCategory } from './CategoryParser';
|
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);
|
validate(content);
|
||||||
const categories = new Array<Category>();
|
const categories = new Array<Category>();
|
||||||
for (const action of content.actions) {
|
for (const action of content.actions) {
|
||||||
const category = parseCategory(action);
|
const category = parseCategory(action);
|
||||||
categories.push(category);
|
categories.push(category);
|
||||||
}
|
}
|
||||||
|
const info = readAppInformation(env);
|
||||||
const app = new Application(
|
const app = new Application(
|
||||||
content.name,
|
info,
|
||||||
content.repositoryUrl,
|
|
||||||
process.env.VUE_APP_VERSION,
|
|
||||||
categories);
|
categories);
|
||||||
return app;
|
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 {
|
function validate(content: ApplicationYaml): void {
|
||||||
if (!content) {
|
if (!content) {
|
||||||
throw new Error('application is null or undefined');
|
throw new Error('application is null or undefined');
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export class ApplicationState implements IApplicationState {
|
|||||||
/** Initially selected scripts */
|
/** Initially selected scripts */
|
||||||
public readonly defaultScripts: Script[]) {
|
public readonly defaultScripts: Script[]) {
|
||||||
this.selection = new UserSelection(app, defaultScripts.map((script) => new SelectedScript(script, false)));
|
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);
|
this.filter = new UserFilter(app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
# Structure documented in "./application.yaml.d.ts" (as code)
|
# Structure documented in "./application.yaml.d.ts" (as code)
|
||||||
name: privacy.sexy
|
|
||||||
repositoryUrl: https://github.com/undergroundwires/privacy.sexy
|
|
||||||
actions:
|
actions:
|
||||||
-
|
-
|
||||||
category: Privacy cleanup
|
category: Privacy cleanup
|
||||||
|
|||||||
2
src/application/application.yaml.d.ts
vendored
2
src/application/application.yaml.d.ts
vendored
@@ -19,8 +19,6 @@ declare module 'js-yaml-loader!*' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ApplicationYaml {
|
export interface ApplicationYaml {
|
||||||
name: string;
|
|
||||||
repositoryUrl: string;
|
|
||||||
actions: ReadonlyArray<YamlCategory>;
|
actions: ReadonlyArray<YamlCategory>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { IEntity } from '../infrastructure/Entity/IEntity';
|
|||||||
import { ICategory } from './ICategory';
|
import { ICategory } from './ICategory';
|
||||||
import { IScript } from './IScript';
|
import { IScript } from './IScript';
|
||||||
import { IApplication } from './IApplication';
|
import { IApplication } from './IApplication';
|
||||||
|
import { IProjectInformation } from './IProjectInformation';
|
||||||
|
|
||||||
export class Application implements IApplication {
|
export class Application implements IApplication {
|
||||||
public get totalScripts(): number { return this.flattened.allScripts.length; }
|
public get totalScripts(): number { return this.flattened.allScripts.length; }
|
||||||
@@ -10,13 +11,11 @@ export class Application implements IApplication {
|
|||||||
private readonly flattened: IFlattenedApplication;
|
private readonly flattened: IFlattenedApplication;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public readonly name: string,
|
public readonly info: IProjectInformation,
|
||||||
public readonly repositoryUrl: string,
|
|
||||||
public readonly version: string,
|
|
||||||
public readonly actions: ReadonlyArray<ICategory>) {
|
public readonly actions: ReadonlyArray<ICategory>) {
|
||||||
if (!name) { throw Error('Application has no name'); }
|
if (!info) {
|
||||||
if (!repositoryUrl) { throw Error('Application has no repository url'); }
|
throw new Error('info is undefined');
|
||||||
if (!version) { throw Error('Version cannot be empty'); }
|
}
|
||||||
this.flattened = flatten(actions);
|
this.flattened = flatten(actions);
|
||||||
ensureValid(this.flattened);
|
ensureValid(this.flattened);
|
||||||
ensureNoDuplicates(this.flattened.allCategories);
|
ensureNoDuplicates(this.flattened.allCategories);
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { IScript } from '@/domain/IScript';
|
import { IScript } from '@/domain/IScript';
|
||||||
import { ICategory } from '@/domain/ICategory';
|
import { ICategory } from '@/domain/ICategory';
|
||||||
|
import { IProjectInformation } from './IProjectInformation';
|
||||||
|
|
||||||
export interface IApplication {
|
export interface IApplication {
|
||||||
readonly name: string;
|
readonly info: IProjectInformation;
|
||||||
readonly repositoryUrl: string;
|
|
||||||
readonly version: string;
|
|
||||||
readonly totalScripts: number;
|
readonly totalScripts: number;
|
||||||
readonly totalCategories: number;
|
readonly totalCategories: number;
|
||||||
readonly actions: ReadonlyArray<ICategory>;
|
readonly actions: ReadonlyArray<ICategory>;
|
||||||
|
|||||||
11
src/domain/IProjectInformation.ts
Normal file
11
src/domain/IProjectInformation.ts
Normal file
@@ -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;
|
||||||
|
}
|
||||||
55
src/domain/ProjectInformation.ts
Normal file
55
src/domain/ProjectInformation.ts
Normal file
@@ -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]}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
|
|
||||||
public async mounted() {
|
public async mounted() {
|
||||||
const state = await this.getCurrentStateAsync();
|
const state = await this.getCurrentStateAsync();
|
||||||
this.repositoryUrl = state.app.repositoryUrl;
|
this.repositoryUrl = state.app.info.repositoryWebUrl;
|
||||||
state.filter.filterRemoved.on(() => {
|
state.filter.filterRemoved.on(() => {
|
||||||
this.isSearching = false;
|
this.isSearching = false;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Vue } from 'vue-property-decorator';
|
import { Component, Vue } from 'vue-property-decorator';
|
||||||
import { Environment } from '@/application/Environment/Environment';
|
import { Environment } from '@/application/Environment/Environment';
|
||||||
import { OperatingSystem } from '@/application/Environment/OperatingSystem';
|
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||||
import DownloadUrlListItem from './DownloadUrlListItem.vue';
|
import DownloadUrlListItem from './DownloadUrlListItem.vue';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
import { Component, Prop, Watch } from 'vue-property-decorator';
|
import { Component, Prop, Watch } from 'vue-property-decorator';
|
||||||
import { StatefulVue } from '@/presentation/StatefulVue';
|
import { StatefulVue } from '@/presentation/StatefulVue';
|
||||||
import { Environment } from '@/application/Environment/Environment';
|
import { Environment } from '@/application/Environment/Environment';
|
||||||
import { OperatingSystem } from '@/application/Environment/OperatingSystem';
|
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
export default class DownloadUrlListItem extends StatefulVue {
|
export default class DownloadUrlListItem extends StatefulVue {
|
||||||
@@ -39,7 +39,7 @@ export default class DownloadUrlListItem extends StatefulVue {
|
|||||||
|
|
||||||
private async getDownloadUrlAsync(os: OperatingSystem): Promise<string> {
|
private async getDownloadUrlAsync(os: OperatingSystem): Promise<string> {
|
||||||
const state = await this.getCurrentStateAsync();
|
const state = await this.getCurrentStateAsync();
|
||||||
return `${state.app.repositoryUrl}/releases/download/${state.app.version}/${getFileName(os, state.app.version)}`;
|
return state.app.info.getDownloadUrl(os);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,18 +62,6 @@ function getOperatingSystemName(os: OperatingSystem): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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]}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ export default class TheFooter extends StatefulVue {
|
|||||||
|
|
||||||
public async mounted() {
|
public async mounted() {
|
||||||
const state = await this.getCurrentStateAsync();
|
const state = await this.getCurrentStateAsync();
|
||||||
this.repositoryUrl = state.app.repositoryUrl;
|
this.repositoryUrl = state.app.info.repositoryWebUrl;
|
||||||
this.feedbackUrl = `${state.app.repositoryUrl}/issues`;
|
this.feedbackUrl = state.app.info.feedbackUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="footer__section">
|
<div class="footer__section">
|
||||||
<span v-if="isDesktop" class="footer__section__item">
|
<span v-if="isDesktop" class="footer__section__item">
|
||||||
<font-awesome-icon class="icon" :icon="['fas', 'globe']" />
|
<font-awesome-icon class="icon" :icon="['fas', 'globe']" />
|
||||||
<span>Online version at <a href="https://privacy.sexy" target="_blank">https://privacy.sexy</a></span>
|
<span>Online version at <a :href="homepageUrl" target="_blank">{{ homepageUrl }}</a></span>
|
||||||
</span>
|
</span>
|
||||||
<span v-else class="footer__section__item">
|
<span v-else class="footer__section__item">
|
||||||
<DownloadUrlList />
|
<DownloadUrlList />
|
||||||
@@ -66,6 +66,7 @@ export default class TheFooter extends StatefulVue {
|
|||||||
public repositoryUrl: string = '';
|
public repositoryUrl: string = '';
|
||||||
public releaseUrl: string = '';
|
public releaseUrl: string = '';
|
||||||
public feedbackUrl: string = '';
|
public feedbackUrl: string = '';
|
||||||
|
public homepageUrl: string = '';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@@ -74,12 +75,15 @@ export default class TheFooter extends StatefulVue {
|
|||||||
|
|
||||||
public async mounted() {
|
public async mounted() {
|
||||||
const state = await this.getCurrentStateAsync();
|
const state = await this.getCurrentStateAsync();
|
||||||
this.version = state.app.version;
|
const info = state.app.info;
|
||||||
this.repositoryUrl = state.app.repositoryUrl;
|
this.version = info.version;
|
||||||
this.releaseUrl = `${state.app.repositoryUrl}/releases/tag/${state.app.version}`;
|
this.homepageUrl = info.homepage;
|
||||||
this.feedbackUrl = `${state.app.repositoryUrl}/issues`;
|
this.repositoryUrl = info.repositoryWebUrl;
|
||||||
|
this.releaseUrl = info.releaseUrl;
|
||||||
|
this.feedbackUrl = info.feedbackUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export default class TheHeader extends StatefulVue {
|
|||||||
|
|
||||||
public async mounted() {
|
public async mounted() {
|
||||||
const state = await this.getCurrentStateAsync();
|
const state = await this.getCurrentStateAsync();
|
||||||
this.title = state.app.name;
|
this.title = state.app.info.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { OperatingSystem } from '@/application/Environment/OperatingSystem';
|
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||||
import { BrowserOsDetector } from '@/application/Environment/BrowserOs/BrowserOsDetector';
|
import { BrowserOsDetector } from '@/application/Environment/BrowserOs/BrowserOsDetector';
|
||||||
import { BrowserOsTestCases } from './BrowserOsTestCases';
|
import { BrowserOsTestCases } from './BrowserOsTestCases';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { OperatingSystem } from '@/application/Environment/OperatingSystem';
|
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||||
|
|
||||||
interface IBrowserOsTestCase {
|
interface IBrowserOsTestCase {
|
||||||
userAgent: string;
|
userAgent: string;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { OperatingSystem } from '@/application/Environment/OperatingSystem';
|
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||||
|
|
||||||
interface IDesktopTestCase {
|
interface IDesktopTestCase {
|
||||||
processPlatform: string;
|
processPlatform: string;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { IBrowserOsDetector } from '@/application/Environment/BrowserOs/IBrowserOsDetector';
|
import { IBrowserOsDetector } from '@/application/Environment/BrowserOs/IBrowserOsDetector';
|
||||||
import { OperatingSystem } from '@/application/Environment/OperatingSystem';
|
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||||
import { DesktopOsTestCases } from './DesktopOsTestCases';
|
import { DesktopOsTestCases } from './DesktopOsTestCases';
|
||||||
import { Environment } from '@/application/Environment/Environment';
|
import { Environment } from '@/application/Environment/Environment';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ import 'mocha';
|
|||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { parseCategory } from '@/application/Parser/CategoryParser';
|
import { parseCategory } from '@/application/Parser/CategoryParser';
|
||||||
|
|
||||||
declare var process;
|
|
||||||
|
|
||||||
describe('ApplicationParser', () => {
|
describe('ApplicationParser', () => {
|
||||||
describe('parseApplication', () => {
|
describe('parseApplication', () => {
|
||||||
it('can parse current application file', () => {
|
it('can parse current application file', () => {
|
||||||
@@ -16,74 +14,64 @@ describe('ApplicationParser', () => {
|
|||||||
expect(() => parseApplication(undefined)).to.throw('application is null or undefined');
|
expect(() => parseApplication(undefined)).to.throw('application is null or undefined');
|
||||||
});
|
});
|
||||||
it('throws when undefined actions', () => {
|
it('throws when undefined actions', () => {
|
||||||
const sut: ApplicationYaml = {
|
const sut: ApplicationYaml = { actions: undefined };
|
||||||
name: 'test',
|
|
||||||
repositoryUrl: 'https://privacy.sexy',
|
|
||||||
actions: undefined,
|
|
||||||
};
|
|
||||||
expect(() => parseApplication(sut)).to.throw('application does not define any action');
|
expect(() => parseApplication(sut)).to.throw('application does not define any action');
|
||||||
});
|
});
|
||||||
it('throws when has no actions', () => {
|
it('throws when has no actions', () => {
|
||||||
const sut: ApplicationYaml = {
|
const sut: ApplicationYaml = { actions: [] };
|
||||||
name: 'test',
|
|
||||||
repositoryUrl: 'https://privacy.sexy',
|
|
||||||
actions: [],
|
|
||||||
};
|
|
||||||
expect(() => parseApplication(sut)).to.throw('application does not define any action');
|
expect(() => parseApplication(sut)).to.throw('application does not define any action');
|
||||||
});
|
});
|
||||||
it('returns expected name', () => {
|
describe('information', () => {
|
||||||
// arrange
|
it('returns expected repository version', () => {
|
||||||
const expected = 'test-app-name';
|
// arrange
|
||||||
const sut: ApplicationYaml = {
|
const expected = 'expected-version';
|
||||||
name: expected,
|
const env = getProcessEnvironmentStub();
|
||||||
repositoryUrl: 'https://privacy.sexy',
|
env.VUE_APP_VERSION = expected;
|
||||||
actions: [ getTestCategory() ],
|
const sut: ApplicationYaml = { actions: [ getTestCategory() ] };
|
||||||
};
|
// act
|
||||||
// act
|
const actual = parseApplication(sut, env).info.version;
|
||||||
const actual = parseApplication(sut).name;
|
// assert
|
||||||
// assert
|
expect(actual).to.be.equal(expected);
|
||||||
expect(actual).to.be.equal(actual);
|
});
|
||||||
});
|
it('returns expected repository url', () => {
|
||||||
it('returns expected repository url', () => {
|
// arrange
|
||||||
// arrange
|
const expected = 'https://expected-repository.url';
|
||||||
const expected = 'https://privacy.sexy';
|
const env = getProcessEnvironmentStub();
|
||||||
const sut: ApplicationYaml = {
|
env.VUE_APP_REPOSITORY_URL = expected;
|
||||||
name: 'name',
|
const sut: ApplicationYaml = { actions: [ getTestCategory() ] };
|
||||||
repositoryUrl: expected,
|
// act
|
||||||
actions: [ getTestCategory() ],
|
const actual = parseApplication(sut, env).info.repositoryUrl;
|
||||||
};
|
// assert
|
||||||
// act
|
expect(actual).to.be.equal(expected);
|
||||||
const actual = parseApplication(sut).repositoryUrl;
|
});
|
||||||
// assert
|
it('returns expected name', () => {
|
||||||
expect(actual).to.be.equal(actual);
|
// arrange
|
||||||
});
|
const expected = 'expected-app-name';
|
||||||
it('returns expected repository version', () => {
|
const env = getProcessEnvironmentStub();
|
||||||
// arrange
|
env.VUE_APP_NAME = expected;
|
||||||
const expected = '1.0.0';
|
const sut: ApplicationYaml = { actions: [ getTestCategory() ] };
|
||||||
process = {
|
// act
|
||||||
env: {
|
const actual = parseApplication(sut, env).info.name;
|
||||||
VUE_APP_VERSION: expected,
|
// assert
|
||||||
},
|
expect(actual).to.be.equal(expected);
|
||||||
};
|
});
|
||||||
const sut: ApplicationYaml = {
|
it('returns expected homepage url', () => {
|
||||||
name: 'name',
|
// arrange
|
||||||
repositoryUrl: 'https://privacy.sexy',
|
const expected = 'https://expected.sexy';
|
||||||
actions: [ getTestCategory() ],
|
const env = getProcessEnvironmentStub();
|
||||||
};
|
env.VUE_APP_HOMEPAGE_URL = expected;
|
||||||
// act
|
const sut: ApplicationYaml = { actions: [ getTestCategory() ] };
|
||||||
const actual = parseApplication(sut).version;
|
// act
|
||||||
// assert
|
const actual = parseApplication(sut, env).info.homepage;
|
||||||
expect(actual).to.be.equal(actual);
|
// assert
|
||||||
|
expect(actual).to.be.equal(expected);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('parses actions', () => {
|
it('parses actions', () => {
|
||||||
// arrange
|
// arrange
|
||||||
const actions = [ getTestCategory('test1'), getTestCategory('test2') ];
|
const actions = [ getTestCategory('test1'), getTestCategory('test2') ];
|
||||||
const expected = [ parseCategory(actions[0]), parseCategory(actions[1]) ];
|
const expected = [ parseCategory(actions[0]), parseCategory(actions[1]) ];
|
||||||
const sut: ApplicationYaml = {
|
const sut: ApplicationYaml = { actions };
|
||||||
name: 'name',
|
|
||||||
repositoryUrl: 'https://privacy.sexy',
|
|
||||||
actions,
|
|
||||||
};
|
|
||||||
// act
|
// act
|
||||||
const actual = parseApplication(sut).actions;
|
const actual = parseApplication(sut).actions;
|
||||||
// assert
|
// assert
|
||||||
@@ -113,3 +101,12 @@ function getTestScript(scriptName: string): YamlScript {
|
|||||||
recommend: true,
|
recommend: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getProcessEnvironmentStub(): NodeJS.ProcessEnv {
|
||||||
|
return {
|
||||||
|
VUE_APP_VERSION: 'stub-version',
|
||||||
|
VUE_APP_NAME: 'stub-name',
|
||||||
|
VUE_APP_REPOSITORY_URL: 'stub-repository-url',
|
||||||
|
VUE_APP_HOMEPAGE_URL: 'stub-homepage-url',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { ScriptStub } from './../stubs/ScriptStub';
|
import { ScriptStub } from './../stubs/ScriptStub';
|
||||||
import { CategoryStub } from './../stubs/CategoryStub';
|
import { CategoryStub } from './../stubs/CategoryStub';
|
||||||
import { Application } from './../../../src/domain/Application';
|
import { Application } from '@/domain/Application';
|
||||||
import 'mocha';
|
import 'mocha';
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
import { ProjectInformation } from '@/domain/ProjectInformation';
|
||||||
|
import { IProjectInformation } from '@/domain/IProjectInformation';
|
||||||
|
|
||||||
describe('Application', () => {
|
describe('Application', () => {
|
||||||
it('getRecommendedScripts returns as expected', () => {
|
it('getRecommendedScripts returns as expected', () => {
|
||||||
@@ -11,53 +13,56 @@ describe('Application', () => {
|
|||||||
new ScriptStub('S3').withIsRecommended(true),
|
new ScriptStub('S3').withIsRecommended(true),
|
||||||
new ScriptStub('S4').withIsRecommended(true),
|
new ScriptStub('S4').withIsRecommended(true),
|
||||||
];
|
];
|
||||||
const sut = new Application('name', 'repo', '0.1.0', [
|
const sut = new Application(createInformation(), [
|
||||||
new CategoryStub(3).withScripts(expected[0], new ScriptStub('S1').withIsRecommended(false)),
|
new CategoryStub(3).withScripts(expected[0], new ScriptStub('S1').withIsRecommended(false)),
|
||||||
new CategoryStub(2).withScripts(expected[1], new ScriptStub('S2').withIsRecommended(false)),
|
new CategoryStub(2).withScripts(expected[1], new ScriptStub('S2').withIsRecommended(false)),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
const actual = sut.getRecommendedScripts();
|
const actual = sut.getRecommendedScripts();
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
expect(expected[0]).to.deep.equal(actual[0]);
|
expect(expected[0]).to.deep.equal(actual[0]);
|
||||||
expect(expected[1]).to.deep.equal(actual[1]);
|
expect(expected[1]).to.deep.equal(actual[1]);
|
||||||
});
|
});
|
||||||
it('cannot construct without categories', () => {
|
describe('parameter validation', () => {
|
||||||
// arrange
|
it('cannot construct without categories', () => {
|
||||||
const categories = [];
|
// arrange
|
||||||
|
const categories = [];
|
||||||
// act
|
// act
|
||||||
function construct() { return new Application('name', 'repo', '0.1.0', categories); }
|
function construct() { return new Application(createInformation(), categories); }
|
||||||
|
// assert
|
||||||
// assert
|
expect(construct).to.throw('Application must consist of at least one category');
|
||||||
expect(construct).to.throw('Application must consist of at least one category');
|
});
|
||||||
});
|
it('cannot construct without scripts', () => {
|
||||||
it('cannot construct without scripts', () => {
|
// arrange
|
||||||
// arrange
|
const categories = [
|
||||||
const categories = [
|
new CategoryStub(3),
|
||||||
new CategoryStub(3),
|
new CategoryStub(2),
|
||||||
new CategoryStub(2),
|
];
|
||||||
];
|
// act
|
||||||
|
function construct() { return new Application(createInformation(), categories); }
|
||||||
// act
|
// assert
|
||||||
function construct() { return new Application('name', 'repo', '0.1.0', categories); }
|
expect(construct).to.throw('Application must consist of at least one script');
|
||||||
|
});
|
||||||
// assert
|
it('cannot construct without any recommended scripts', () => {
|
||||||
expect(construct).to.throw('Application must consist of at least one script');
|
// arrange
|
||||||
});
|
const categories = [
|
||||||
it('cannot construct without any recommended scripts', () => {
|
new CategoryStub(3).withScripts(new ScriptStub('S1').withIsRecommended(false)),
|
||||||
// arrange
|
new CategoryStub(2).withScripts(new ScriptStub('S2').withIsRecommended(false)),
|
||||||
const categories = [
|
];
|
||||||
new CategoryStub(3).withScripts(new ScriptStub('S1').withIsRecommended(false)),
|
// act
|
||||||
new CategoryStub(2).withScripts(new ScriptStub('S2').withIsRecommended(false)),
|
function construct() { return new Application(createInformation(), categories); }
|
||||||
];
|
// assert
|
||||||
|
expect(construct).to.throw('Application must consist of at least one recommended script');
|
||||||
// act
|
});
|
||||||
function construct() { return new Application('name', 'repo', '0.1.0', categories); }
|
it('cannot construct without information', () => {
|
||||||
|
// arrange
|
||||||
// assert
|
const categories = [new CategoryStub(1).withScripts(new ScriptStub('S1').withIsRecommended(true))];
|
||||||
expect(construct).to.throw('Application must consist of at least one recommended script');
|
const information = undefined;
|
||||||
|
// act
|
||||||
|
function construct() { return new Application(information, categories); }
|
||||||
|
// assert
|
||||||
|
expect(construct).to.throw('info is undefined');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('totalScripts counts right', () => {
|
it('totalScripts counts right', () => {
|
||||||
// arrange
|
// arrange
|
||||||
@@ -67,9 +72,9 @@ describe('Application', () => {
|
|||||||
new CategoryStub(3).withCategories(new CategoryStub(4).withScripts(new ScriptStub('S4'))),
|
new CategoryStub(3).withCategories(new CategoryStub(4).withScripts(new ScriptStub('S4'))),
|
||||||
];
|
];
|
||||||
// act
|
// act
|
||||||
const application = new Application('name', 'repo', '0.1.0', categories);
|
const sut = new Application(createInformation(), categories);
|
||||||
// assert
|
// assert
|
||||||
expect(application.totalScripts).to.equal(4);
|
expect(sut.totalScripts).to.equal(4);
|
||||||
});
|
});
|
||||||
it('totalCategories counts right', () => {
|
it('totalCategories counts right', () => {
|
||||||
// arrange
|
// arrange
|
||||||
@@ -79,8 +84,22 @@ describe('Application', () => {
|
|||||||
new CategoryStub(3).withCategories(new CategoryStub(4).withScripts(new ScriptStub('S4'))),
|
new CategoryStub(3).withCategories(new CategoryStub(4).withScripts(new ScriptStub('S4'))),
|
||||||
];
|
];
|
||||||
// act
|
// act
|
||||||
const application = new Application('name', 'repo', '0.1.0', categories);
|
const sut = new Application(createInformation(), categories);
|
||||||
// assert
|
// assert
|
||||||
expect(application.totalCategories).to.equal(4);
|
expect(sut.totalCategories).to.equal(4);
|
||||||
|
});
|
||||||
|
it('sets information as expected', () => {
|
||||||
|
// arrange
|
||||||
|
const expected = createInformation();
|
||||||
|
// act
|
||||||
|
const sut = new Application(
|
||||||
|
expected,
|
||||||
|
[new CategoryStub(1).withScripts(new ScriptStub('S1').withIsRecommended(true))]);
|
||||||
|
// assert
|
||||||
|
expect(sut.info).to.deep.equal(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function createInformation(): IProjectInformation {
|
||||||
|
return new ProjectInformation('name', 'repo', '0.1.0', 'homepage');
|
||||||
|
}
|
||||||
|
|||||||
128
tests/unit/domain/ProjectInformation.spec.ts
Normal file
128
tests/unit/domain/ProjectInformation.spec.ts
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
import 'mocha';
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { ProjectInformation } from '@/domain/ProjectInformation';
|
||||||
|
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||||
|
|
||||||
|
describe('ProjectInformation', () => {
|
||||||
|
it('sets name as expected', () => {
|
||||||
|
// arrange
|
||||||
|
const expected = 'expected-name';
|
||||||
|
const sut = new ProjectInformation(expected, 'version', 'repositoryUrl', 'homepage');
|
||||||
|
// act
|
||||||
|
const actual = sut.name;
|
||||||
|
// assert
|
||||||
|
expect(actual).to.equal(expected);
|
||||||
|
});
|
||||||
|
it('sets version as expected', () => {
|
||||||
|
// arrange
|
||||||
|
const expected = 'expected-version';
|
||||||
|
const sut = new ProjectInformation('name', expected, 'repositoryUrl', 'homepage');
|
||||||
|
// act
|
||||||
|
const actual = sut.version;
|
||||||
|
// assert
|
||||||
|
expect(actual).to.equal(expected);
|
||||||
|
});
|
||||||
|
it('sets repositoryUrl as expected', () => {
|
||||||
|
// arrange
|
||||||
|
const expected = 'expected-repository-url';
|
||||||
|
const sut = new ProjectInformation('name', 'version', expected, 'homepage');
|
||||||
|
// act
|
||||||
|
const actual = sut.repositoryUrl;
|
||||||
|
// assert
|
||||||
|
expect(actual).to.equal(expected);
|
||||||
|
});
|
||||||
|
describe('sets repositoryWebUrl as expected', () => {
|
||||||
|
it('sets repositoryUrl when it does not end with .git', () => {
|
||||||
|
// arrange
|
||||||
|
const expected = 'expected-repository-url';
|
||||||
|
const sut = new ProjectInformation('name', 'version', expected, 'homepage');
|
||||||
|
// act
|
||||||
|
const actual = sut.repositoryWebUrl;
|
||||||
|
// assert
|
||||||
|
expect(actual).to.equal(expected);
|
||||||
|
});
|
||||||
|
it('removes ".git" from the end when it ends with ".git"', () => {
|
||||||
|
// arrange
|
||||||
|
const expected = 'expected-repository-url';
|
||||||
|
const sut = new ProjectInformation('name', 'version', `${expected}.git`, 'homepage');
|
||||||
|
// act
|
||||||
|
const actual = sut.repositoryWebUrl;
|
||||||
|
// assert
|
||||||
|
expect(actual).to.equal(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('sets homepage as expected', () => {
|
||||||
|
// arrange
|
||||||
|
const expected = 'expected-homepage';
|
||||||
|
const sut = new ProjectInformation('name', 'version', 'repositoryUrl', expected);
|
||||||
|
// act
|
||||||
|
const actual = sut.homepage;
|
||||||
|
// assert
|
||||||
|
expect(actual).to.equal(expected);
|
||||||
|
});
|
||||||
|
it('sets feedbackUrl to github issues page', () => {
|
||||||
|
// arrange
|
||||||
|
const repositoryUrl = 'https://github.com/undergroundwires/privacy.sexy.git';
|
||||||
|
const expected = 'https://github.com/undergroundwires/privacy.sexy/issues';
|
||||||
|
const sut = new ProjectInformation('name', 'version', repositoryUrl, 'homepage');
|
||||||
|
// act
|
||||||
|
const actual = sut.feedbackUrl;
|
||||||
|
// assert
|
||||||
|
expect(actual).to.equal(expected);
|
||||||
|
});
|
||||||
|
it('sets releaseUrl to github releases page', () => {
|
||||||
|
// arrange
|
||||||
|
const repositoryUrl = 'https://github.com/undergroundwires/privacy.sexy.git';
|
||||||
|
const version = '0.7.2';
|
||||||
|
const expected = 'https://github.com/undergroundwires/privacy.sexy/releases/tag/0.7.2';
|
||||||
|
const sut = new ProjectInformation('name', version, repositoryUrl, 'homepage');
|
||||||
|
// act
|
||||||
|
const actual = sut.releaseUrl;
|
||||||
|
// assert
|
||||||
|
expect(actual).to.equal(expected);
|
||||||
|
});
|
||||||
|
describe('getDownloadUrl', () => {
|
||||||
|
it('gets expected url for macOS', () => {
|
||||||
|
// arrange
|
||||||
|
const expected = 'https://github.com/undergroundwires/privacy.sexy/releases/download/0.7.2/privacy.sexy-0.7.2.dmg';
|
||||||
|
const repositoryUrl = 'https://github.com/undergroundwires/privacy.sexy.git';
|
||||||
|
const version = '0.7.2';
|
||||||
|
const sut = new ProjectInformation('name', version, repositoryUrl, 'homepage');
|
||||||
|
// act
|
||||||
|
const actual = sut.getDownloadUrl(OperatingSystem.macOS);
|
||||||
|
// assert
|
||||||
|
expect(actual).to.equal(expected);
|
||||||
|
});
|
||||||
|
it('gets expected url for Linux', () => {
|
||||||
|
// arrange
|
||||||
|
const expected = 'https://github.com/undergroundwires/privacy.sexy/releases/download/0.7.2/privacy.sexy-0.7.2.AppImage';
|
||||||
|
const repositoryUrl = 'https://github.com/undergroundwires/privacy.sexy.git';
|
||||||
|
const version = '0.7.2';
|
||||||
|
const sut = new ProjectInformation('name', version, repositoryUrl, 'homepage');
|
||||||
|
// act
|
||||||
|
const actual = sut.getDownloadUrl(OperatingSystem.Linux);
|
||||||
|
// assert
|
||||||
|
expect(actual).to.equal(expected);
|
||||||
|
});
|
||||||
|
it('gets expected url for Windows', () => {
|
||||||
|
// arrange
|
||||||
|
const expected = 'https://github.com/undergroundwires/privacy.sexy/releases/download/0.7.2/privacy.sexy-Setup-0.7.2.exe';
|
||||||
|
const repositoryUrl = 'https://github.com/undergroundwires/privacy.sexy.git';
|
||||||
|
const version = '0.7.2';
|
||||||
|
const sut = new ProjectInformation('name', version, repositoryUrl, 'homepage');
|
||||||
|
// act
|
||||||
|
const actual = sut.getDownloadUrl(OperatingSystem.Windows);
|
||||||
|
// assert
|
||||||
|
expect(actual).to.equal(expected);
|
||||||
|
});
|
||||||
|
it('throws when OS is unknown', () => {
|
||||||
|
// arrange
|
||||||
|
const sut = new ProjectInformation('name', 'version', 'repositoryUrl', 'homepage');
|
||||||
|
const os = OperatingSystem.Unknown;
|
||||||
|
// act
|
||||||
|
const act = () => sut.getDownloadUrl(os);
|
||||||
|
// assert
|
||||||
|
expect(act).to.throw(`Unsupported os: ${OperatingSystem[os]}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
import { IApplication, ICategory, IScript } from '@/domain/IApplication';
|
import { IApplication, ICategory, IScript } from '@/domain/IApplication';
|
||||||
|
import { ProjectInformation } from '@/domain/ProjectInformation';
|
||||||
|
|
||||||
export class ApplicationStub implements IApplication {
|
export class ApplicationStub implements IApplication {
|
||||||
public totalScripts = 0;
|
public totalScripts = 0;
|
||||||
public totalCategories = 0;
|
public totalCategories = 0;
|
||||||
public readonly name = 'StubApplication';
|
public readonly info = new ProjectInformation('StubApplication', '0.1.0', 'https://github.com/undergroundwires/privacy.sexy', 'https://privacy.sexy');
|
||||||
public readonly repositoryUrl = 'https://privacy.sexy';
|
|
||||||
public readonly version = '0.1.0';
|
|
||||||
public readonly actions = new Array<ICategory>();
|
public readonly actions = new Array<ICategory>();
|
||||||
|
|
||||||
public withAction(category: ICategory): ApplicationStub {
|
public withAction(category: ICategory): ApplicationStub {
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
process.env.VUE_APP_VERSION = require('./package.json').version;
|
const packageJson = require('./package.json');
|
||||||
|
|
||||||
|
process.env.VUE_APP_VERSION = packageJson.version;
|
||||||
|
process.env.VUE_APP_NAME = packageJson.name;
|
||||||
|
process.env.VUE_APP_REPOSITORY_URL = packageJson.repository.url;
|
||||||
|
process.env.VUE_APP_HOMEPAGE_URL = packageJson.homepage;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
pluginOptions: {
|
pluginOptions: {
|
||||||
|
|||||||
Reference in New Issue
Block a user