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", "name": "serde-json-ts",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",
"main": "index.js", "main": "dist/index.js",
"scripts": { "scripts": {
"build": "esbuild src/index.ts --bundle --outfile=dist/index.js", "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" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"keywords": [], "keywords": [],

141
src/de.ts
View file

@ -1,6 +1,6 @@
import { DefaultIterableAccessImpl, DefaultMapAccessImpl, Deserialize, Deserializer, GenericVisitor, IterableAccess, MapAccess, Visitor } from 'serde/de' import { IIterableAccess, MapAccess, IVisitor, IDeserializer, IterResult, Deserialize, GenericVisitor, GenericSeed } from 'serde/de'
import { mixin, Nullable } from 'serde/utils'
import { unexpected } from './err' import { unexpected } from './err'
import { GlobalRegistry, Registry } from 'serde'
type Byte = number type Byte = number
@ -44,20 +44,24 @@ const Token = Object.freeze({
Colon: char`:` Colon: char`:`
} as const) } as const)
export interface CommaSeparated extends MapAccess, IterableAccess { } export class CommaSeparated<T> extends MapAccess implements IIterableAccess {
@mixin<MapAccess>(DefaultMapAccessImpl)
@mixin<IterableAccess>(DefaultIterableAccessImpl)
export class CommaSeparated implements MapAccess, IterableAccess {
private readonly de: JSONDeserializer private readonly de: JSONDeserializer
private readonly defaultSeed: GenericSeed<T>
private first: boolean = true private first: boolean = true
constructor(deserializer: JSONDeserializer) { constructor(deserializer: JSONDeserializer, visitor: IVisitor<T> = new GenericVisitor()) {
super()
this.de = deserializer this.de = deserializer
this.defaultSeed = new GenericSeed(visitor)
} }
nextKeySeed<T, K extends Deserialize<T>>(seed: K): Nullable<T> { private seed(): Deserialize {
if (this.de.buffer.peek().next() === Token.RightCurly) { return this.defaultSeed.deserialize.bind(this.defaultSeed) as Deserialize
return }
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) { if (!this.first) {
@ -68,41 +72,47 @@ export class CommaSeparated implements MapAccess, IterableAccess {
} }
this.first = false 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() const next = this.de.buffer.next()
if (next !== Token.Colon) { 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> { private nextItem<T>(end: number): IteratorResult<T> {
if (this.de.buffer.peek().next() === Token.RightSquare) { return this.nextItemSeed(this.seed(), end)
return }
}
if (!this.first) { nextKey<T>(): IteratorResult<T> {
const take = this.de.buffer.take() return this.nextItem(Token.RightCurly)
if (take.next() !== Token.Comma) { }
throw unexpected(',', take.toString(), this.de.buffer.position)
}
}
this.first = false nextValue<V>(): IteratorResult<V> {
return seed.deserialize(this.de) return this.nextValueSeed(this.seed())
}
nextElement<T>(): IteratorResult<T> {
return this.nextItem(Token.RightSquare)
} }
} }
class StringBuffer { class ByteArray {
private readonly view: Uint8Array private readonly view: Uint8Array
private index: number = 0
private readonly encoder: TextEncoder private readonly encoder: TextEncoder
private readonly decoder: TextDecoder private readonly decoder: TextDecoder
private index: number = 0
get position() { get position() {
return this.index return this.index
} }
@ -117,11 +127,11 @@ class StringBuffer {
this.decoder = decoder 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) 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( return this.fromArrayBuffer(
encoder.encode(value), encoder.encode(value),
encoder, encoder,
@ -151,7 +161,7 @@ class StringBuffer {
return this.decoder.decode(this.toBytes()) return this.decoder.decode(this.toBytes())
} }
take(limit: number = 1): StringBuffer { take(limit: number = 1): ByteArray {
const bytes = this.peek(limit) const bytes = this.peek(limit)
this.index += limit this.index += limit
return bytes return bytes
@ -161,7 +171,7 @@ class StringBuffer {
return this.view[this.index + index] return this.view[this.index + index]
} }
takeWhile(fn: Predicate<number>): StringBuffer { takeWhile(fn: Predicate<number>): ByteArray {
let index = 0 let index = 0
while (!this.done() && fn(this.at(index))) { while (!this.done() && fn(this.at(index))) {
@ -171,7 +181,7 @@ class StringBuffer {
return this.take(index) return this.take(index)
} }
takeUntil(fn: Predicate<number>): StringBuffer { takeUntil(fn: Predicate<number>): ByteArray {
return this.takeWhile((v: number) => !fn(v)) return this.takeWhile((v: number) => !fn(v))
} }
@ -180,7 +190,7 @@ class StringBuffer {
return this return this
} }
dropWhile(fn: Predicate<number>): StringBuffer { dropWhile(fn: Predicate<number>): ByteArray {
let index = 0 let index = 0
while (!this.done() && fn(this.at(index))) { while (!this.done() && fn(this.at(index))) {
@ -190,11 +200,11 @@ class StringBuffer {
return this.drop(index) return this.drop(index)
} }
dropUntil(fn: Predicate<number>): StringBuffer { dropUntil(fn: Predicate<number>): ByteArray {
return this.dropWhile((v: number) => !fn(v)) return this.dropWhile((v: number) => !fn(v))
} }
peek(limit: number = 1): StringBuffer { peek(limit: number = 1): ByteArray {
const index = this.index const index = this.index
return this.slice(index, index + limit) return this.slice(index, index + limit)
} }
@ -211,7 +221,7 @@ class StringBuffer {
} }
slice(start?: number, end?: number) { slice(start?: number, end?: number) {
return new StringBuffer( return new ByteArray(
this.view.subarray(start, end), this.view.subarray(start, end),
this.encoder, this.encoder,
this.decoder this.decoder
@ -233,18 +243,20 @@ class StringBuffer {
} }
} }
export class JSONDeserializer implements Deserializer { export class JSONDeserializer implements IDeserializer {
readonly buffer: StringBuffer readonly buffer: ByteArray
readonly registry: Registry
constructor(buffer: StringBuffer) { constructor(buffer: ByteArray, registry: Registry = GlobalRegistry) {
this.buffer = buffer this.buffer = buffer
this.registry = registry
} }
static fromString(value: string): JSONDeserializer { 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 peek = this.buffer.peek()
const nextByte = peek.take() const nextByte = peek.take()
const byte = nextByte.next() 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')) { if (this.buffer.startsWith('null')) {
this.buffer.take(4) this.buffer.take(4)
} }
@ -275,11 +287,11 @@ export class JSONDeserializer implements Deserializer {
return visitor.visitNull() 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() let next = this.buffer.take()
if (next.next() === Token.LeftCurly) { if (next.next() === Token.LeftCurly) {
const value = fn(new CommaSeparated(this)) const value = visitor.visitObject(new CommaSeparated(this))
next = this.buffer.take() next = this.buffer.take()
if (next.next() === Token.RightCurly) { if (next.next() === Token.RightCurly) {
@ -292,27 +304,11 @@ export class JSONDeserializer implements Deserializer {
} }
} }
deserializeObject<T, V extends Visitor<T>>(visitor: V): T { deserializeClass<T, V extends IVisitor<T>>(_name: string, visitor: V): T {
return this._deserializeObject(visitor.visitObject.bind(visitor)) return this.deserializeObject(visitor)
} }
deserializeClass<T, V extends Visitor<T>>(name: string, visitor: V): T { deserializeString<T, V extends IVisitor<T>>(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 {
const next = this.buffer.take() const next = this.buffer.take()
if (next.next() === Token.Quote) { if (next.next() === Token.Quote) {
let index = -1 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() const next = this.buffer.peek().next()
if (isNumericToken(next)) { if (isNumericToken(next)) {
@ -350,11 +346,11 @@ export class JSONDeserializer implements Deserializer {
throw unexpected('"-", ".", or 0..=9', next.toString(), this.buffer.position) 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) 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() const next = this.buffer.next()
let length = 3 let length = 3
@ -371,15 +367,15 @@ export class JSONDeserializer implements Deserializer {
return visitor.visitBoolean(length === 3) 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.') 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() let next = this.buffer.take()
if (next.next() === Token.LeftSquare) { if (next.next() === Token.LeftSquare) {
const value = visitor.visitIterable!(new CommaSeparated(this)) const value = visitor.visitIterable(new CommaSeparated(this))
next = this.buffer.take() next = this.buffer.take()
if (next.next() === Token.RightSquare) { if (next.next() === Token.RightSquare) {
@ -391,5 +387,10 @@ export class JSONDeserializer implements Deserializer {
throw unexpected('[', next.toString(), this.buffer.position) 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 { JSONSerializer } from './ser'
import { Deserialize } from 'serde/de' import { deserialize, Deserialize } from 'serde/de'
import { JSONDeserializer } from './de' import { JSONDeserializer } from './de'
import { serialize } from 'serde/ser'
export function toString(value: any): string { export function toString(value: any): string {
const serializer = new JSONSerializer() const serializer = new JSONSerializer()
serializeWith(serializer, value) serialize(serializer, value)
return serializer.output return serializer.output
} }
export function fromString<T, D extends Deserialize<T>>(value: string, into: D): T { export function fromString<T, D extends Deserialize<T>>(value: string, into: D): T {
const deserializer = JSONDeserializer.fromString(value) 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 ser: JSONSerializer
private first: boolean = true private first: boolean = true
constructor(serializer: JSONSerializer) { constructor(serializer: JSONSerializer) {
super()
this.ser = serializer this.ser = serializer
serializer.write('{') serializer.write('{')
} }
serializeKey<U extends Serializable>(key: U): void { serializeKey<U>(key: U): void {
if (!this.first) { if (!this.first) {
this.ser.write(',') this.ser.write(',')
} else { } else {
this.first = false this.first = false
} }
serializeWith(this.ser, key) serialize(this.ser, key)
this.ser.write(':') this.ser.write(':')
} }
serializeValue<U extends Serializable>(value: U): void { serializeValue<U>(value: U): void {
serializeWith(this.ser, value) serialize(this.ser, value)
} }
end(): void { 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 ser: JSONSerializer
private first: boolean = true private first: boolean = true
@ -38,14 +39,14 @@ class JSONIterableSerializer implements IterableSerializer<void> {
serializer.write('[') serializer.write('[')
} }
serializeElement<U extends Serializable>(element: U): void { serializeElement<U>(element: U): void {
if (!this.first) { if (!this.first) {
this.ser.write(',') this.ser.write(',')
} else { } else {
this.first = false this.first = false
} }
serializeWith(this.ser, element) serialize(this.ser, element)
} }
end(): void { end(): void {
@ -53,35 +54,7 @@ class JSONIterableSerializer implements IterableSerializer<void> {
} }
} }
class JSONClassSerializer implements ObjectSerializer<void> { export class JSONSerializer implements ISerializer<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> {
output: string = '' output: string = ''
write(value: string) { write(value: string) {
@ -105,12 +78,12 @@ export class JSONSerializer implements Serializer<void> {
} }
} }
serializeObject(): ObjectSerializer<void> { serializeObject(): ISerializeObject<void> {
return new JSONObjectSerializer(this) return new JSONObjectSerializer(this)
} }
serializeClass(name: PropertyKey): ObjectSerializer<void> { serializeClass(_name: PropertyKey): ISerializeObject<void> {
return new JSONClassSerializer(this, name as string) return this.serializeObject()
} }
serializeNumber(value: number) { serializeNumber(value: number) {
@ -121,7 +94,7 @@ export class JSONSerializer implements Serializer<void> {
this.write(value.toString()) this.write(value.toString())
} }
serializeIterable(): IterableSerializer<void> { serializeIterable(): ISerializeIterable<void> {
return new JSONIterableSerializer(this) return new JSONIterableSerializer(this)
} }