Skip to content

Commit

Permalink
[REFACTOR] Change error result data structure
Browse files Browse the repository at this point in the history
Squashed commit of the following:

commit 8eb65e0a3abb4b38115e48a43f95a78ef9f83240
Author: Luke Autry <[email protected]>
Date:   Tue Nov 26 15:35:22 2019 -0500

    new error data structure
  • Loading branch information
lukeautry committed Nov 26, 2019
1 parent 82b9398 commit 5da6719
Show file tree
Hide file tree
Showing 52 changed files with 763 additions and 1,067 deletions.
13 changes: 8 additions & 5 deletions src/assertions/array-of-type.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Result, Expected } from "./result";
import { success } from "./success";
import { isArray } from "./array";
import { error } from "./error";

type ArrayScanResult<T> = IArrayScanSuccess<T> | Expected;

Expand All @@ -16,11 +15,12 @@ const scanArrayForType = <T>(
): ArrayScanResult<T> => {
for (let index = 0; index < values.length; index++) {
const result = fn(values[index]);
if (!result.success) {
return error("keyed", {
if (result.kind !== "success") {
return {
kind: "object-key",
key: `[${index}]`,
value: result
});
};
}
}

Expand All @@ -39,6 +39,9 @@ export const assertArrayOfType = <T>(
return scanResult;
}
} else {
return error("single", { value: "array" });
return {
kind: "single",
value: "array"
};
}
};
3 changes: 1 addition & 2 deletions src/assertions/boolean.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Result } from "./result";
import { success } from "./success";
import { error } from "./error";

export const isBoolean = (value: unknown): value is boolean =>
typeof value === "boolean";

export const assertBoolean = (value: unknown): Result<boolean> =>
isBoolean(value) ? success(value) : error("single", { value: "boolean" });
isBoolean(value) ? success(value) : { kind: "single", value: "boolean" };
11 changes: 0 additions & 11 deletions src/assertions/error.ts

This file was deleted.

3 changes: 1 addition & 2 deletions src/assertions/false.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Result } from "./result";
import { success } from "./success";
import { error } from "./error";

export const isFalse = (value: unknown): value is false => value === false;

export const assertFalse = (value: unknown): Result<false> =>
isFalse(value) ? success(value) : error("single", { value: false });
isFalse(value) ? success(value) : { kind: "single", value: false };
8 changes: 5 additions & 3 deletions src/assertions/key-value.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Result } from "./result";
import { success } from "./success";
import { hasKey } from "./has-key";
import { error } from "./error";

export const assertKeyValue = <O extends {}, K extends string, T>(
value: O,
Expand All @@ -10,14 +9,17 @@ export const assertKeyValue = <O extends {}, K extends string, T>(
): Result<O & Record<K, T>> => {
if (hasKey(value, key)) {
const result = assertFn(value[key]);
if (result.success) {
if (result.kind === "success") {
// at this point, we should have merged assertions here, but that doesn't
// seem to be happening, hence the cast
return success((value as unknown) as O & Record<K, T>);
} else {
return result;
}
} else {
return error("single", { value: "to exist" });
return {
kind: "single",
value: "to exist"
};
}
};
3 changes: 1 addition & 2 deletions src/assertions/null.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Result } from "./result";
import { success } from "./success";
import { error } from "./error";

export const isNull = (value: unknown): value is null => value === null;

export const assertNull = (value: unknown): Result<null> =>
isNull(value) ? success(value) : error("single", { value: null });
isNull(value) ? success(value) : { kind: "single", value: null };
3 changes: 1 addition & 2 deletions src/assertions/number.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Result } from "./result";
import { success } from "./success";
import { error } from "./error";

export const isNumber = (value: unknown): value is number =>
typeof value === "number";

export const assertNumber = (value: unknown): Result<number> =>
isNumber(value) ? success(value) : error("single", { value: "number" });
isNumber(value) ? success(value) : { kind: "single", value: "number" };
3 changes: 1 addition & 2 deletions src/assertions/numeric-literal.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Result } from "./result";
import { success } from "./success";
import { error } from "./error";

