change based on serde-ts refactor
This commit is contained in:
parent
78261b5384
commit
0b100c5b9e
6 changed files with 573 additions and 2188 deletions
1195
dist/index.js
vendored
1195
dist/index.js
vendored
File diff suppressed because it is too large
Load diff
1356
dist/test.js
vendored
1356
dist/test.js
vendored
File diff suppressed because it is too large
Load diff
|
@ -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
141
src/de.ts
|
@ -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.')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
57
src/ser.ts
57
src/ser.ts
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue