Skip to content

fix: allow TypedArray for binary data #494

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/event/cloudevent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ See: https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system`);

set data(value: T | undefined) {
if (isBinary(value)) {
this.data_base64 = asBase64(value);
this.data_base64 = asBase64(value as unknown as Buffer);
}
this.#_data = value;
}
Expand Down
13 changes: 9 additions & 4 deletions src/event/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@

import { ErrorObject } from "ajv";

export type TypeArray = Int8Array | Uint8Array | Int16Array | Uint16Array |
Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array;


/**
* An Error class that will be thrown when a CloudEvent
* cannot be properly validated against a specification.
Expand Down Expand Up @@ -36,7 +40,7 @@ export const isDefined = (v: unknown): boolean => v !== null && typeof v !== "un
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): v is Date => v instanceof Date;
export const isBinary = (v: unknown): v is Uint32Array => v instanceof Uint32Array;
export const isBinary = (v: unknown): boolean => ArrayBuffer.isView(v);

export const isStringOrThrow = (v: unknown, t: Error): boolean =>
isString(v)
Expand Down Expand Up @@ -73,7 +77,7 @@ export const isBase64 = (value: unknown): boolean =>

export const isBuffer = (value: unknown): boolean => value instanceof Buffer;

export const asBuffer = (value: string | Buffer | Uint32Array): Buffer =>
export const asBuffer = (value: string | Buffer | TypeArray): Buffer =>
isBinary(value)
? Buffer.from((value as unknown) as string)
: isBuffer(value)
Expand All @@ -82,7 +86,8 @@ export const asBuffer = (value: string | Buffer | Uint32Array): 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 asBase64 =
(value: string | Buffer | TypeArray): string => asBuffer(value).toString("base64");

export const clone = (o: Record<string, unknown>): Record<string, unknown> => JSON.parse(JSON.stringify(o));

Expand All @@ -97,5 +102,5 @@ export const asData = (data: unknown, contentType: string): string => {
return isBinary(maybeJson) ? asBase64(maybeJson) : maybeJson;
};

export const isValidType = (v: boolean | number | string | Date | Uint32Array | unknown): boolean =>
export const isValidType = (v: boolean | number | string | Date | TypeArray | unknown): boolean =>
isBoolean(v) || isInteger(v) || isString(v) || isDate(v) || isBinary(v) || isObject(v);
62 changes: 54 additions & 8 deletions test/integration/spec_1_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,14 +173,60 @@ describe("CloudEvents Spec v1.0", () => {
expect(typeof ce.data).to.equal("string");
});

it("should be ok when type is 'Uint32Array' for 'Binary'", () => {
const dataString = ")(*~^my data for ce#@#$%";

const dataBinary = Uint32Array.from(dataString, (c) => c.codePointAt(0) as number);
const expected = asBase64(dataBinary);

const ce = cloudevent.cloneWith({ datacontenttype: "text/plain", data: dataBinary });
expect(ce.data_base64).to.equal(expected);
const dataString = ")(*~^my data for ce#@#$%";
const testCases = [
{
type: Int8Array,
data: Int8Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Int8Array.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Uint8Array,
data: Uint8Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Uint8Array.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Int16Array,
data: Int16Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Int16Array.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Uint16Array,
data: Uint16Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Uint16Array.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Int32Array,
data: Int32Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Int32Array.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Uint32Array,
data: Uint32Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Uint32Array.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Uint8ClampedArray,
data: Uint8ClampedArray.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Uint8ClampedArray.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Float32Array,
data: Float32Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Float32Array.from(dataString, (c) => c.codePointAt(0) as number))
},
{
type: Float64Array,
data: Float64Array.from(dataString, (c) => c.codePointAt(0) as number),
expected: asBase64(Float64Array.from(dataString, (c) => c.codePointAt(0) as number))
},
];

testCases.forEach((test) => {
it(`should be ok when type is '${test.type.name}' for 'Binary'`, () => {
const ce = cloudevent.cloneWith({ datacontenttype: "text/plain", data: test.data });
expect(ce.data_base64).to.equal(test.expected);
});
});
});
});