const isNumericLiteral = <N extends number>(
value: unknown,
Expand All @@ -15,4 +14,4 @@ export const assertNumericLiteral = <N extends number>(
): Result<N> =>
isNumericLiteral(value, expected)
? success(value)
: error("single", { value: expected });
: { kind: "single", value: expected };
6 changes: 2 additions & 4 deletions src/assertions/record.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Result } from "./result";
import { hasKey } from "./has-key";
import { success } from "./success";
import { error } from "./error";

export const assertRecord = <O extends {}, T>(
value: O,
assertFn: (val: unknown) => Result<T>
Expand All @@ -12,11 +10,11 @@ export const assertRecord = <O extends {}, T>(
if (hasKey(value, key)) {
const objVal = value[key];
const result = assertFn(objVal);
if (!result.success) {
if (result.kind !== "success") {
return result;
}
} else {
return error("keyed", { key, value });
return { kind: "object-key", key, value };
}
}

Expand Down
36 changes: 14 additions & 22 deletions src/assertions/result.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,29 @@
export type Result<T> = ISuccessResult<T> | Expected;
export type Result<T> = Readonly<ISuccessResult<T> | Expected>;

export interface ISuccessResult<T> {
success: true;
kind: "success";
value: T;
}

export type Expected = IAllOf | IOneOf | ISingle | IKeyed;
export type Expected = IAllOf | IOneOf | ISingle | IObjectKey;

export interface IExpectedTypes {
"all-of": IAllOf;
"one-of": IOneOf;
single: ISingle;
keyed: IKeyed;
interface IAllOf {
kind: "all-of";
values: ReadonlyArray<Expected>;
}

interface IExpected<K extends keyof IExpectedTypes> {
success: false;
kind: K;
interface IOneOf {
kind: "one-of";
values: ReadonlyArray<Expected>;
}

interface IAllOf extends IExpected<"all-of"> {
values: (JSONType | Expected)[];
interface ISingle {
kind: "single";
value: JSONType;
}

interface IOneOf extends IExpected<"one-of"> {
values: (JSONType | Expected)[];
}

interface ISingle extends IExpected<"single"> {
value: JSONType | Expected;
}

interface IKeyed extends IExpected<"keyed"> {
interface IObjectKey {
kind: "object-key";
key: string;
value: JSONType | Expected;
}
Expand Down
3 changes: 1 addition & 2 deletions src/assertions/string-literal.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Result } from "./result";
import { success } from "./success";
import { error } from "./error";

const isStringLiteral = <K extends string>(
value: unknown,
Expand All @@ -15,4 +14,4 @@ export const assertStringLiteral = <K extends string>(
): Result<K> =>
isStringLiteral(value, expected)
? success(value)
: error("single", { value: expected });
: { kind: "single", value: expected };
3 changes: 1 addition & 2 deletions src/assertions/string.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Result } from "./result";
import { success } from "./success";
import { error } from "./error";

export const isString = (value: unknown): value is string =>
typeof value === "string";

export const assertString = (value: unknown): Result<string> =>
isString(value) ? success(value) : error("single", { value: "string" });
isString(value) ? success(value) : { kind: "single", value: "string" };
2 changes: 1 addition & 1 deletion src/assertions/success.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ISuccessResult } from "./result";

export const success = <T>(value: T): ISuccessResult<T> => ({
success: true,
kind: "success",
value
});
3 changes: 1 addition & 2 deletions src/assertions/true.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Result } from "./result";
import { success } from "./success";
import { error } from "./error";

export const isTrue = (value: unknown): value is true => value === true;

export const assertTrue = (value: unknown): Result<true> =>
isTrue(value) ? success(value) : error("single", { value: true });
isTrue(value) ? success(value) : { kind: "single", value: true };
3 changes: 1 addition & 2 deletions src/assertions/undefined.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Result } from "./result";
import { success } from "./success";
import { error } from "./error";

export const isUndefined = (value: unknown): value is undefined =>
typeof value === "undefined";

export const assertUndefined = (value: unknown): Result<undefined> =>
isUndefined(value) ? success(value) : error("single", { value: "undefined" });
isUndefined(value) ? success(value) : { kind: "single", value: "undefined" };
4 changes: 2 additions & 2 deletions src/render/renderers/enum-member-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { IRenderParams } from "./common/render-params";
export const enumMemberRenderer: (
params: IRenderParams<"enum-member">
) => string = ({ cache, value, name, varName }) => {
cache.includeSnippet("success", "error");
cache.includeSnippet("success");

const escapedVal = getEscaped(value.value);
return `(() => {
if (${varName} === ${escapedVal}) {
return success(${varName} as ${name});
} else {
return error('single', { value: ${escapedVal} });
return { kind: 'single', value: ${escapedVal} } as const;
}
})()`;
};
11 changes: 7 additions & 4 deletions src/render/renderers/enum-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const enumRenderer: (params: IRenderParams<"enum">) => string = ({
name
}) => {
if (value.values.length > 0) {
cache.includeSnippet("success", "error");
cache.includeSnippet("success");
}
return `(() => {
const arr = [${value.values.map(v => getEscaped(v))}];
Expand All @@ -17,8 +17,11 @@ export const enumRenderer: (params: IRenderParams<"enum">) => string = ({
}
}
return error('one-of', {
values: [${value.values.map(v => getEscaped(v)).join(",")}]
});
return {
kind: 'one-of',
values: [${value.values
.map(v => `{ kind: 'single', value: ${getEscaped(v)} }`)
.join(",")}]
} as const;
})()`;
};
2 changes: 1 addition & 1 deletion src/render/renderers/intersection-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const intersectionRenderer: (
varName: lastPropVarName(),
cache
})};
if (!${propVarName}.success) { return ${propVarName}; }`;
if (${propVarName}.kind !== 'success') { return ${propVarName}; }`;
})
.join(LINE_BREAK)}
Expand Down
17 changes: 10 additions & 7 deletions src/render/renderers/object-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ export const objectRenderer: (params: IRenderParams<"object">) => string = ({
}) => {
cache.includeSnippet(
"object",
value.properties.length ? "key-value" : "success",
"error"
value.properties.length ? "key-value" : "success"
);
const prefix = cache.getPrefix();
const prefixedVarName = (index: number) => `${prefix}${index}`;
return `(() => {
if (!isObject(${varName})) {
return error('single', { value: 'object' });
return {
kind: 'single',
value: 'object'
} as const;
}
${value.properties
Expand All @@ -38,7 +40,7 @@ export const objectRenderer: (params: IRenderParams<"object">) => string = ({
varName: paramName,
cache
})});
if (!${propVarName}.success) { return ${propVarName}; }
if (${propVarName}.kind !== 'success') { return ${propVarName}; }
`;
} else {
const assertKeyScript = `
Expand All @@ -59,11 +61,12 @@ export const objectRenderer: (params: IRenderParams<"object">) => string = ({
})})`;
const errorCheckScript = `
if (!${propVarName}.success) {
return error('keyed', {
if (${propVarName}.kind !== 'success') {
return {
kind: 'object-key',
key: '${p.name}',
value: ${propVarName}
});
} as const;
}
`;
Expand Down
14 changes: 9 additions & 5 deletions src/render/renderers/tuple-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const tupleRenderer: (params: IRenderParams<"tuple">) => string = ({
varName,
name
}) => {
cache.includeSnippet("array", "success", "error");
cache.includeSnippet("array", "success");
const prefix = cache.getPrefix();
const prefixedVarName = (index: number) => `${prefix}${index}`;

Expand All @@ -24,11 +24,12 @@ export const tupleRenderer: (params: IRenderParams<"tuple">) => string = ({
varName: `${varName}[${i}]`,
cache
})};
if (!${elementVarName}.success) {
return error('keyed', {
if (${elementVarName}.kind !== 'success') {
return {
kind: 'object-key',
key: '[${i}]',
value: ${elementVarName}
});
} as const;
}
`;
})
Expand All @@ -42,7 +43,10 @@ export const tupleRenderer: (params: IRenderParams<"tuple">) => string = ({
.join(", ")}
]);
} else {
return error('single', { value: 'array' });
return {
kind: 'single',
value: 'array'
} as const;
}
})()`;
};
Loading

0 comments on commit 5da6719

Please sign in to comment.