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 "mocha";
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
import { JSONParser as Parser } from "../../src/parsers/";
|
import { JSONParser as Parser } from "../../src/parsers";
|
||||||
import { ValidationError } from "../../src/";
|
import { ValidationError } from "../../src/";
|
||||||
|
|
||||||
describe("JSON Event Format Parser", () => {
|
describe("JSON Event Format Parser", () => {
|
||||||
|
|
Loading…
Reference in New Issue