Refactor to enforce strictNullChecks
This commit applies `strictNullChecks` to the entire codebase to improve maintainability and type safety. Key changes include: - Remove some explicit null-checks where unnecessary. - Add necessary null-checks. - Refactor static factory functions for a more functional approach. - Improve some test names and contexts for better debugging. - Add unit tests for any additional logic introduced. - Refactor `createPositionFromRegexFullMatch` to its own function as the logic is reused. - Prefer `find` prefix on functions that may return `undefined` and `get` prefix for those that always return a value.
This commit is contained in:
@@ -21,9 +21,6 @@ export class ApplicationCode implements IApplicationCode {
|
||||
private readonly scriptingDefinition: IScriptingDefinition,
|
||||
private readonly generator: IUserScriptGenerator = new UserScriptGenerator(),
|
||||
) {
|
||||
if (!userSelection) { throw new Error('missing userSelection'); }
|
||||
if (!scriptingDefinition) { throw new Error('missing scriptingDefinition'); }
|
||||
if (!generator) { throw new Error('missing generator'); }
|
||||
this.setCode(userSelection.selectedScripts);
|
||||
userSelection.changed.on((scripts) => {
|
||||
this.setCode(scripts);
|
||||
|
||||
@@ -36,7 +36,11 @@ export class CodeChangedEvent implements ICodeChangedEvent {
|
||||
}
|
||||
|
||||
public getScriptPositionInCode(script: IScript): ICodePosition {
|
||||
return this.scripts.get(script);
|
||||
const position = this.scripts.get(script);
|
||||
if (!position) {
|
||||
throw new Error('Unknown script: Position could not be found for the script');
|
||||
}
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,9 @@ export abstract class CodeBuilder implements ICodeBuilder {
|
||||
return this;
|
||||
}
|
||||
const lines = code.match(/[^\r\n]+/g);
|
||||
this.lines.push(...lines);
|
||||
if (lines) {
|
||||
this.lines.push(...lines);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@ export class UserScriptGenerator implements IUserScriptGenerator {
|
||||
selectedScripts: ReadonlyArray<SelectedScript>,
|
||||
scriptingDefinition: IScriptingDefinition,
|
||||
): IUserScript {
|
||||
if (!selectedScripts) { throw new Error('missing scripts'); }
|
||||
if (!scriptingDefinition) { throw new Error('missing definition'); }
|
||||
if (!selectedScripts.length) {
|
||||
return { code: '', scriptPositions: new Map<SelectedScript, ICodePosition>() };
|
||||
}
|
||||
@@ -68,8 +66,19 @@ function appendSelection(
|
||||
function appendCode(selection: SelectedScript, builder: ICodeBuilder): ICodeBuilder {
|
||||
const { script } = selection;
|
||||
const name = selection.revert ? `${script.name} (revert)` : script.name;
|
||||
const scriptCode = selection.revert ? script.code.revert : script.code.execute;
|
||||
const scriptCode = getSelectedCode(selection);
|
||||
return builder
|
||||
.appendLine()
|
||||
.appendFunction(name, scriptCode);
|
||||
}
|
||||
|
||||
function getSelectedCode(selection: SelectedScript): string {
|
||||
const { code } = selection.script;
|
||||
if (!selection.revert) {
|
||||
return code.execute;
|
||||
}
|
||||
if (!code.revert) {
|
||||
throw new Error('Reverted script lacks revert code.');
|
||||
}
|
||||
return code.revert;
|
||||
}
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
import { IFilterResult } from '@/application/Context/State/Filter/IFilterResult';
|
||||
import { FilterActionType } from './FilterActionType';
|
||||
import { IFilterChangeDetails, IFilterChangeDetailsVisitor } from './IFilterChangeDetails';
|
||||
import {
|
||||
IFilterChangeDetails, IFilterChangeDetailsVisitor,
|
||||
ApplyFilterAction, ClearFilterAction,
|
||||
} from './IFilterChangeDetails';
|
||||
|
||||
export class FilterChange implements IFilterChangeDetails {
|
||||
public static forApply(filter: IFilterResult) {
|
||||
if (!filter) {
|
||||
throw new Error('missing filter');
|
||||
}
|
||||
return new FilterChange(FilterActionType.Apply, filter);
|
||||
public static forApply(
|
||||
filter: IFilterResult,
|
||||
): IFilterChangeDetails {
|
||||
return new FilterChange({ type: FilterActionType.Apply, filter });
|
||||
}
|
||||
|
||||
public static forClear() {
|
||||
return new FilterChange(FilterActionType.Clear);
|
||||
public static forClear(): IFilterChangeDetails {
|
||||
return new FilterChange({ type: FilterActionType.Clear });
|
||||
}
|
||||
|
||||
private constructor(
|
||||
public readonly actionType: FilterActionType,
|
||||
public readonly filter?: IFilterResult,
|
||||
) { }
|
||||
private constructor(public readonly action: ApplyFilterAction | ClearFilterAction) { }
|
||||
|
||||
public visit(visitor: IFilterChangeDetailsVisitor): void {
|
||||
if (!visitor) {
|
||||
throw new Error('missing visitor');
|
||||
}
|
||||
switch (this.actionType) {
|
||||
switch (this.action.type) {
|
||||
case FilterActionType.Apply:
|
||||
visitor.onApply(this.filter);
|
||||
if (visitor.onApply) {
|
||||
visitor.onApply(this.action.filter);
|
||||
}
|
||||
break;
|
||||
case FilterActionType.Clear:
|
||||
visitor.onClear();
|
||||
if (visitor.onClear) {
|
||||
visitor.onClear();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown action type: ${this.actionType}`);
|
||||
throw new Error(`Unknown action: ${this.action}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,22 @@ import { IFilterResult } from '@/application/Context/State/Filter/IFilterResult'
|
||||
import { FilterActionType } from './FilterActionType';
|
||||
|
||||
export interface IFilterChangeDetails {
|
||||
readonly actionType: FilterActionType;
|
||||
readonly filter?: IFilterResult;
|
||||
|
||||
readonly action: FilterAction;
|
||||
visit(visitor: IFilterChangeDetailsVisitor): void;
|
||||
}
|
||||
|
||||
export interface IFilterChangeDetailsVisitor {
|
||||
onClear(): void;
|
||||
onApply(filter: IFilterResult): void;
|
||||
readonly onClear?: () => void;
|
||||
readonly onApply?: (filter: IFilterResult) => void;
|
||||
}
|
||||
|
||||
export type ApplyFilterAction = {
|
||||
readonly type: FilterActionType.Apply,
|
||||
readonly filter: IFilterResult;
|
||||
};
|
||||
|
||||
export type ClearFilterAction = {
|
||||
readonly type: FilterActionType.Clear,
|
||||
};
|
||||
|
||||
export type FilterAction = ApplyFilterAction | ClearFilterAction;
|
||||
|
||||
@@ -9,8 +9,6 @@ export class FilterResult implements IFilterResult {
|
||||
public readonly query: string,
|
||||
) {
|
||||
if (!query) { throw new Error('Query is empty or undefined'); }
|
||||
if (!scriptMatches) { throw new Error('Script matches is undefined'); }
|
||||
if (!categoryMatches) { throw new Error('Category matches is undefined'); }
|
||||
}
|
||||
|
||||
public hasAnyMatches(): boolean {
|
||||
|
||||
@@ -43,7 +43,7 @@ export class UserSelection implements IUserSelection {
|
||||
}
|
||||
|
||||
public removeAllInCategory(categoryId: number): void {
|
||||
const category = this.collection.findCategory(categoryId);
|
||||
const category = this.collection.getCategory(categoryId);
|
||||
const scriptsToRemove = category.getAllScriptsRecursively()
|
||||
.filter((script) => this.scripts.exists(script.id));
|
||||
if (!scriptsToRemove.length) {
|
||||
@@ -57,7 +57,7 @@ export class UserSelection implements IUserSelection {
|
||||
|
||||
public addOrUpdateAllInCategory(categoryId: number, revert = false): void {
|
||||
const scriptsToAddOrUpdate = this.collection
|
||||
.findCategory(categoryId)
|
||||
.getCategory(categoryId)
|
||||
.getAllScriptsRecursively()
|
||||
.filter(
|
||||
(script) => !this.scripts.exists(script.id)
|
||||
@@ -74,17 +74,14 @@ export class UserSelection implements IUserSelection {
|
||||
}
|
||||
|
||||
public addSelectedScript(scriptId: string, revert: boolean): void {
|
||||
const script = this.collection.findScript(scriptId);
|
||||
if (!script) {
|
||||
throw new Error(`Cannot add (id: ${scriptId}) as it is unknown`);
|
||||
}
|
||||
const script = this.collection.getScript(scriptId);
|
||||
const selectedScript = new SelectedScript(script, revert);
|
||||
this.scripts.addItem(selectedScript);
|
||||
this.changed.notify(this.scripts.getItems());
|
||||
}
|
||||
|
||||
public addOrUpdateSelectedScript(scriptId: string, revert: boolean): void {
|
||||
const script = this.collection.findScript(scriptId);
|
||||
const script = this.collection.getScript(scriptId);
|
||||
const selectedScript = new SelectedScript(script, revert);
|
||||
this.scripts.addOrUpdateItem(selectedScript);
|
||||
this.changed.notify(this.scripts.getItems());
|
||||
@@ -130,7 +127,7 @@ export class UserSelection implements IUserSelection {
|
||||
}
|
||||
|
||||
public selectOnly(scripts: readonly IScript[]): void {
|
||||
if (!scripts || scripts.length === 0) {
|
||||
if (!scripts.length) {
|
||||
throw new Error('Scripts are empty. Use deselectAll() if you want to deselect everything');
|
||||
}
|
||||
let totalChanged = 0;
|
||||
|
||||
Reference in New Issue
Block a user