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:
@@ -1,28 +1,84 @@
|
||||
import { it } from 'vitest';
|
||||
|
||||
export function itEachAbsentStringValue(
|
||||
runner: (absentValue: string | null) => void,
|
||||
options: { excludeUndefined: true, excludeNull?: false }
|
||||
): void;
|
||||
export function itEachAbsentStringValue(
|
||||
runner: (absentValue: string | undefined) => void,
|
||||
options: { excludeUndefined?: false, excludeNull: true }
|
||||
): void;
|
||||
export function itEachAbsentStringValue(
|
||||
runner: (absentValue: string) => void,
|
||||
options: IAbsentTestCaseOptions = DefaultAbsentTestCaseOptions,
|
||||
options: { excludeUndefined: true, excludeNull: true }
|
||||
): void;
|
||||
export function itEachAbsentStringValue(
|
||||
runner: (absentValue: string | null | undefined) => void,
|
||||
options?: { excludeUndefined?: false, excludeNull?: false },
|
||||
): void;
|
||||
export function itEachAbsentStringValue(
|
||||
runner: ((absentValue: string) => void)
|
||||
| ((absentValue: string | null) => void)
|
||||
| ((absentValue: string | undefined) => void)
|
||||
| ((absentValue: string | null | undefined) => void),
|
||||
options: AbsentTestCaseOptions = DefaultAbsentTestCaseOptions,
|
||||
): void {
|
||||
itEachAbsentTestCase(getAbsentStringTestCases(options), runner);
|
||||
// Using `as any` due to limitation of TypeScript, this may be fixed in future versions.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
itEachAbsentTestCase(getAbsentStringTestCases(options as any), runner);
|
||||
}
|
||||
|
||||
export function itEachAbsentCollectionValue<T>(
|
||||
runner: (absentValue: T[] | null) => void,
|
||||
options: { excludeUndefined: true, excludeNull?: false }
|
||||
): void;
|
||||
export function itEachAbsentCollectionValue<T>(
|
||||
runner: (absentValue: T[] | undefined) => void,
|
||||
options: { excludeUndefined?: false, excludeNull: true }
|
||||
): void;
|
||||
export function itEachAbsentCollectionValue<T>(
|
||||
runner: (absentValue: T[]) => void,
|
||||
options: { excludeUndefined: true, excludeNull: true }
|
||||
): void;
|
||||
export function itEachAbsentCollectionValue<T>(
|
||||
runner: (absentValue: T[] | null | undefined) => void,
|
||||
options?: { excludeUndefined?: false, excludeNull?: false },
|
||||
): void;
|
||||
export function itEachAbsentCollectionValue<T>(
|
||||
runner: ((absentValue: T[]) => void)
|
||||
| ((absentValue: T[] | null) => void)
|
||||
| ((absentValue: T[] | undefined) => void)
|
||||
| ((absentValue: T[] | null | undefined) => void),
|
||||
options: AbsentTestCaseOptions = DefaultAbsentTestCaseOptions,
|
||||
): void {
|
||||
// Using `as any` due to limitation of TypeScript, this may be fixed in future versions.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
itEachAbsentTestCase(getAbsentCollectionTestCases<T>(options as any), runner);
|
||||
}
|
||||
|
||||
export function itEachAbsentObjectValue(
|
||||
runner: (absentValue: AbsentObjectType) => void,
|
||||
options: IAbsentTestCaseOptions = DefaultAbsentTestCaseOptions,
|
||||
runner: (absentValue: null) => void,
|
||||
options: { excludeUndefined: true, excludeNull?: false },
|
||||
): void;
|
||||
export function itEachAbsentObjectValue(
|
||||
runner: (absentValue: undefined) => void,
|
||||
options: { excludeUndefined?: false, excludeNull: true },
|
||||
): void;
|
||||
export function itEachAbsentObjectValue(
|
||||
runner: (absentValue: undefined | null) => void,
|
||||
options?: { excludeUndefined?: false, excludeNull?: false } | AbsentTestCaseOptions,
|
||||
): void;
|
||||
export function itEachAbsentObjectValue(
|
||||
runner: ((absentValue: null) => void)
|
||||
| ((absentValue: undefined) => void)
|
||||
| ((absentValue: null | undefined) => void),
|
||||
options: AbsentTestCaseOptions = DefaultAbsentTestCaseOptions,
|
||||
): void {
|
||||
itEachAbsentTestCase(getAbsentObjectTestCases(options), runner);
|
||||
}
|
||||
|
||||
export function itEachAbsentCollectionValue<T>(
|
||||
runner: (absentValue: []) => void,
|
||||
options: IAbsentTestCaseOptions = DefaultAbsentTestCaseOptions,
|
||||
): void {
|
||||
itEachAbsentTestCase(getAbsentCollectionTestCases<T>(options), runner);
|
||||
}
|
||||
|
||||
export function itEachAbsentTestCase<T>(
|
||||
testCases: readonly IAbsentTestCase<T>[],
|
||||
testCases: readonly AbsentTestCase<T>[],
|
||||
runner: (absentValue: T) => void,
|
||||
): void {
|
||||
for (const testCase of testCases) {
|
||||
@@ -32,68 +88,106 @@ export function itEachAbsentTestCase<T>(
|
||||
}
|
||||
}
|
||||
|
||||
export function getAbsentObjectTestCases(
|
||||
options: IAbsentTestCaseOptions = DefaultAbsentTestCaseOptions,
|
||||
): IAbsentTestCase<AbsentObjectType>[] {
|
||||
return [
|
||||
{
|
||||
valueName: 'null',
|
||||
absentValue: null,
|
||||
},
|
||||
...(options.excludeUndefined ? [] : [
|
||||
{
|
||||
valueName: 'undefined',
|
||||
absentValue: undefined,
|
||||
},
|
||||
]),
|
||||
];
|
||||
interface AbsentTestCaseOptions {
|
||||
readonly excludeUndefined?: boolean;
|
||||
readonly excludeNull?: boolean;
|
||||
}
|
||||
|
||||
export function getAbsentStringTestCases(
|
||||
options: IAbsentTestCaseOptions = DefaultAbsentTestCaseOptions,
|
||||
): IAbsentStringCase[] {
|
||||
return [
|
||||
{
|
||||
valueName: 'empty',
|
||||
absentValue: '',
|
||||
},
|
||||
...getAbsentObjectTestCases(options),
|
||||
];
|
||||
}
|
||||
|
||||
export function getAbsentCollectionTestCases<T>(
|
||||
options: IAbsentTestCaseOptions = DefaultAbsentTestCaseOptions,
|
||||
): readonly IAbsentCollectionCase<T>[] {
|
||||
return [
|
||||
...getAbsentObjectTestCases(options),
|
||||
{
|
||||
valueName: 'empty',
|
||||
absentValue: new Array<T>(),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const DefaultAbsentTestCaseOptions: IAbsentTestCaseOptions = {
|
||||
const DefaultAbsentTestCaseOptions: AbsentTestCaseOptions = {
|
||||
excludeUndefined: false,
|
||||
excludeNull: false,
|
||||
};
|
||||
|
||||
interface IAbsentTestCaseOptions {
|
||||
readonly excludeUndefined: boolean;
|
||||
}
|
||||
|
||||
type AbsentObjectType = undefined | null;
|
||||
|
||||
interface IAbsentTestCase<T> {
|
||||
interface AbsentTestCase<T> {
|
||||
readonly valueName: string;
|
||||
readonly absentValue: T;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
interface IAbsentStringCase extends IAbsentTestCase<string> {
|
||||
// Marker interface
|
||||
export function getAbsentObjectTestCases(
|
||||
options: { excludeUndefined: true, excludeNull?: false },
|
||||
): ReadonlyArray<AbsentTestCase<null>>;
|
||||
export function getAbsentObjectTestCases(
|
||||
options: { excludeUndefined?: false, excludeNull: true },
|
||||
): ReadonlyArray<AbsentTestCase<undefined>>;
|
||||
export function getAbsentObjectTestCases(
|
||||
options: { excludeUndefined: true, excludeNull: true },
|
||||
): ReadonlyArray<never>;
|
||||
export function getAbsentObjectTestCases(
|
||||
options?: { excludeUndefined?: false, excludeNull?: false } | AbsentTestCaseOptions,
|
||||
): ReadonlyArray<AbsentTestCase<null> | AbsentTestCase<undefined>>;
|
||||
export function getAbsentObjectTestCases(
|
||||
options: AbsentTestCaseOptions = DefaultAbsentTestCaseOptions,
|
||||
): ReadonlyArray<AbsentTestCase<null> | AbsentTestCase<undefined>> {
|
||||
const results: Array<AbsentTestCase<null> | AbsentTestCase<undefined>> = [];
|
||||
if (!options.excludeNull) {
|
||||
results.push({
|
||||
valueName: 'null',
|
||||
absentValue: null,
|
||||
});
|
||||
}
|
||||
if (!options.excludeUndefined) {
|
||||
results.push({
|
||||
valueName: 'undefined',
|
||||
absentValue: undefined,
|
||||
});
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
interface IAbsentCollectionCase<T> extends IAbsentTestCase<T[]> {
|
||||
// Marker interface
|
||||
export function getAbsentStringTestCases(
|
||||
options?: { excludeUndefined: false, excludeNull: false },
|
||||
): ReadonlyArray<AbsentTestCase<string> | AbsentTestCase<null> | AbsentTestCase<undefined>>;
|
||||
export function getAbsentStringTestCases(
|
||||
options: { excludeUndefined: true, excludeNull?: false }
|
||||
): ReadonlyArray<AbsentTestCase<string> | AbsentTestCase<null>>;
|
||||
export function getAbsentStringTestCases(
|
||||
options: { excludeUndefined?: false, excludeNull: true }
|
||||
): ReadonlyArray<AbsentTestCase<string> | AbsentTestCase<undefined>>;
|
||||
export function getAbsentStringTestCases(
|
||||
options: { excludeUndefined: true, excludeNull: true }
|
||||
): ReadonlyArray<AbsentTestCase<string>>;
|
||||
export function getAbsentStringTestCases(
|
||||
options: AbsentTestCaseOptions = DefaultAbsentTestCaseOptions,
|
||||
): ReadonlyArray<AbsentTestCase<string> | AbsentTestCase<null> | AbsentTestCase<undefined>> {
|
||||
const results: Array<(
|
||||
AbsentTestCase<string> | AbsentTestCase<null> | AbsentTestCase<undefined>
|
||||
)> = [];
|
||||
|
||||
results.push({
|
||||
valueName: 'empty',
|
||||
absentValue: '',
|
||||
});
|
||||
|
||||
const objectTestCases = getAbsentObjectTestCases(options);
|
||||
results.push(...objectTestCases);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
export function getAbsentCollectionTestCases<T>(
|
||||
options?: { excludeUndefined: false, excludeNull: false },
|
||||
): ReadonlyArray<AbsentTestCase<T[]> | AbsentTestCase<null> | AbsentTestCase<undefined>>;
|
||||
export function getAbsentCollectionTestCases<T>(
|
||||
options: { excludeUndefined: true, excludeNull?: false }
|
||||
): ReadonlyArray<AbsentTestCase<T[]> | AbsentTestCase<null>>;
|
||||
export function getAbsentCollectionTestCases<T>(
|
||||
options: { excludeUndefined?: false, excludeNull: true }
|
||||
): ReadonlyArray<AbsentTestCase<T[]> | AbsentTestCase<undefined>>;
|
||||
export function getAbsentCollectionTestCases<T>(
|
||||
options: { excludeUndefined: true, excludeNull: true }
|
||||
): ReadonlyArray<AbsentTestCase<T[]>>;
|
||||
export function getAbsentCollectionTestCases<T>(
|
||||
options: AbsentTestCaseOptions = DefaultAbsentTestCaseOptions,
|
||||
): ReadonlyArray<AbsentTestCase<T[]> | AbsentTestCase<null> | AbsentTestCase<undefined>> {
|
||||
const results: Array<AbsentTestCase<T[]> | AbsentTestCase<null> | AbsentTestCase<undefined>> = [];
|
||||
|
||||
const objectTestCases = getAbsentObjectTestCases(options);
|
||||
results.push(...objectTestCases);
|
||||
|
||||
results.push({
|
||||
valueName: 'empty',
|
||||
absentValue: [],
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user