From 4b54b272a5578523c3a03b21720cb89c0d5177db Mon Sep 17 00:00:00 2001 From: Grant Timmerman Date: Thu, 23 Jul 2020 16:09:07 -0700 Subject: [PATCH] feat: simplify validation logic/imports (#265) Signed-off-by: Grant Timmerman --- src/event/validation.ts | 85 +++++++++++++++++++++++ src/event/validation/index.ts | 2 - src/event/validation/is.ts | 87 ------------------------ src/event/validation/validation_error.ts | 14 ---- test/integration/http_binding_1.ts | 2 +- test/integration/utilities_test.ts | 2 +- 6 files changed, 87 insertions(+), 105 deletions(-) create mode 100644 src/event/validation.ts delete mode 100644 src/event/validation/index.ts delete mode 100644 src/event/validation/is.ts delete mode 100644 src/event/validation/validation_error.ts diff --git a/src/event/validation.ts b/src/event/validation.ts new file mode 100644 index 0000000..56b97e5 --- /dev/null +++ b/src/event/validation.ts @@ -0,0 +1,85 @@ +import { ErrorObject } from "ajv"; + +/** + * An Error class that will be thrown when a CloudEvent + * cannot be properly validated against a specification. + */ +export class ValidationError extends TypeError { + errors?: string[] | ErrorObject[] | null; + + constructor(message: string, errors?: string[] | ErrorObject[] | null) { + super(message); + this.errors = errors ? errors : []; + } +} + +export const isString = (v: unknown): boolean => typeof v === "string"; +export const isObject = (v: unknown): boolean => typeof v === "object"; +export const isDefined = (v: unknown): boolean => v && typeof v !== "undefined"; + +export const isBoolean = (v: unknown): boolean => typeof v === "boolean"; +export const isInteger = (v: unknown): boolean => Number.isInteger(v as number); +export const isDate = (v: unknown): boolean => v instanceof Date; +export const isBinary = (v: unknown): boolean => v instanceof Uint32Array; + +export const isStringOrThrow = (v: unknown, t: Error): boolean => + isString(v) + ? true + : (() => { + throw t; + })(); + +export const isDefinedOrThrow = (v: unknown, t: Error): boolean => + isDefined(v) + ? true + : (() => { + throw t; + })(); + +export const isStringOrObjectOrThrow = (v: unknown, t: Error): boolean => + isString(v) + ? true + : isObject(v) + ? true + : (() => { + throw t; + })(); + +export const equalsOrThrow = (v1: unknown, v2: unknown, t: Error): boolean => + v1 === v2 + ? true + : (() => { + throw t; + })(); + +export const isBase64 = (value: unknown): boolean => + Buffer.from(value as string, "base64").toString("base64") === value; + +export const isBuffer = (value: unknown): boolean => value instanceof Buffer; + +export const asBuffer = (value: string | Buffer | Uint32Array): Buffer => + isBinary(value) + ? Buffer.from(value as string) + : isBuffer(value) + ? (value as Buffer) + : (() => { + throw new TypeError("is not buffer or a valid binary"); + })(); + +export const asBase64 = (value: string | Buffer | Uint32Array): string => asBuffer(value).toString("base64"); + +export const clone = (o: Record): Record => JSON.parse(JSON.stringify(o)); + +export const isJsonContentType = (contentType: string): "" | RegExpMatchArray | null => + contentType && contentType.match(/(json)/i); + +export const asData = (data: unknown, contentType: string): string => { + // pattern matching alike + const maybeJson = + isString(data) && !isBase64(data) && isJsonContentType(contentType) ? JSON.parse(data as string) : data; + + return isBinary(maybeJson) ? asBase64(maybeJson) : maybeJson; +}; + +export const isValidType = (v: boolean | number | string | Date | Uint32Array): boolean => + isBoolean(v) || isInteger(v) || isString(v) || isDate(v) || isBinary(v); diff --git a/src/event/validation/index.ts b/src/event/validation/index.ts deleted file mode 100644 index 5b4ab37..0000000 --- a/src/event/validation/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./is"; -export * from "./validation_error"; diff --git a/src/event/validation/is.ts b/src/event/validation/is.ts deleted file mode 100644 index 328746d..0000000 --- a/src/event/validation/is.ts +++ /dev/null @@ -1,87 +0,0 @@ -const isString = (v: unknown): boolean => typeof v === "string"; -const isObject = (v: unknown): boolean => typeof v === "object"; -const isDefined = (v: unknown): boolean => v && typeof v !== "undefined"; - -const isBoolean = (v: unknown): boolean => typeof v === "boolean"; -const isInteger = (v: unknown): boolean => Number.isInteger(v as number); -const isDate = (v: unknown): boolean => v instanceof Date; -const isBinary = (v: unknown): boolean => v instanceof Uint32Array; - -const isStringOrThrow = (v: unknown, t: Error): boolean => - isString(v) - ? true - : (() => { - throw t; - })(); - -const isDefinedOrThrow = (v: unknown, t: Error): boolean => - isDefined(v) - ? true - : (() => { - throw t; - })(); - -const isStringOrObjectOrThrow = (v: unknown, t: Error): boolean => - isString(v) - ? true - : isObject(v) - ? true - : (() => { - throw t; - })(); - -const equalsOrThrow = (v1: unknown, v2: unknown, t: Error): boolean => - v1 === v2 - ? true - : (() => { - throw t; - })(); - -const isBase64 = (value: unknown): boolean => Buffer.from(value as string, "base64").toString("base64") === value; - -const isBuffer = (value: unknown): boolean => value instanceof Buffer; - -const asBuffer = (value: string | Buffer | Uint32Array): Buffer => - isBinary(value) - ? Buffer.from(value as string) - : isBuffer(value) - ? (value as Buffer) - : (() => { - throw new TypeError("is not buffer or a valid binary"); - })(); - -const asBase64 = (value: string | Buffer | Uint32Array): string => asBuffer(value).toString("base64"); - -const clone = (o: Record): Record => JSON.parse(JSON.stringify(o)); - -const isJsonContentType = (contentType: string) => contentType && contentType.match(/(json)/i); - -const asData = (data: unknown, contentType: string): string => { - // pattern matching alike - const maybeJson = - isString(data) && !isBase64(data) && isJsonContentType(contentType) ? JSON.parse(data as string) : data; - - return isBinary(maybeJson) ? asBase64(maybeJson) : maybeJson; -}; - -const isValidType = (v: boolean | number | string | Date | Uint32Array): boolean => - isBoolean(v) || isInteger(v) || isString(v) || isDate(v) || isBinary(v); - -export { - isString, - isStringOrThrow, - isObject, - isDefined, - isBoolean, - isInteger, - isDate, - isBinary, - isDefinedOrThrow, - isStringOrObjectOrThrow, - isValidType, - equalsOrThrow, - isBase64, - clone, - asData, - asBase64, -}; diff --git a/src/event/validation/validation_error.ts b/src/event/validation/validation_error.ts deleted file mode 100644 index 598fee6..0000000 --- a/src/event/validation/validation_error.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ErrorObject } from "ajv"; - -/** - * An Error class that will be thrown when a CloudEvent - * cannot be properly validated against a specification. - */ -export class ValidationError extends TypeError { - errors?: string[] | ErrorObject[] | null; - - constructor(message: string, errors?: string[] | ErrorObject[] | null) { - super(message); - this.errors = errors ? errors : []; - } -} diff --git a/test/integration/http_binding_1.ts b/test/integration/http_binding_1.ts index 0a88a64..d64cd75 100644 --- a/test/integration/http_binding_1.ts +++ b/test/integration/http_binding_1.ts @@ -5,7 +5,7 @@ import nock from "nock"; import { CloudEvent, Version } from "../../src"; import { emitBinary, emitStructured } from "../../src/transport/http"; -import { asBase64 } from "../../src/event/validation/is"; +import { asBase64 } from "../../src/event/validation"; import { AxiosResponse } from "axios"; const type = "com.github.pull.create"; diff --git a/test/integration/utilities_test.ts b/test/integration/utilities_test.ts index 4895b68..f387e60 100644 --- a/test/integration/utilities_test.ts +++ b/test/integration/utilities_test.ts @@ -1,6 +1,6 @@ import "mocha"; import { expect } from "chai"; -import { isStringOrThrow, equalsOrThrow, isBase64, asData } from "../../src/event/validation/is"; +import { isStringOrThrow, equalsOrThrow, isBase64, asData } from "../../src/event/validation"; describe("Utilities", () => { describe("isStringOrThrow", () => {