Skip to content

Commit

Permalink
fix(smithy-client): string.toString requires this be a String (smithy…
Browse files Browse the repository at this point in the history
…-lang#1027)

* fix(smithy-client): string.toString requires this be a String

Because of Because of microsoft/tslib#95,
TS 'extends' shim doesn't support extending native types like String.
So here we create StringWrapper that duplicate everything from String
class including its prototype chain. So we can extend from here.

* fix: typo
  • Loading branch information
AllanZhengYP authored and srchase committed Jun 16, 2023
1 parent cc0e87e commit 5db1522
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 2 deletions.
36 changes: 36 additions & 0 deletions packages/smithy-client/src/lazy-json.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { LazyJsonString } from "./lazy-json";
describe("LazyJsonString", () => {
it("should has string methods", () => {
const jsonValue = new LazyJsonString('"foo"');
expect(jsonValue.length).toBe(5);
expect(jsonValue.toString()).toBe('"foo"');
});

it("should deserialize json properly", () => {
const jsonValue = new LazyJsonString('"foo"');
expect(jsonValue.deserializeJSON()).toBe("foo");
const wrongJsonValue = new LazyJsonString("foo");
expect(() => wrongJsonValue.deserializeJSON()).toThrow();
});

it("should get JSON string properly", () => {
const jsonValue = new LazyJsonString('{"foo", "bar"}');
expect(jsonValue.toJSON()).toBe('{"foo", "bar"}');
});

it("can instantiate from LazyJsonString class", () => {
const original = new LazyJsonString('"foo"');
const newOne = LazyJsonString.fromObject(original);
expect(newOne.toString()).toBe('"foo"');
});

it("can instantiate from String class", () => {
const jsonValue = LazyJsonString.fromObject(new String('"foo"'));
expect(jsonValue.toString()).toBe('"foo"');
});

it("can instantiate from object", () => {
const jsonValue = LazyJsonString.fromObject({ foo: "bar" });
expect(jsonValue.toString()).toBe('{"foo":"bar"}');
});
});
35 changes: 33 additions & 2 deletions packages/smithy-client/src/lazy-json.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,38 @@
/**
* Lazy String holder for JSON typed contents.
*/
export class LazyJsonString extends String {

interface StringWrapper {
new (arg: any): String;
}

/**
* Because of https://github.com/microsoft/tslib/issues/95,
* TS 'extends' shim doesn't support extending native types like String.
* So here we create StringWrapper that duplicate everything from String
* class including its prototype chain. So we can extend from here.
*/
// @ts-ignore StringWrapper implementation is not a simple constructor
export const StringWrapper: StringWrapper = function() {
//@ts-ignore 'this' cannot be assigned to any, but Object.getPrototypeOf accepts any
const Class = Object.getPrototypeOf(this).constructor;
const Constructor = Function.bind.apply(String, [null as any, ...arguments]);
//@ts-ignore Call wrapped String constructor directly, don't bother typing it.
const instance = new Constructor();
Object.setPrototypeOf(instance, Class.prototype);
return instance as String;
};
StringWrapper.prototype = Object.create(String.prototype, {
constructor: {
value: StringWrapper,
enumerable: false,
writable: true,
configurable: true
}
});
Object.setPrototypeOf(StringWrapper, String);

export class LazyJsonString extends StringWrapper {
deserializeJSON(): any {
return JSON.parse(super.toString());
}
Expand All @@ -13,7 +44,7 @@ export class LazyJsonString extends String {
static fromObject(object: any): LazyJsonString {
if (object instanceof LazyJsonString) {
return object;
} else if (object instanceof String || typeof object === 'string') {
} else if (object instanceof String || typeof object === "string") {
return new LazyJsonString(object);
}
return new LazyJsonString(JSON.stringify(object));
Expand Down

0 comments on commit 5db1522

Please sign in to comment.