From c6b73369400e84f36b71ffd07dcf2f3c3b5d1356 Mon Sep 17 00:00:00 2001 From: rowan Date: Sun, 25 May 2025 12:43:05 -0500 Subject: [PATCH] add readme --- README.md | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..6afe3c3 --- /dev/null +++ b/README.md @@ -0,0 +1,129 @@ +# serde-json-ts +a (de)serializer for [serde-ts](https://git.kitsu.cafe/rowan/serde-ts) + +# Usage +```ts +import { Null } from 'serde' +import { fromString, toString } from 'serde-json-ts' + +toString(true) // "true" +toString(null) // "null" +toString({ test: 1 }) // '{"test":1}' +toString([1, 2, 3]) // '[1,2,3]' + +fromString("true", Boolean) // true +fromString("null", Null) // null +fromString('{"test":1}', Object) // { test: 1 } +fromString('[1,2,3]', Array) // [1, 2, 3] + +class Recipient { + static { + registerSerialize(Recipient, Recipient.serialize) + registerDeserialize(Recipient, Recipient.deserialize) + } + + private readonly email: string + readonly displayName: string + + constructor(email: string, displayName: string) { + this.email = email + this.displayName = displayName + } + + static serialize(serializer: ISerializer, recipient: Recipient) { + // there's no real reason to serialize it this way other than + // we can. not good for production though + return serializer.serializeString(`${recipient.displayName}<${recipient.email}>`) + } + + static deserialize(deserializer: IDeserializer) { + return deserializer.deserializeString({ + visitString(value: string) { + let [displayName, email] = value.split('<') + email = email.slice(0, -1) + return new Recipient(displayName, email) + } + }) + } +} + +class Message { + static { + registerSerialize(Message, Message.serialize) + registerDeserialize(Message, Message.deserialize) + } + + readonly from: Recipient + readonly to: Recipient[] + readonly text: string + + constructor(from: Recipient, to: Recipient[], text: string) { + this.from = from + this.to = to + this.text = text + } + + static serialize(serializer: ISerializer, message: Message) { + // we could hint that the size is 3, but json doesn't care about size, only shape. same + const serializeObj = serializer.serializeObject() + + serializeObj.serializeEntry('from', message.from) + serializeObj.serializeEntry('to', message.to) + serializeObj.serializeEntry('text', message.text) + + return serializeObj.end() + } + + static deserialize(deserializer: IDeserializer) { + // signal to the deserializer that we are expecting an object + return deserializer.deserializeObject({ + visitObject(access: IMapAccess) { + let from, to, text + + for (const [key, value] of access) { + switch (key) { + case 'from': + from = forward(value, Recipient) + break + case 'to': + to = value.map((v: any) => forward(v, Recipient)) + break + case 'text': + text = value + break + } + } + + return new Message(from, to, text) + } + }) + } +} + +const bob = new Recipient('Bob', 'bob@security.lol') +const alice = new Recipient('Alice', 'alice@balloon.party') +const alicesMom = new Recipient("Alice's Mom", 'alice.mom@malware.zip') +const message = new Message(bob, [alice, alicesMom], 'i hope this email finds you before i do') + +const messageSerial = toString(message) +console.log(messageSerial) +// {"from":"bob@security.lol","to":["alice@balloon.party","alice.mom@malware.zip"],"text":"i hope this email finds you before i do"} + +const messageDecereal = fromString(messageSerial, Message) +console.log(messageDecereal) +/* + Message { + from: Recipient { email: 'bob@security.lol', displayName: 'Bob' }, + to: [ + Recipient { email: 'alice@balloon.party', displayName: 'Alice' }, + Recipient { + email: 'alice.mom@malware.zip', + displayName: "Alice's Mom" + } + ], + text: 'i hope this email finds you before i do' + } + */ + +``` +