refactor: simplify parser logic and duplicated code (#269)
Signed-off-by: Grant Timmerman <timmerman+devrel@google.com>
This commit is contained in:
parent
9ae32c76cb
commit
a6124cc350
|
@ -0,0 +1,79 @@
|
|||
import CONSTANTS from "./constants";
|
||||
import { isString, isDefinedOrThrow, isStringOrObjectOrThrow, ValidationError } from "./event/validation";
|
||||
|
||||
export abstract class Parser {
|
||||
abstract parse(payload: Record<string, unknown> | string): unknown;
|
||||
}
|
||||
|
||||
export class JSONParser implements Parser {
|
||||
decorator?: Base64Parser;
|
||||
constructor(decorator?: Base64Parser) {
|
||||
this.decorator = decorator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the payload with an optional decorator
|
||||
* @param {object|string} payload the JSON payload
|
||||
* @return {object} the parsed JSON payload.
|
||||
*/
|
||||
parse(payload: Record<string, unknown> | string): string {
|
||||
if (this.decorator) {
|
||||
payload = this.decorator.parse(payload);
|
||||
}
|
||||
|
||||
isDefinedOrThrow(payload, new ValidationError("null or undefined payload"));
|
||||
isStringOrObjectOrThrow(payload, new ValidationError("invalid payload type, allowed are: string or object"));
|
||||
const parseJSON = (v: Record<string, unknown> | string): string => (isString(v) ? JSON.parse(v as string) : v);
|
||||
return parseJSON(payload);
|
||||
}
|
||||
}
|
||||
|
||||
export class PassThroughParser extends Parser {
|
||||
parse(payload: unknown): unknown {
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
|
||||
const jsonParser = new JSONParser();
|
||||
export const parserByContentType: { [key: string]: Parser } = {
|
||||
[CONSTANTS.MIME_JSON]: jsonParser,
|
||||
[CONSTANTS.MIME_CE_JSON]: jsonParser,
|
||||
[CONSTANTS.DEFAULT_CONTENT_TYPE]: jsonParser,
|
||||
[CONSTANTS.DEFAULT_CE_CONTENT_TYPE]: jsonParser,
|
||||
[CONSTANTS.MIME_OCTET_STREAM]: new PassThroughParser(),
|
||||
};
|
||||
|
||||
export class Base64Parser implements Parser {
|
||||
decorator?: Parser;
|
||||
|
||||
constructor(decorator?: Parser) {
|
||||
this.decorator = decorator;
|
||||
}
|
||||
|
||||
parse(payload: Record<string, unknown> | string): string {
|
||||
let payloadToParse = payload;
|
||||
if (this.decorator) {
|
||||
payloadToParse = this.decorator.parse(payload) as string;
|
||||
}
|
||||
|
||||
return Buffer.from(payloadToParse as string, "base64").toString();
|
||||
}
|
||||
}
|
||||
|
||||
export interface MappedParser {
|
||||
name: string;
|
||||
parser: Parser;
|
||||
}
|
||||
|
||||
export class DateParser extends Parser {
|
||||
parse(payload: string): Date {
|
||||
return new Date(Date.parse(payload));
|
||||
}
|
||||
}
|
||||
|
||||
export const parserByEncoding: { [key: string]: { [key: string]: Parser } } = {
|
||||
base64: {
|
||||
[CONSTANTS.MIME_CE_JSON]: new JSONParser(new Base64Parser()),
|
||||
[CONSTANTS.MIME_OCTET_STREAM]: new PassThroughParser(),
|
||||
},
|
||||
};
|
|
@ -1,18 +0,0 @@
|
|||
import { Parser } from "./parser";
|
||||
|
||||
export class Base64Parser implements Parser {
|
||||
decorator?: Parser;
|
||||
|
||||
constructor(decorator?: Parser) {
|
||||
this.decorator = decorator;
|
||||
}
|
||||
|
||||
parse(payload: Record<string, unknown> | string): string {
|
||||
let payloadToParse = payload;
|
||||
if (this.decorator) {
|
||||
payloadToParse = this.decorator.parse(payload) as string;
|
||||
}
|
||||
|
||||
return Buffer.from(payloadToParse as string, "base64").toString();
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
import { Parser } from "./parser";
|
||||
|
||||
export class DateParser extends Parser {
|
||||
parse(payload: string): Date {
|
||||
return new Date(Date.parse(payload));
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
import { Parser } from "./parser";
|
||||
import { JSONParser } from "./json";
|
||||
import { PassThroughParser } from "./pass_through";
|
||||
import { Base64Parser } from "./base64";
|
||||
import CONSTANTS from "../constants";
|
||||
|
||||
export * from "./parser";
|
||||
export * from "./base64";
|
||||
export * from "./json";
|
||||
export * from "./date";
|
||||
export * from "./mapped";
|
||||
export * from "./pass_through";
|
||||
|
||||
const jsonParser = new JSONParser();
|
||||
const passThroughParser = new PassThroughParser();
|
||||
|
||||
export const parserByContentType: { [key: string]: Parser } = {
|
||||
[CONSTANTS.MIME_JSON]: jsonParser,
|
||||
[CONSTANTS.MIME_CE_JSON]: jsonParser,
|
||||
[CONSTANTS.DEFAULT_CONTENT_TYPE]: jsonParser,
|
||||
[CONSTANTS.DEFAULT_CE_CONTENT_TYPE]: jsonParser,
|
||||
[CONSTANTS.MIME_OCTET_STREAM]: passThroughParser,
|
||||
};
|
||||
|
||||
export const parserByEncoding: { [key: string]: { [key: string]: Parser } } = {
|
||||
base64: {
|
||||
[CONSTANTS.MIME_CE_JSON]: new JSONParser(new Base64Parser()),
|
||||
[CONSTANTS.MIME_OCTET_STREAM]: new PassThroughParser(),
|
||||
},
|
||||
};
|
|
@ -1,30 +0,0 @@
|
|||
import { Base64Parser } from "./base64";
|
||||
import { isString, isDefinedOrThrow, isStringOrObjectOrThrow, ValidationError } from "../event/validation";
|
||||
import { Parser } from "./parser";
|
||||
|
||||
const invalidPayloadTypeError = new ValidationError("invalid payload type, allowed are: string or object");
|
||||
const nullOrUndefinedPayload = new ValidationError("null or undefined payload");
|
||||
|
||||
const parseJSON = (v: Record<string, unknown> | string): string => (isString(v) ? JSON.parse(v as string) : v);
|
||||
|
||||
export class JSONParser implements Parser {
|
||||
decorator?: Base64Parser;
|
||||
constructor(decorator?: Base64Parser) {
|
||||
this.decorator = decorator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the payload with an optional decorator
|
||||
* @param {object|string} payload the JSON payload
|
||||
* @return {object} the parsed JSON payload.
|
||||
*/
|
||||
parse(payload: Record<string, unknown> | string): string {
|
||||
if (this.decorator) {
|
||||
payload = this.decorator.parse(payload);
|
||||
}
|
||||
|
||||
isDefinedOrThrow(payload, nullOrUndefinedPayload);
|
||||
isStringOrObjectOrThrow(payload, invalidPayloadTypeError);
|
||||
return parseJSON(payload);
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
import { Parser } from "./parser";
|
||||
|
||||
export interface MappedParser {
|
||||
name: string;
|
||||
parser: Parser;
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
export abstract class Parser {
|
||||
abstract parse(payload: Record<string, unknown> | string): unknown;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
import { Parser } from "./parser";
|
||||
|
||||
export class PassThroughParser extends Parser {
|
||||
parse(payload: unknown): unknown {
|
||||
return payload;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import "mocha";
|
||||
import { expect } from "chai";
|
||||
|
||||
import { JSONParser as Parser } from "../../src/parsers/";
|
||||
import { JSONParser as Parser } from "../../src/parsers";
|
||||
import { ValidationError } from "../../src/";
|
||||
|
||||
describe("JSON Event Format Parser", () => {
|
||||
|
|
Loading…
Reference in New Issue