No description
Find a file
2025-05-27 21:16:18 -05:00
dist fix esbuild config 2025-05-27 21:16:18 -05:00
src add type declarations 2025-05-27 00:27:06 -05:00
types add type declarations 2025-05-27 00:27:06 -05:00
.gitignore initial commit 2025-05-19 13:31:22 -05:00
package-lock.json oops make serde Not a local package 2025-05-25 18:01:42 -05:00
package.json fix esbuild config 2025-05-27 21:16:18 -05:00
README.md update readme 2025-05-25 13:02:20 -05:00
tsconfig.json fix esbuild config 2025-05-27 21:16:18 -05:00

serde-json-ts

a (de)serializer for serde-ts

Usage

fromString and toString are provided as easy entrypoints into the (de)serializer. JSONSerializer and JSONDeserializer are also directly usable in more complex scenarios

Example

import { Null, registerSerialize, registerDeserialize } from 'serde'
import { ISerializer } from 'serde/ser'
import { forward, IDeserializer, IIterableAccess, IMapAccess } from 'serde/de'
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<string>)
    registerDeserialize(Recipient, Recipient.deserialize)
  }

  readonly displayName: string
  private readonly email: string

  constructor(displayName: string, email: string,) {
    this.displayName = displayName
    this.email = email
  }

  static serialize<T>(serializer: ISerializer<T>, 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<string>)
    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<T>(serializer: ISerializer<T>, 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<bob@security.lol>","to":["Alice<alice@balloon.party>","Alice's Mom<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 { displayName: 'Bob', email: 'bob@security.lol' },
      to: [
        Recipient { displayName: 'Alice', email: 'alice@balloon.party' },
        Recipient {
          displayName: "Alice's Mom",
          email: 'alice.mom@malware.zip'
        }
      ],
      text: 'i hope this email finds you before i do'
    }
 */