typo fixes + whitespace refactorings

This commit is contained in:
undergroundwires
2020-01-01 12:31:41 +01:00
parent 090e831909
commit e99f210c9d
22 changed files with 148 additions and 95 deletions

View File

@@ -1,19 +1,18 @@
<template>
<div id="app">
<div id="app">
<div class="wrapper">
<TheHeader
class="row"
github-url="https://github.com/undergroundwires/privacy.sexy"/>
<TheHeader class="row"
github-url="https://github.com/undergroundwires/privacy.sexy" />
<!-- <TheSearchBar> </TheSearchBar> -->
<!-- <div style="display: flex; justify-content: space-between;"> -->
<!-- <TheGrouper></TheGrouper> -->
<!-- <TheGrouper></TheGrouper> -->
<TheSelector class="row" />
<!-- </div> -->
<CardList />
<TheCodeArea class="row" theme="xcode"/>
<TheCodeArea class="row" theme="xcode" />
<TheCodeButtons class="row" />
</div>
</div>
</div>
</template>
<script lang="ts">

View File

@@ -26,8 +26,9 @@ export class ApplicationParser {
categories.push(category);
}
const app = new Application(name, version, categories);
return {application: app, selectedScripts};
return { application: app, selectedScripts };
}
private static categoryIdCounter = 0;
private static parseCategory(category: YamlCategory, selectedScripts: Script[]): Category {
@@ -43,9 +44,12 @@ export class ApplicationParser {
} else if (ApplicationParser.isScript(categoryOrScript)) {
const yamlScript = categoryOrScript as YamlScript;
const script = new Script(
/* name */ yamlScript.name,
/* code */ yamlScript.code,
/* docs */ this.parseDocUrls(yamlScript));
/* name */
yamlScript.name,
/* code */
yamlScript.code,
/* docs */
this.parseDocUrls(yamlScript));
subScripts.push(script);
if (yamlScript.default === true) {
selectedScripts.push(script);
@@ -56,11 +60,16 @@ export class ApplicationParser {
}
}
return new Category(
/*id*/ ApplicationParser.categoryIdCounter++,
/*name*/ category.category,
/*docs*/ this.parseDocUrls(category),
/*categories*/ subCategories,
/*scripts*/ subScripts,
/*id*/
ApplicationParser.categoryIdCounter++,
/*name*/
category.category,
/*docs*/
this.parseDocUrls(category),
/*categories*/
subCategories,
/*scripts*/
subScripts,
);
}
@@ -97,6 +106,7 @@ export class ApplicationParser {
private static isScript(categoryOrScript: any): boolean {
return categoryOrScript.code && categoryOrScript.code.length > 0;
}
private static isCategory(categoryOrScript: any): boolean {
return categoryOrScript.category && categoryOrScript.category.length > 0;
}

View File

@@ -16,7 +16,7 @@ import { IApplicationCode } from './Code/IApplicationCode';
export class ApplicationState implements IApplicationState {
/** Get singleton application state */
public static GetAsync(): Promise<IApplicationState> {
return ApplicationState.instance.getValueAsync();
return ApplicationState.instance.getValueAsync();
}
/** Application instance with all scripts. */
@@ -36,10 +36,10 @@ export class ApplicationState implements IApplicationState {
private readonly app: Application,
/** Initially selected scripts */
public readonly defaultScripts: Script[]) {
this.selection = new UserSelection(app, defaultScripts);
this.code = new ApplicationCode(this.selection, app.version.toString());
this.filter = new UserFilter(app);
}
this.selection = new UserSelection(app, defaultScripts);
this.code = new ApplicationCode(this.selection, app.version.toString());
this.filter = new UserFilter(app);
}
public getCategory(categoryId: number): ICategory | undefined {
return this.app.findCategory(categoryId);

View File

@@ -2,17 +2,19 @@ import { FunctionRenderer } from './FunctionRenderer';
export class AdminRightsFunctionRenderer {
private readonly functionRenderer: FunctionRenderer;
constructor() {
this.functionRenderer = new FunctionRenderer();
}
public renderAdminRightsFunction() {
const name = 'Ensure admin priviliges';
const name = 'Ensure admin privileges';
const code = 'fltmc >nul 2>&1 || (\n' +
' echo This batch script requires administrator privileges. Right-click on\n' +
' echo the script and select "Run as administrator".\n' +
' pause\n' +
' exit 1\n' +
')';
' echo This batch script requires administrator privileges. Right-click on\n' +
' echo the script and select "Run as administrator".\n' +
' pause\n' +
' exit 1\n' +
')';
return this.functionRenderer.renderFunction(name, code);
}
}

View File

@@ -2,15 +2,17 @@ import { CodeRenderer } from './CodeRenderer';
export class AsciiArtRenderer extends CodeRenderer {
public renderAsciiArt(version: string): string {
if (!version) { throw new Error('Version is not defined'); }
if (!version) {
throw new Error('Version is not defined');
}
return (
'██████╗ ██████╗ ██╗██╗ ██╗ █████╗ ██████╗██╗ ██╗███████╗███████╗██╗ ██╗██╗ ██╗\n' +
'██╔══██╗██╔══██╗██║██║ ██║██╔══██╗██╔════╝╚██╗ ██╔╝██╔════╝██╔════╝╚██╗██╔╝╚██╗ ██╔╝\n' +
'██████╔╝██████╔╝██║██║ ██║███████║██║ ╚████╔╝ ███████╗█████╗ ╚███╔╝ ╚████╔╝ \n' +
'██╔═══╝ ██╔══██╗██║╚██╗ ██╔╝██╔══██║██║ ╚██╔╝ ╚════██║██╔══╝ ██╔██╗ ╚██╔╝ \n' +
'██║ ██║ ██║██║ ╚████╔╝ ██║ ██║╚██████╗ ██║██╗███████║███████╗██╔╝ ██╗ ██║ \n' +
'╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═╝ ')
.split('\n').map((line) => this.renderComment(line)).join('\n')
+ `\n${this.renderComment(`https://privacy.sexy — v${version}${new Date().toUTCString()}`)}`;
'██████╗ ██████╗ ██╗██╗ ██╗ █████╗ ██████╗██╗ ██╗███████╗███████╗██╗ ██╗██╗ ██╗\n' +
'██╔══██╗██╔══██╗██║██║ ██║██╔══██╗██╔════╝╚██╗ ██╔╝██╔════╝██╔════╝╚██╗██╔╝╚██╗ ██╔╝\n' +
'██████╔╝██████╔╝██║██║ ██║███████║██║ ╚████╔╝ ███████╗█████╗ ╚███╔╝ ╚████╔╝ \n' +
'██╔═══╝ ██╔══██╗██║╚██╗ ██╔╝██╔══██║██║ ╚██╔╝ ╚════██║██╔══╝ ██╔██╗ ╚██╔╝ \n' +
'██║ ██║ ██║██║ ╚████╔╝ ██║ ██║╚██████╗ ██║██╗███████║███████╗██╔╝ ██╗ ██║ \n' +
'╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝╚═╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═╝ ')
.split('\n').map((line) => this.renderComment(line)).join('\n') +
`\n${this.renderComment(`https://privacy.sexy — v${version}${new Date().toUTCString()}`)}`;
}
}

View File

@@ -20,9 +20,9 @@ export class FunctionRenderer extends CodeRenderer {
}
private renderFunctionName(functionName: string) {
const autoFirstHypens = '-'.repeat(Math.floor((this.totalFunctionSeparatorChars - functionName.length) / 2));
const secondHypens = '-'.repeat(Math.ceil((this.totalFunctionSeparatorChars - functionName.length) / 2));
return `${this.renderComment()}${autoFirstHypens}${functionName}${secondHypens}`;
const firstHyphens = '-'.repeat(Math.floor((this.totalFunctionSeparatorChars - functionName.length) / 2));
const secondHyphens = '-'.repeat(Math.ceil((this.totalFunctionSeparatorChars - functionName.length) / 2));
return `${this.renderComment()}${firstHyphens}${functionName}${secondHyphens}`;
}
private renderFunctionEndComment(): string {

View File

@@ -16,8 +16,8 @@ export class UserFilter implements IUserFilter {
throw new Error('Filter must be defined and not empty. Use removeFilter() to remove the filter');
}
const filteredScripts = this.application.getAllScripts().filter(
(script) => script.name.toLowerCase().includes(filter.toLowerCase())
|| script.code.toLowerCase().includes(filter.toLowerCase()));
(script) => script.name.toLowerCase().includes(filter.toLowerCase()) ||
script.code.toLowerCase().includes(filter.toLowerCase()));
const matches: IFilterMatches = {
scriptMatches: filteredScripts,

View File

@@ -18,4 +18,3 @@ export interface IApplicationState {
readonly defaultScripts: ReadonlyArray<IScript>;
getCategory(categoryId: number): ICategory | undefined;
}

View File

@@ -1,23 +1,28 @@
declare module 'js-yaml-loader!*' {
type CategoryOrScript = YamlCategory | YamlScript;
type DocumentationUrls = ReadonlyArray<string> | string;
export interface YamlDocumentable {
docs?: DocumentationUrls;
}
export interface YamlScript extends YamlDocumentable {
name: string;
code: string;
default: boolean;
}
export interface YamlCategory extends YamlDocumentable {
children: ReadonlyArray<CategoryOrScript>;
category: string;
}
interface ApplicationYaml {
name: string;
version: number;
actions: ReadonlyArray<YamlCategory>;
}
const content: ApplicationYaml;
export default content;
}

View File

@@ -9,6 +9,7 @@ export class Application implements IApplication {
throw new Error('an application must consist of at least one category');
}
}
/**
* Checks all categories against duplicates, throws exception if it find any duplicates
* @return {number} Total unique categories
@@ -17,6 +18,7 @@ export class Application implements IApplication {
private static mustNotHaveDuplicatedCategories(categories: ReadonlyArray<ICategory>): number {
return Application.ensureNoDuplicateEntities(categories, Application.visitAllCategoriesOnce);
}
/**
* Checks all scripts against duplicates, throws exception if it find any scripts duplicates total scripts.
* @return {number} Total unique scripts
@@ -24,6 +26,7 @@ export class Application implements IApplication {
private static mustNotHaveDuplicatedScripts(categories: ReadonlyArray<ICategory>): number {
return Application.ensureNoDuplicateEntities(categories, Application.visitAllScriptsOnce);
}
/**
* Checks entities against duplicates using a visit function, throws exception if it find any duplicates.
* @return {number} Result from the visit function
@@ -35,8 +38,8 @@ export class Application implements IApplication {
const totalOccurencesById = new Map<TKey, number>();
const totalVisited = visitFunction(categories,
(entity) =>
totalOccurencesById.set(entity.id,
(totalOccurencesById.get(entity.id) || 0) + 1));
totalOccurencesById.set(entity.id,
(totalOccurencesById.get(entity.id) || 0) + 1));
const duplicatedIds = new Array<TKey>();
totalOccurencesById.forEach((count, id) => {
if (count > 1) {
@@ -50,34 +53,41 @@ export class Application implements IApplication {
}
return totalVisited;
}
// Runs handler on each category and returns sum of total visited categories
private static visitAllCategoriesOnce(
categories: ReadonlyArray<ICategory>, handler: (category: ICategory) => any): number {
categories: ReadonlyArray<ICategory>,
handler: (category: ICategory) => any): number {
let total = 0;
for (const category of categories) {
handler(category);
total++;
if (category.subCategories && category.subCategories.length > 0) {
total += Application.visitAllCategoriesOnce(
category.subCategories as ReadonlyArray<ICategory>, handler);
category.subCategories as ReadonlyArray<ICategory>,
handler);
}
}
return total;
}
// Runs handler on each script and returns sum of total visited scripts
private static visitAllScriptsOnce(
categories: ReadonlyArray<ICategory>, handler: (script: IScript) => any): number {
categories: ReadonlyArray<ICategory>,
handler: (script: IScript) => any): number {
let total = 0;
Application.visitAllCategoriesOnce(categories, (category) => {
if (category.scripts) {
for (const script of category.scripts) {
handler(script);
total++;
Application.visitAllCategoriesOnce(categories,
(category) => {
if (category.scripts) {
for (const script of category.scripts) {
handler(script);
total++;
}
}
}
});
});
return total;
}
public readonly totalScripts: number;
public readonly totalCategories: number;
@@ -92,27 +102,32 @@ export class Application implements IApplication {
public findCategory(categoryId: number): ICategory | undefined {
let result: ICategory | undefined;
Application.visitAllCategoriesOnce(this.categories, (category) => {
if (category.id === categoryId) {
result = category;
}
});
Application.visitAllCategoriesOnce(this.categories,
(category) => {
if (category.id === categoryId) {
result = category;
}
});
return result;
}
public findScript(scriptId: string): IScript | undefined {
let result: IScript | undefined;
Application.visitAllScriptsOnce(this.categories, (script) => {
if (script.id === scriptId) {
result = script;
}
});
Application.visitAllScriptsOnce(this.categories,
(script) => {
if (script.id === scriptId) {
result = script;
}
});
return result;
}
public getAllScripts(): IScript[] {
const result = new Array<IScript>();
Application.visitAllScriptsOnce(this.categories, (script) => {
result.push(script);
});
Application.visitAllScriptsOnce(this.categories,
(script) => {
result.push(script);
});
return result;
}
}

View File

@@ -7,8 +7,8 @@ export class Category extends BaseEntity<number> implements ICategory {
if (!category.name) {
throw new Error('name is null or empty');
}
if ((!category.subCategories || category.subCategories.length === 0)
&& (!category.scripts || category.scripts.length === 0)) {
if ((!category.subCategories || category.subCategories.length === 0) &&
(!category.scripts || category.scripts.length === 0)) {
throw new Error('A category must have at least one sub-category or scripts');
}
}

21
src/global.d.ts vendored
View File

@@ -1,9 +1,9 @@
// Two ways of typing other libraries: https://stackoverflow.com/a/53070501
declare module 'liquor-tree' {
import { PluginObject } from 'vue';
import { VueClass } from 'vue-class-component/lib/declarations';
// https://github.com/amsik/liquor-tree/blob/master/src/lib/Tree.js
export interface ILiquorTree {
readonly model: ReadonlyArray<ILiquorTreeExistingNode>;
@@ -14,20 +14,22 @@ declare module 'liquor-tree' {
interface ICustomLiquorTreeData {
documentationUrls: ReadonlyArray<string>;
}
/**
* Returned from Node tree view events.
* See constructor in https://github.com/amsik/liquor-tree/blob/master/src/lib/Node.js
*/
* Returned from Node tree view events.
* See constructor in https://github.com/amsik/liquor-tree/blob/master/src/lib/Node.js
*/
export interface ILiquorTreeExistingNode {
id: string;
data: ILiquorTreeNodeData;
states: ILiquorTreeNodeState | undefined;
children: ReadonlyArray<ILiquorTreeExistingNode> | undefined;
}
/**
* Sent to liquor tree to define of new nodes.
* https://github.com/amsik/liquor-tree/blob/master/src/lib/Node.js
*/
* Sent to liquor tree to define of new nodes.
* https://github.com/amsik/liquor-tree/blob/master/src/lib/Node.js
*/
export interface ILiquorTreeNewNode {
id: string;
text: string;
@@ -35,13 +37,16 @@ declare module 'liquor-tree' {
children: ReadonlyArray<ILiquorTreeNewNode> | undefined;
data: ICustomLiquorTreeData;
}
// https://github.com/amsik/liquor-tree/blob/master/src/lib/Node.js
interface ILiquorTreeNodeState {
checked: boolean;
}
interface ILiquorTreeNodeData extends ICustomLiquorTreeData {
text: string;
}
// https://github.com/amsik/liquor-tree/blob/master/src/components/TreeRoot.vue
interface ILiquorTreeOptions {
checkbox: boolean;
@@ -49,11 +54,13 @@ declare module 'liquor-tree' {
filter: ILiquorTreeFilter;
deletion(node: ILiquorTreeNewNode): boolean;
}
// https://github.com/amsik/liquor-tree/blob/master/src/components/TreeRoot.vue
interface ILiquorTreeFilter {
emptyText: string;
matcher(query: string, node: ILiquorTreeNewNode): boolean;
}
const LiquorTree: PluginObject<any> & VueClass<any>;
export default LiquorTree;
}

View File

@@ -1,14 +1,13 @@
import { IEntity } from './IEntity';
export abstract class BaseEntity<TId> implements IEntity<TId> {
constructor(public id: TId) {
protected constructor(public id: TId) {
if (typeof id !== 'number' && !id) {
throw new Error('Id cannot be null or empty');
}
}
public equals(otherId: TId): boolean {
return this.id === otherId;
}
}

View File

@@ -3,6 +3,7 @@ import { IRepository } from './IRepository';
export class InMemoryRepository<TKey, TEntity extends IEntity<TKey>> implements IRepository<TKey, TEntity> {
private readonly items: TEntity[];
constructor(items?: TEntity[]) {
this.items = items || new Array<TEntity>();
}

View File

@@ -10,7 +10,7 @@ export class SaveFileDialog {
const blob = new Blob([file], { type: fileType });
fileSaver.saveAs(blob, fileName);
} catch (e) {
window.open('data:' + fileType + ',' + encodeURIComponent(file.toString()), '_blank', '');
window.open(`data:${fileType},${encodeURIComponent(file.toString())}`, '_blank', '');
}
}
}

View File

@@ -6,7 +6,7 @@ export class AsyncLazy<T> {
private isCreatingValue = false;
private value: T | undefined;
constructor(private valueFactory: () => Promise<T>) { }
constructor(private valueFactory: () => Promise<T>) {}
public setValueFactory(valueFactory: () => Promise<T>) {
this.valueFactory = valueFactory;

View File

@@ -3,8 +3,8 @@ import App from './App.vue';
import { ApplicationBootstrapper } from './presentation/Bootstrapping/ApplicationBootstrapper';
new ApplicationBootstrapper()
.bootstrap(Vue);
.bootstrap(Vue);
new Vue({
render: (h) => h(App),
render: (h) => h(App),
}).$mount('#app');

View File

@@ -11,8 +11,15 @@ import { faTimes, faFileDownload, faCopy, faSearch, faInfoCircle } from '@fortaw
export class IconBootstrapper implements IVueBootstrapper {
public bootstrap(vue: VueConstructor): void {
library.add(faGithub, faFolderOpen, faFolder,
faTimes, faFileDownload, faCopy, faSearch, faInfoCircle);
library.add(
faGithub,
faFolderOpen,
faFolder,
faTimes,
faFileDownload,
faCopy,
faSearch,
faInfoCircle);
vue.component('font-awesome-icon', FontAwesomeIcon);
}
}

View File

@@ -1,4 +1,6 @@
// based on https://github.com/Akryum/v-tooltip/blob/83615e394c96ca491a4df04b892ae87e833beb97/demo-src/src/App.vue#L179-L303
@import "@/presentation/styles/colors.scss";
.tooltip {
display: block !important;
z-index: 10000;

View File

@@ -1,4 +1,5 @@
// Overrides base styling for LiquorTree
@import "@/presentation/styles/colors.scss";
.tree-node > .tree-content > .tree-anchor > span {
color: $white !important;

20
src/shims-tsx.d.ts vendored
View File

@@ -1,13 +1,17 @@
import Vue, { VNode } from 'vue';
declare global {
namespace JSX {
// tslint:disable no-empty-interface
interface Element extends VNode {}
// tslint:disable no-empty-interface
interface ElementClass extends Vue {}
interface IntrinsicElements {
[elem: string]: any;
namespace JSX {
// tslint:disable no-empty-interface
interface Element extends VNode {
}
// tslint:disable no-empty-interface
interface ElementClass extends Vue {
}
interface IntrinsicElements {
[elem: string]: any;
}
}
}
}

4
src/shims-vue.d.ts vendored
View File

@@ -1,4 +1,4 @@
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
import Vue from 'vue';
export default Vue;
}