Fix parameter ordering and defaults
This commit is contained in:
parent
013c5f4dae
commit
1743756097
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "preserves",
|
||||
"version": "0.5.0",
|
||||
"version": "0.5.1",
|
||||
"description": "Experimental data serialization format",
|
||||
"homepage": "https://gitlab.com/preserves/preserves",
|
||||
"license": "Apache-2.0",
|
||||
|
|
|
@ -135,8 +135,8 @@ export class Decoder<T extends object> {
|
|||
return this.includeAnnotations ? new Annotated(v) : v;
|
||||
}
|
||||
|
||||
static dictionaryFromArray<T extends object>(vs: Value<T>[]): Dictionary<T, Value<T>> {
|
||||
const d = new Dictionary<T, Value<T>>();
|
||||
static dictionaryFromArray<T extends object>(vs: Value<T>[]): Dictionary<Value<T>, T> {
|
||||
const d = new Dictionary<Value<T>, T>();
|
||||
if (vs.length % 2) throw new DecodeError("Missing dictionary value");
|
||||
for (let i = 0; i < vs.length; i += 2) {
|
||||
d.set(vs[i], vs[i+1]);
|
||||
|
|
|
@ -9,15 +9,17 @@ import { _iterMap, FlexMap, FlexSet } from './flex';
|
|||
const textEncoder = new TextEncoder();
|
||||
const textDecoder = new TextDecoder();
|
||||
|
||||
export type Value<T extends object> = Atom | Compound<T> | T | Annotated<T>;
|
||||
export type DefaultPointer = object
|
||||
|
||||
export type Value<T extends object = DefaultPointer> = Atom | Compound<T> | T | Annotated<T>;
|
||||
export type Atom = boolean | Single | Double | number | string | Bytes | symbol;
|
||||
export type Compound<T extends object> = Record<T> | Array<Value<T>> | Set<T> | Dictionary<T, Value<T>>;
|
||||
export type Compound<T extends object = DefaultPointer> = Record<T> | Array<Value<T>> | Set<T> | Dictionary<Value<T>, T>;
|
||||
|
||||
export const IsPreservesRecord = Symbol.for('IsPreservesRecord');
|
||||
export const IsPreservesBytes = Symbol.for('IsPreservesBytes');
|
||||
export const IsPreservesAnnotated = Symbol.for('IsPreservesAnnotated');
|
||||
|
||||
export function fromJS<T extends object>(x: any): Value<T> {
|
||||
export function fromJS<T extends object = DefaultPointer>(x: any): Value<T> {
|
||||
switch (typeof x) {
|
||||
case 'number':
|
||||
if (!Number.isInteger(x)) {
|
||||
|
@ -95,7 +97,7 @@ export abstract class Float {
|
|||
}
|
||||
|
||||
export class Single extends Float implements Preservable<never> {
|
||||
[AsPreserve]<T extends object>(): Value<T> {
|
||||
[AsPreserve]<T extends object = DefaultPointer>(): Value<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -116,7 +118,7 @@ export class Single extends Float implements Preservable<never> {
|
|||
}
|
||||
|
||||
export class Double extends Float implements Preservable<never> {
|
||||
[AsPreserve]<T extends object>(): Value<T> {
|
||||
[AsPreserve]<T extends object = DefaultPointer>(): Value<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -254,7 +256,7 @@ export class Bytes implements Preservable<never> {
|
|||
return this.asPreservesText();
|
||||
}
|
||||
|
||||
[AsPreserve]<T extends object>(): Value<T> {
|
||||
[AsPreserve]<T extends object = DefaultPointer>(): Value<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -416,7 +418,7 @@ keys lastIndexOf reduce reduceRight some toLocaleString values`.split(/\s+/))
|
|||
Bytes.prototype[Symbol.iterator] = function () { return this._view[Symbol.iterator](); };
|
||||
})();
|
||||
|
||||
export class Record<T extends object> extends Array<Value<T>> {
|
||||
export class Record<T extends object = DefaultPointer> extends Array<Value<T>> {
|
||||
readonly label: Value<T>;
|
||||
|
||||
constructor(label: Value<T>, fieldsJS: any[]) {
|
||||
|
@ -482,11 +484,11 @@ export class Record<T extends object> extends Array<Value<T>> {
|
|||
}).join(', ') + ')';
|
||||
}
|
||||
|
||||
static makeConstructor<T extends object>(labelSymbolText: string, fieldNames: string[]): RecordConstructor<T> {
|
||||
static makeConstructor<T extends object = DefaultPointer>(labelSymbolText: string, fieldNames: string[]): RecordConstructor<T> {
|
||||
return Record.makeBasicConstructor(Symbol.for(labelSymbolText), fieldNames);
|
||||
}
|
||||
|
||||
static makeBasicConstructor<T extends object>(label0: any, fieldNames: string[]): RecordConstructor<T> {
|
||||
static makeBasicConstructor<T extends object = DefaultPointer>(label0: any, fieldNames: string[]): RecordConstructor<T> {
|
||||
const label = fromJS<T>(label0);
|
||||
const arity = fieldNames.length;
|
||||
const ctor: RecordConstructor<T> = (...fields: any[]): Record<T> => {
|
||||
|
@ -523,23 +525,23 @@ export class Record<T extends object> extends Array<Value<T>> {
|
|||
return true;
|
||||
}
|
||||
|
||||
static isRecord<T extends object>(x: any): x is Record<T> {
|
||||
static isRecord<T extends object = DefaultPointer>(x: any): x is Record<T> {
|
||||
return !!x?.[IsPreservesRecord];
|
||||
}
|
||||
|
||||
static isClassOf<T extends object>(ci: RecordConstructorInfo<T>, v: any): v is Record<T> {
|
||||
static isClassOf<T extends object = DefaultPointer>(ci: RecordConstructorInfo<T>, v: any): v is Record<T> {
|
||||
return (Record.isRecord(v)) && is(ci.label, v.label) && (ci.arity === v.length);
|
||||
}
|
||||
}
|
||||
|
||||
export interface RecordConstructor<T extends object> {
|
||||
export interface RecordConstructor<T extends object = DefaultPointer> {
|
||||
(...fields: any[]): Record<T>;
|
||||
constructorInfo: RecordConstructorInfo<T>;
|
||||
isClassOf(v: any): v is Record<T>;
|
||||
_: { [getter: string]: (r: any) => Value<T> | undefined };
|
||||
}
|
||||
|
||||
export interface RecordConstructorInfo<T extends object> {
|
||||
export interface RecordConstructorInfo<T extends object = DefaultPointer> {
|
||||
label: Value<T>;
|
||||
arity: number;
|
||||
}
|
||||
|
@ -564,18 +566,18 @@ export function is(a: any, b: any): boolean {
|
|||
export type DictionaryType = 'Dictionary' | 'Set';
|
||||
export const DictionaryType = Symbol.for('DictionaryType');
|
||||
|
||||
export class Dictionary<T extends object, V> extends FlexMap<Value<T>, V> {
|
||||
export class Dictionary<V, T extends object = DefaultPointer> extends FlexMap<Value<T>, V> {
|
||||
get [DictionaryType](): DictionaryType {
|
||||
return 'Dictionary';
|
||||
}
|
||||
|
||||
static isDictionary<T extends object, V>(x: any): x is Dictionary<T, V> {
|
||||
static isDictionary<V, T extends object = DefaultPointer>(x: any): x is Dictionary<V, T> {
|
||||
return x?.[DictionaryType] === 'Dictionary';
|
||||
}
|
||||
|
||||
static fromJS<T extends object, V extends object>(x: object): Dictionary<T, Value<V>> {
|
||||
if (Dictionary.isDictionary<T, V>(x)) return x as Dictionary<T, Value<V>>;
|
||||
const d = new Dictionary<T, Value<V>>();
|
||||
static fromJS<V extends object = DefaultPointer, T extends object = DefaultPointer>(x: object): Dictionary<Value<V>, T> {
|
||||
if (Dictionary.isDictionary<V, T>(x)) return x as Dictionary<Value<V>, T>;
|
||||
const d = new Dictionary<Value<V>, T>();
|
||||
Object.entries(x).forEach(([key, value]) => d.set(key, fromJS(value)));
|
||||
return d;
|
||||
}
|
||||
|
@ -585,8 +587,8 @@ export class Dictionary<T extends object, V> extends FlexMap<Value<T>, V> {
|
|||
super(canonicalString, iter === void 0 ? void 0 : _iterMap(iter, ([k,v]) => [fromJS(k), v]));
|
||||
}
|
||||
|
||||
mapEntries<R extends object, W>(f: (entry: [Value<T>, V]) => [Value<R>, W]): Dictionary<R, W> {
|
||||
const result = new Dictionary<R, W>();
|
||||
mapEntries<W, R extends object = DefaultPointer>(f: (entry: [Value<T>, V]) => [Value<R>, W]): Dictionary<W, R> {
|
||||
const result = new Dictionary<W, R>();
|
||||
for (let oldEntry of this.entries()) {
|
||||
const newEntry = f(oldEntry);
|
||||
result.set(newEntry[0], newEntry[1])
|
||||
|
@ -601,7 +603,7 @@ export class Dictionary<T extends object, V> extends FlexMap<Value<T>, V> {
|
|||
'}';
|
||||
}
|
||||
|
||||
clone(): Dictionary<T, V> {
|
||||
clone(): Dictionary<V, T> {
|
||||
return new Dictionary(this);
|
||||
}
|
||||
|
||||
|
@ -628,12 +630,12 @@ export class Dictionary<T extends object, V> extends FlexMap<Value<T>, V> {
|
|||
}
|
||||
}
|
||||
|
||||
export class Set<T extends object> extends FlexSet<Value<T>> {
|
||||
export class Set<T extends object = DefaultPointer> extends FlexSet<Value<T>> {
|
||||
get [DictionaryType](): DictionaryType {
|
||||
return 'Set';
|
||||
}
|
||||
|
||||
static isSet<T extends object>(x: any): x is Set<T> {
|
||||
static isSet<T extends object = DefaultPointer>(x: any): x is Set<T> {
|
||||
return x?.[DictionaryType] === 'Set';
|
||||
}
|
||||
|
||||
|
@ -642,7 +644,7 @@ export class Set<T extends object> extends FlexSet<Value<T>> {
|
|||
super(canonicalString, iter === void 0 ? void 0 : _iterMap<any, Value<T>>(iter, fromJS));
|
||||
}
|
||||
|
||||
map<R extends object>(f: (value: Value<T>) => Value<R>): Set<R> {
|
||||
map<R extends object = DefaultPointer>(f: (value: Value<T>) => Value<R>): Set<R> {
|
||||
return new Set(_iterMap(this[Symbol.iterator](), f));
|
||||
}
|
||||
|
||||
|
@ -679,7 +681,7 @@ export class Set<T extends object> extends FlexSet<Value<T>> {
|
|||
}
|
||||
}
|
||||
|
||||
export class Annotated<T extends object> {
|
||||
export class Annotated<T extends object = DefaultPointer> {
|
||||
readonly annotations: Array<Value<T>>;
|
||||
readonly item: Value<T>;
|
||||
|
||||
|
@ -723,16 +725,16 @@ export class Annotated<T extends object> {
|
|||
return true;
|
||||
}
|
||||
|
||||
static isAnnotated<T extends object>(x: any): x is Annotated<T> {
|
||||
static isAnnotated<T extends object = DefaultPointer>(x: any): x is Annotated<T> {
|
||||
return !!x?.[IsPreservesAnnotated];
|
||||
}
|
||||
}
|
||||
|
||||
export function peel<T extends object>(v: Value<T>): Value<T> {
|
||||
export function peel<T extends object = DefaultPointer>(v: Value<T>): Value<T> {
|
||||
return strip(v, 1);
|
||||
}
|
||||
|
||||
export function strip<T extends object>(v: Value<T>, depth: number = Infinity): Value<T> {
|
||||
export function strip<T extends object = DefaultPointer>(v: Value<T>, depth: number = Infinity): Value<T> {
|
||||
function step(v: Value<T>, depth: number): Value<T> {
|
||||
if (depth === 0) return v;
|
||||
if (!Annotated.isAnnotated<T>(v)) return v;
|
||||
|
@ -746,7 +748,7 @@ export function strip<T extends object>(v: Value<T>, depth: number = Infinity):
|
|||
return v.item.map(walk);
|
||||
} else if (Set.isSet<T>(v.item)) {
|
||||
return v.item.map(walk);
|
||||
} else if (Dictionary.isDictionary<T, Value<T>>(v.item)) {
|
||||
} else if (Dictionary.isDictionary<Value<T>, T>(v.item)) {
|
||||
return v.item.mapEntries((e) => [walk(e[0]), walk(e[1])]);
|
||||
} else if (Annotated.isAnnotated(v.item)) {
|
||||
throw new Error("Improper annotation structure");
|
||||
|
@ -757,7 +759,7 @@ export function strip<T extends object>(v: Value<T>, depth: number = Infinity):
|
|||
return step(v, depth);
|
||||
}
|
||||
|
||||
export function annotate<T extends object>(v0: Value<T>, ...anns: Value<T>[]): Annotated<T> {
|
||||
export function annotate<T extends object = DefaultPointer>(v0: Value<T>, ...anns: Value<T>[]): Annotated<T> {
|
||||
const v = Annotated.isAnnotated<T>(v0) ? v0 : new Annotated(v0);
|
||||
anns.forEach((a) => v.annotations.push(a));
|
||||
return v;
|
||||
|
|
|
@ -151,7 +151,7 @@ describe('encoding and decoding pointers', () => {
|
|||
it('should store pointers embedded in map keys correctly', () => {
|
||||
const A1 = ({a: 1});
|
||||
const A2 = ({a: 1});
|
||||
const m = new Dictionary<object, Value<object>>();
|
||||
const m = new Dictionary();
|
||||
m.set([A1], 1);
|
||||
m.set([A2], 2);
|
||||
expect(m.get(A1)).toBeUndefined();
|
||||
|
@ -241,7 +241,7 @@ describe('common test suite', () => {
|
|||
});
|
||||
}
|
||||
|
||||
const tests = peel(TestCases._.cases(peel(samples))!) as Dictionary<Pointer, Value<Pointer>>;
|
||||
const tests = peel(TestCases._.cases(peel(samples))!) as Dictionary<Value<Pointer>, Pointer>;
|
||||
tests.forEach((t0: Value<Pointer>, tName0: Value<Pointer>) => {
|
||||
const tName = Symbol.keyFor(strip(tName0) as symbol)!;
|
||||
const t = peel(t0) as Record<Pointer>;
|
||||
|
|
Loading…
Reference in New Issue