change based on serde-ts refactor

This commit is contained in:
Rowan 2025-05-21 19:35:29 -05:00
parent 78261b5384
commit 0b100c5b9e
6 changed files with 573 additions and 2188 deletions

1195
dist/index.js vendored

File diff suppressed because it is too large Load diff

1356
dist/test.js vendored

File diff suppressed because it is too large Load diff

View file

@ -2,10 +2,10 @@
"name": "serde-json-ts",
"version": "1.0.0",
"description": "",
"main": "index.js",
"main": "dist/index.js",
"scripts": {
"build": "esbuild src/index.ts --bundle --outfile=dist/index.js",
"build:test": "esbuild test.ts --platform=node --target=es2022 --bundle --outfile=dist/test.js --tsconfig=tsconfig.json",
"build:test": "esbuild test.ts --format=cjs --bundle --target=es2022 --outfile=dist/test.js --tsconfig=tsconfig.json",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],

141
src/de.ts
View file

@ -1,6 +1,6 @@
import { DefaultIterableAccessImpl, DefaultMapAccessImpl, Deserialize, Deserializer, GenericVisitor, IterableAccess, MapAccess, Visitor } from 'serde/de'
import { mixin, Nullable } from 'serde/utils'
import { IIterableAccess, MapAccess, IVisitor, IDeserializer, IterResult, Deserialize, GenericVisitor, GenericSeed } from 'serde/de'
import { unexpected } from './err'
import { GlobalRegistry, Registry } from 'serde'
type Byte = number
@ -44,20 +44,24 @@ const Token = Object.freeze({
Colon: char`:`
} as const)
export interface CommaSeparated extends MapAccess, IterableAccess { }
@mixin<MapAccess>(DefaultMapAccessImpl)
@mixin<IterableAccess>(DefaultIterableAccessImpl)
export class CommaSeparated implements MapAccess, IterableAccess {
export class CommaSeparated<T> extends MapAccess implements IIterableAccess {
private readonly de: JSONDeserializer
private readonly defaultSeed: GenericSeed<T>
private first: boolean = true
constructor(deserializer: JSONDeserializer) {
constructor(deserializer: JSONDeserializer, visitor: IVisitor<T> = new GenericVisitor()) {
super()
this.de = deserializer
this.defaultSeed = new GenericSeed(visitor)
}
nextKeySeed<T, K extends Deserialize<T>>(seed: K): Nullable<T> {
if (this.de.buffer.peek().next() === Token.RightCurly) {
return
private seed(): Deserialize {
return this.defaultSeed.deserialize.bind(this.defaultSeed) as Deserialize
}
private nextItemSeed<T, D extends Deserialize>(seed: D, end: number): IteratorResult<T> {
if (this.de.buffer.peek().next() === end) {
return IterResult.Done()
}
if (!this.first) {
@ -68,41 +72,47 @@ export class CommaSeparated implements MapAccess, IterableAccess {
}
this.first = false
return seed.deserialize(this.de)
return IterResult.Next(seed(this.de)) as IteratorResult<T>
}
nextValueSeed<T, V extends Deserialize<T>>(seed: V): Nullable<T> {
nextKeySeed<T, K extends Deserialize>(seed: K): IteratorResult<T> {
return this.nextItemSeed(seed, Token.RightCurly)
}
nextValueSeed<T, V extends Deserialize>(seed: V): IteratorResult<T> {
const next = this.de.buffer.next()
if (next !== Token.Colon) {
throw unexpected(':', next.toString(), this.de.buffer.position)
throw unexpected(':', String.fromCharCode(next), this.de.buffer.position)
}
return seed.deserialize(this.de)
return IterResult.Next(seed(this.de)) as IteratorResult<T>
}
nextElementSeed<T, I extends Deserialize<T>>(seed: I): Nullable<T> {
if (this.de.buffer.peek().next() === Token.RightSquare) {
return
}
private nextItem<T>(end: number): IteratorResult<T> {
return this.nextItemSeed(this.seed(), end)
}
if (!this.first) {
const take = this.de.buffer.take()
if (take.next() !== Token.Comma) {
throw unexpected(',', take.toString(), this.de.buffer.position)
}
}
nextKey<T>(): IteratorResult<T> {
return this.nextItem(Token.RightCurly)
}
this.first = false
return seed.deserialize(this.de)
nextValue<V>(): IteratorResult<V> {
return this.nextValueSeed(this.seed())
}
nextElement<T>(): IteratorResult<T> {
return this.nextItem(Token.RightSquare)
}
}
class StringBuffer {
class ByteArray {
private readonly view: Uint8Array
private index: number = 0
private readonly encoder: TextEncoder
private readonly decoder: TextDecoder
private index: number = 0
get position() {
return this.index
}
@ -117,11 +127,11 @@ class StringBuffer {
this.decoder = decoder
}
static fromArrayBuffer(value: ArrayBuffer, encoder?: TextEncoder, decoder?: TextDecoder): StringBuffer {
static fromArrayBuffer(value: ArrayBuffer, encoder?: TextEncoder, decoder?: TextDecoder): ByteArray {
return new this(new Uint8Array(value), encoder, decoder)
}
static fromString(value: string, encoder: TextEncoder = new TextEncoder(), decoder?: TextDecoder): StringBuffer {
static fromString(value: string, encoder: TextEncoder = new TextEncoder(), decoder?: TextDecoder): ByteArray {
return this.fromArrayBuffer(
encoder.encode(value),
encoder,
@ -151,7 +161,7 @@ class StringBuffer {
return this.decoder.decode(this.toBytes())
}
take(limit: number = 1): StringBuffer {
take(limit: number = 1): ByteArray {
const bytes = this.peek(limit)
this.index += limit
return bytes
@ -161,7 +171,7 @@ class StringBuffer {
return this.view[this.index + index]
}
takeWhile(fn: Predicate<number>): StringBuffer {
takeWhile(fn: Predicate<number>): ByteArray {
let index = 0
while (!this.done() && fn(this.at(index))) {
@ -171,7 +181,7 @@ class StringBuffer {
return this.take(index)
}
takeUntil(fn: Predicate<number>): StringBuffer {
takeUntil(fn: Predicate<number>): ByteArray {
return this.takeWhile((v: number) => !fn(v))
}
@ -180,7 +190,7 @@ class StringBuffer {
return this
}
dropWhile(fn: Predicate<number>): StringBuffer {
dropWhile(fn: Predicate<number>): ByteArray {
let index = 0
while (!this.done() && fn(this.at(index))) {
@ -190,11 +200,11 @@ class StringBuffer {
return this.drop(index)
}
dropUntil(fn: Predicate<number>): StringBuffer {
dropUntil(fn: Predicate<number>): ByteArray {
return this.dropWhile((v: number) => !fn(v))
}
peek(limit: number = 1): StringBuffer {
peek(limit: number = 1): ByteArray {
const index = this.index
return this.slice(index, index + limit)
}
@ -211,7 +221,7 @@ class StringBuffer {
}
slice(start?: number, end?: number) {
return new StringBuffer(
return new ByteArray(
this.view.subarray(start, end),
this.encoder,
this.decoder
@ -233,18 +243,20 @@ class StringBuffer {
}
}
export class JSONDeserializer implements Deserializer {
readonly buffer: StringBuffer
export class JSONDeserializer implements IDeserializer {
readonly buffer: ByteArray
readonly registry: Registry
constructor(buffer: StringBuffer) {
constructor(buffer: ByteArray, registry: Registry = GlobalRegistry) {
this.buffer = buffer
this.registry = registry
}
static fromString(value: string): JSONDeserializer {
return new this(StringBuffer.fromString(value))
return new this(ByteArray.fromString(value))
}
deserializeAny<T, V extends Visitor<T>>(visitor: V): T {
deserializeAny<T>(visitor: IVisitor<T>): T {
const peek = this.buffer.peek()
const nextByte = peek.take()
const byte = nextByte.next()
@ -267,7 +279,7 @@ export class JSONDeserializer implements Deserializer {
}
}
deserializeNull<T, V extends Visitor<T>>(visitor: V): T {
deserializeNull<T, V extends IVisitor<T>>(visitor: V): T {
if (this.buffer.startsWith('null')) {
this.buffer.take(4)
}
@ -275,11 +287,11 @@ export class JSONDeserializer implements Deserializer {
return visitor.visitNull()
}
private _deserializeObject<T>(fn: (value: CommaSeparated) => T): T {
deserializeObject<T, V extends IVisitor<T>>(visitor: V): T {
let next = this.buffer.take()
if (next.next() === Token.LeftCurly) {
const value = fn(new CommaSeparated(this))
const value = visitor.visitObject(new CommaSeparated(this))
next = this.buffer.take()
if (next.next() === Token.RightCurly) {
@ -292,27 +304,11 @@ export class JSONDeserializer implements Deserializer {
}
}
deserializeObject<T, V extends Visitor<T>>(visitor: V): T {
return this._deserializeObject(visitor.visitObject.bind(visitor))
deserializeClass<T, V extends IVisitor<T>>(_name: string, visitor: V): T {
return this.deserializeObject(visitor)
}
deserializeClass<T, V extends Visitor<T>>(name: string, visitor: V): T {
if (this.buffer.peek(9).startsWith('{"type":"')) {
const name = this.buffer.drop(9).takeUntil((v: number) => v === Token.Quote)
if (this.buffer.startsWith('","object":')) {
this.buffer.drop(11)
return this._deserializeObject(visitor.visitClass.bind(visitor, name.toString()))
} else {
throw unexpected('"object" property', this.buffer.toString(), this.buffer.position)
}
} else {
throw unexpected('"type" property', this.buffer.toString(), this.buffer.position)
}
}
deserializeString<T, V extends Visitor<T>>(visitor: V): T {
deserializeString<T, V extends IVisitor<T>>(visitor: V): T {
const next = this.buffer.take()
if (next.next() === Token.Quote) {
let index = -1
@ -333,7 +329,7 @@ export class JSONDeserializer implements Deserializer {
}
}
deserializeNumber<T, V extends Visitor<T>>(visitor: V): T {
deserializeNumber<T, V extends IVisitor<T>>(visitor: V): T {
const next = this.buffer.peek().next()
if (isNumericToken(next)) {
@ -350,11 +346,11 @@ export class JSONDeserializer implements Deserializer {
throw unexpected('"-", ".", or 0..=9', next.toString(), this.buffer.position)
}
deserializeBigInt<T, V extends Visitor<T>>(visitor: V): T {
deserializeBigInt<T, V extends IVisitor<T>>(visitor: V): T {
return this.deserializeNumber(visitor)
}
deserializeBoolean<T, V extends Visitor<T>>(visitor: V): T {
deserializeBoolean<T, V extends IVisitor<T>>(visitor: V): T {
const next = this.buffer.next()
let length = 3
@ -371,15 +367,15 @@ export class JSONDeserializer implements Deserializer {
return visitor.visitBoolean(length === 3)
}
deserializeSymbol<T, V extends Visitor<T>>(_visitor: V): T {
deserializeSymbol<T, V extends IVisitor<T>>(_visitor: V): T {
throw new Error('Method not implemented.')
}
deserializeIterable<T, V extends Visitor<T>>(visitor: V): T {
deserializeIterable<T, V extends IVisitor<T>>(visitor: V): T {
let next = this.buffer.take()
if (next.next() === Token.LeftSquare) {
const value = visitor.visitIterable!(new CommaSeparated(this))
const value = visitor.visitIterable(new CommaSeparated(this))
next = this.buffer.take()
if (next.next() === Token.RightSquare) {
@ -391,5 +387,10 @@ export class JSONDeserializer implements Deserializer {
throw unexpected('[', next.toString(), this.buffer.position)
}
}
deserializeFunction<T, V extends IVisitor<T>>(_visitor: V): T {
throw new Error('Method not implemented.')
}
}

View file

@ -1,16 +1,16 @@
import { serializeWith } from 'serde/ser'
import { JSONSerializer } from './ser'
import { Deserialize } from 'serde/de'
import { deserialize, Deserialize } from 'serde/de'
import { JSONDeserializer } from './de'
import { serialize } from 'serde/ser'
export function toString(value: any): string {
const serializer = new JSONSerializer()
serializeWith(serializer, value)
serialize(serializer, value)
return serializer.output
}
export function fromString<T, D extends Deserialize<T>>(value: string, into: D): T {
const deserializer = JSONDeserializer.fromString(value)
return into.deserialize(deserializer)
return deserialize(deserializer, into)
}

View file

@ -1,27 +1,28 @@
import { IterableSerializer, ObjectSerializer, Serializable, Serializer, serializeWith } from 'serde/ser'
import { ISerializeIterable, ISerializeObject, ISerializer, serialize, SerializeObject } from "serde/ser"
class JSONObjectSerializer implements ObjectSerializer<void> {
class JSONObjectSerializer extends SerializeObject<void> {
private ser: JSONSerializer
private first: boolean = true
constructor(serializer: JSONSerializer) {
super()
this.ser = serializer
serializer.write('{')
}
serializeKey<U extends Serializable>(key: U): void {
serializeKey<U>(key: U): void {
if (!this.first) {
this.ser.write(',')
} else {
this.first = false
}
serializeWith(this.ser, key)
serialize(this.ser, key)
this.ser.write(':')
}
serializeValue<U extends Serializable>(value: U): void {
serializeWith(this.ser, value)
serializeValue<U>(value: U): void {
serialize(this.ser, value)
}
end(): void {
@ -29,7 +30,7 @@ class JSONObjectSerializer implements ObjectSerializer<void> {
}
}
class JSONIterableSerializer implements IterableSerializer<void> {
class JSONIterableSerializer implements ISerializeIterable<void> {
private ser: JSONSerializer
private first: boolean = true
@ -38,14 +39,14 @@ class JSONIterableSerializer implements IterableSerializer<void> {
serializer.write('[')
}
serializeElement<U extends Serializable>(element: U): void {
serializeElement<U>(element: U): void {
if (!this.first) {
this.ser.write(',')
} else {
this.first = false
}
serializeWith(this.ser, element)
serialize(this.ser, element)
}
end(): void {
@ -53,35 +54,7 @@ class JSONIterableSerializer implements IterableSerializer<void> {
}
}
class JSONClassSerializer implements ObjectSerializer<void> {
outer: JSONObjectSerializer
inner: JSONObjectSerializer
constructor(serializer: JSONSerializer, name: string) {
this.outer = new JSONObjectSerializer(serializer)
this.outer.serializeKey('type')
this.outer.serializeValue(name)
this.outer.serializeKey('object')
this.inner = new JSONObjectSerializer(serializer)
}
serializeKey<U extends Serializable>(key: U): void {
return this.inner.serializeKey(key)
}
serializeValue<U extends Serializable>(value: U): void {
return this.inner.serializeValue(value)
}
end(): void {
this.inner.end()
this.outer.end()
}
}
export class JSONSerializer implements Serializer<void> {
export class JSONSerializer implements ISerializer<void> {
output: string = ''
write(value: string) {
@ -105,12 +78,12 @@ export class JSONSerializer implements Serializer<void> {
}
}
serializeObject(): ObjectSerializer<void> {
serializeObject(): ISerializeObject<void> {
return new JSONObjectSerializer(this)
}
serializeClass(name: PropertyKey): ObjectSerializer<void> {
return new JSONClassSerializer(this, name as string)
serializeClass(_name: PropertyKey): ISerializeObject<void> {
return this.serializeObject()
}
serializeNumber(value: number) {
@ -121,7 +94,7 @@ export class JSONSerializer implements Serializer<void> {
this.write(value.toString())
}
serializeIterable(): IterableSerializer<void> {
serializeIterable(): ISerializeIterable<void> {
return new JSONIterableSerializer(this)
}