Strict tsconfig

This commit is contained in:
Tony Garnock-Jones 2021-01-15 14:01:14 +01:00
parent d8a041a647
commit a5d4098e29
7 changed files with 52 additions and 40 deletions

View File

@ -206,7 +206,7 @@ export interface EncoderOptions {
} }
function chunkStr(bs: Uint8Array): string { function chunkStr(bs: Uint8Array): string {
return String.fromCharCode.apply(null, bs); return String.fromCharCode.apply(null, bs as any as number[]);
} }
export class Encoder { export class Encoder {

View File

@ -36,16 +36,18 @@ Map.isMap = <K,V> (x: any): x is Map<K, V> => !!x?.[IsMap];
Object.defineProperty(Set.prototype, IsSet, { get() { return true; } }); Object.defineProperty(Set.prototype, IsSet, { get() { return true; } });
Set.isSet = <T> (x: any): x is Set<T> => !!x?.[IsSet]; Set.isSet = <T> (x: any): x is Set<T> => !!x?.[IsSet];
export function _iterMap<S,T>(i: Iterator<S> | undefined, f : (s: S) => T): IterableIterator<T> { export function _iterMap<S,T>(i: Iterator<S>, f : (s: S) => T): IterableIterator<T> {
if (!i) return void 0;
const _f = (r: IteratorResult<S>): IteratorResult<T> => { const _f = (r: IteratorResult<S>): IteratorResult<T> => {
const { done, value } = r; if (r.done) {
return { done, value: done ? void 0 : f(value) }; return { done: true, value: null };
} else {
return { done: false, value: f(r.value) };
}
}; };
return { return {
next: (v?: any): IteratorResult<T> => _f(i.next(v)), next: (v?: any): IteratorResult<T> => _f(i.next(v)),
return: (v?: any): IteratorResult<T> => _f(i.return(v)), return: (v?: any): IteratorResult<T> => _f(i.return?.(v) ?? { done: true, value: null }),
throw: (e?: any): IteratorResult<T> => _f(i.throw(e)), throw: (e?: any): IteratorResult<T> => _f(i.throw?.(e) ?? { done: true, value: null }),
[Symbol.iterator]() { return this; }, [Symbol.iterator]() { return this; },
}; };
} }
@ -56,9 +58,9 @@ export class FlexMap<K, V> implements Map<K, V> {
constructor(c: Canonicalizer<K>, items?: Iterable<readonly [K, V]>) { constructor(c: Canonicalizer<K>, items?: Iterable<readonly [K, V]>) {
this.canonicalizer = c; this.canonicalizer = c;
this.items = new Map((items === void 0) this.items = (items === void 0)
? void 0 ? new Map()
: _iterMap(items[Symbol.iterator](), ([k, v]) => [this._key(k), [k, v]])); : new Map(_iterMap(items[Symbol.iterator](), ([k, v]) => [this._key(k), [k, v]]));
} }
_key(k: K): string { _key(k: K): string {
@ -130,7 +132,7 @@ export class FlexMap<K, V> implements Map<K, V> {
{ {
const ks = this._key(key); const ks = this._key(key);
if (this.items.has(ks)) { if (this.items.has(ks)) {
const oldValue = this.items.get(ks)[1]; const oldValue = this.items.get(ks)![1];
const newValue = f(oldValue); const newValue = f(oldValue);
if (newValue === void 0) { if (newValue === void 0) {
this.items.delete(ks); this.items.delete(ks);
@ -165,9 +167,9 @@ export class FlexSet<V> implements Set<V> {
constructor(c: Canonicalizer<V>, items?: Iterable<V>) { constructor(c: Canonicalizer<V>, items?: Iterable<V>) {
this.canonicalizer = c; this.canonicalizer = c;
this.items = new Map((items === void 0) this.items = (items === void 0)
? void 0 ? new Map()
: _iterMap(items[Symbol.iterator](), (v) => [this._key(v), v])); : new Map(_iterMap(items[Symbol.iterator](), (v) => [this._key(v), v]));
} }
_key(v: V): string { _key(v: V): string {
@ -181,7 +183,7 @@ export class FlexSet<V> implements Set<V> {
get(v: V): {item: V} | null { get(v: V): {item: V} | null {
const vs = this._key(v); const vs = this._key(v);
if (this.items.has(vs)) { if (this.items.has(vs)) {
return {item: this.items.get(vs)}; return { item: this.items.get(vs)! };
} else { } else {
return null; return null;
} }

View File

@ -4,9 +4,10 @@ import * as util from 'util';
import { Record, Bytes, Annotated, Set, Dictionary } from './values'; import { Record, Bytes, Annotated, Set, Dictionary } from './values';
[Bytes, Annotated, Record, Set, Dictionary].forEach((C) => { [Bytes, Annotated, Record, Set, Dictionary].forEach((C) => {
C.prototype[util.inspect.custom] = function (_depth: any, _options: any) { (C as any).prototype[util.inspect.custom] =
return this.asPreservesText(); function (_depth: any, _options: any) {
}; return this.asPreservesText();
};
}); });
Record.fallbackToString = util.inspect; Record.fallbackToString = util.inspect;

View File

@ -183,13 +183,13 @@ export class Bytes {
static fromIO(io: string | BytesLike): string | Bytes { static fromIO(io: string | BytesLike): string | Bytes {
if (typeof io === 'string') return io; if (typeof io === 'string') return io;
if (Bytes.isBytes(io)) return io; if (Bytes.isBytes(io)) return io;
if (io instanceof Uint8Array) return new Bytes(io); return new Bytes(io);
} }
static toIO(b : string | BytesLike): string | Uint8Array { static toIO(b : string | BytesLike): string | Uint8Array {
if (typeof b === 'string') return b; if (typeof b === 'string') return b;
if (Bytes.isBytes(b)) return b._view; if (Bytes.isBytes(b)) return b._view;
if (b instanceof Uint8Array) return b; return b;
} }
static concat = function (bss: BytesLike[]): Bytes { static concat = function (bss: BytesLike[]): Bytes {
@ -334,7 +334,7 @@ String.prototype.asPreservesText = function (): string {
Symbol.prototype.asPreservesText = function (): string { Symbol.prototype.asPreservesText = function (): string {
// TODO: escaping // TODO: escaping
return this.description; return this.description ?? '||';
}; };
Array.prototype.asPreservesText = function (): string { Array.prototype.asPreservesText = function (): string {
@ -390,17 +390,20 @@ export interface Bytes {
for (const k of `entries every find findIndex forEach includes indexOf join for (const k of `entries every find findIndex forEach includes indexOf join
keys lastIndexOf reduce reduceRight some toLocaleString values`.split(/\s+/)) keys lastIndexOf reduce reduceRight some toLocaleString values`.split(/\s+/))
{ {
Bytes.prototype[k] = function (...args: any[]) { return this._view[k](...args); }; (Bytes as any).prototype[k] =
function (...args: any[]) { return this._view[k](...args); };
} }
for (const k of `filter map slice subarray`.split(/\s+/)) for (const k of `filter map slice subarray`.split(/\s+/))
{ {
Bytes.prototype[k] = function (...args: any[]) { return new Bytes(this._view[k](...args)); }; (Bytes as any).prototype[k] =
function (...args: any[]) { return new Bytes(this._view[k](...args)); };
} }
for (const k of `reverse sort`.split(/\s+/)) for (const k of `reverse sort`.split(/\s+/))
{ {
Bytes.prototype[k] = function (...args: any[]) { return new Bytes(this._view.slice()[k](...args)); }; (Bytes as any).prototype[k] =
function (...args: any[]) { return new Bytes(this._view.slice()[k](...args)); };
} }
Bytes.prototype[Symbol.iterator] = function () { return this._view[Symbol.iterator](); }; Bytes.prototype[Symbol.iterator] = function () { return this._view[Symbol.iterator](); };
@ -417,6 +420,7 @@ export class Record extends Array<Value> {
// somewhat calling-convention-compatible. This is // somewhat calling-convention-compatible. This is
// something that isn't part of the user-facing API. // something that isn't part of the user-facing API.
super(label); super(label);
this.label = label; // needed just to keep the typechecker happy
return; return;
} }
@ -426,7 +430,7 @@ export class Record extends Array<Value> {
Object.freeze(this); Object.freeze(this);
} }
get(index: number, defaultValue?: Value): Value { get(index: number, defaultValue?: Value): Value | undefined {
return (index < this.length) ? this[index] : defaultValue; return (index < this.length) ? this[index] : defaultValue;
} }
@ -478,7 +482,7 @@ export class Record extends Array<Value> {
static makeBasicConstructor(label0: any, fieldNames: string[]): RecordConstructor { static makeBasicConstructor(label0: any, fieldNames: string[]): RecordConstructor {
const label = fromJS(label0); const label = fromJS(label0);
const arity = fieldNames.length; const arity = fieldNames.length;
const ctor = (...fields: any[]) => { const ctor: RecordConstructor = (...fields: any[]) => {
if (fields.length !== arity) { if (fields.length !== arity) {
throw new Error("Record: cannot instantiate " + (label && label.toString()) + throw new Error("Record: cannot instantiate " + (label && label.toString()) +
" expecting " + arity + " fields with " + fields.length + " fields"); " expecting " + arity + " fields with " + fields.length + " fields");
@ -490,7 +494,7 @@ export class Record extends Array<Value> {
ctor.isClassOf = (v: any): v is Record => Record.isClassOf(constructorInfo, v); ctor.isClassOf = (v: any): v is Record => Record.isClassOf(constructorInfo, v);
ctor._ = {}; ctor._ = {};
fieldNames.forEach((name, i) => { fieldNames.forEach((name, i) => {
ctor._[name] = function (r: any): Value { ctor._[name] = function (r: any): Value | undefined {
if (!ctor.isClassOf(r)) { if (!ctor.isClassOf(r)) {
throw new Error("Record: attempt to retrieve field "+label.toString()+"."+name+ throw new Error("Record: attempt to retrieve field "+label.toString()+"."+name+
" from non-"+label.toString()+": "+(r && r.toString())); " from non-"+label.toString()+": "+(r && r.toString()));
@ -525,7 +529,7 @@ export interface RecordConstructor {
(...fields: any[]): Record; (...fields: any[]): Record;
constructorInfo: RecordConstructorInfo; constructorInfo: RecordConstructorInfo;
isClassOf(v: any): v is Record; isClassOf(v: any): v is Record;
_: { [getter: string]: (r: any) => Value }; _: { [getter: string]: (r: any) => Value | undefined };
} }
export interface RecordConstructorInfo { export interface RecordConstructorInfo {
@ -569,15 +573,13 @@ export class Dictionary<T> extends FlexMap<Value, T> {
static fromJS(x: object): Dictionary<Value> { static fromJS(x: object): Dictionary<Value> {
if (Dictionary.isDictionary(x)) return x as Dictionary<Value>; if (Dictionary.isDictionary(x)) return x as Dictionary<Value>;
const d = new Dictionary<Value>(); const d = new Dictionary<Value>();
for (let key in x) { Object.entries(x).forEach(([key, value]) => d.set(key, fromJS(value)));
const value = x[key];
d.set(key, fromJS(value));
}
return d; return d;
} }
constructor(items?: Iterable<readonly [any, T]>) { constructor(items?: Iterable<readonly [any, T]>) {
super(canonicalString, _iterMap(items?.[Symbol.iterator](), ([k,v]) => [fromJS(k), v])); const iter = items?.[Symbol.iterator]();
super(canonicalString, iter === void 0 ? void 0 : _iterMap(iter, ([k,v]) => [fromJS(k), v]));
} }
mapEntries<R>(f: (entry: [Value, T]) => [Value, R]): Dictionary<R> { mapEntries<R>(f: (entry: [Value, T]) => [Value, R]): Dictionary<R> {
@ -633,7 +635,8 @@ export class Set extends FlexSet<Value> {
} }
constructor(items?: Iterable<any>) { constructor(items?: Iterable<any>) {
super(canonicalString, _iterMap(items?.[Symbol.iterator](), fromJS)); const iter = items?.[Symbol.iterator]();
super(canonicalString, iter === void 0 ? void 0 : _iterMap(iter, fromJS));
} }
map(f: (value: Value) => Value): Set { map(f: (value: Value) => Value): Set {

View File

@ -22,7 +22,7 @@ describe('immutable byte arrays', () => {
expect(bs.findIndex((b) => b > 50)).toBe(-1); expect(bs.findIndex((b) => b > 50)).toBe(-1);
}); });
it('should implement forEach', () => { it('should implement forEach', () => {
const vs = []; const vs: number[] = [];
bs.forEach((b) => vs.push(b)); bs.forEach((b) => vs.push(b));
expect(fromJS(vs)).is(fromJS([10, 20, 30, 40])); expect(fromJS(vs)).is(fromJS([10, 20, 30, 40]));
}); });

View File

@ -88,7 +88,11 @@ describe('common test suite', () => {
return encodeWithAnnotations(v); return encodeWithAnnotations(v);
} }
const expectedValues = { interface ExpectedValues {
[testName: string]: { value: Value } | { forward: Value, back: Value };
}
const expectedValues: ExpectedValues = {
annotation1: { forward: annotate(9, "abc"), annotation1: { forward: annotate(9, "abc"),
back: 9 }, back: 9 },
annotation2: { forward: annotate([[], annotate([], "x")], "abc", "def"), annotation2: { forward: annotate([[], annotate([], "x")], "abc", "def"),
@ -123,7 +127,7 @@ describe('common test suite', () => {
describe(tName, () => { describe(tName, () => {
const textForm = strip(annotatedTextForm); const textForm = strip(annotatedTextForm);
const {forward, back} = (function () { const {forward, back} = (function () {
const entry = expectedValues[tName] || {value: textForm}; const entry = expectedValues[tName] ?? {value: textForm};
if ('value' in entry) { if ('value' in entry) {
return {forward: entry.value, back: entry.value}; return {forward: entry.value, back: entry.value};
} else if ('forward' in entry && 'back' in entry) { } else if ('forward' in entry && 'back' in entry) {
@ -146,9 +150,9 @@ describe('common test suite', () => {
}); });
} }
const tests = peel(TestCases._.cases(peel(samples))) as Dictionary<Value>; const tests = peel(TestCases._.cases(peel(samples))!) as Dictionary<Value>;
tests.forEach((t0: Value, tName0: Value) => { tests.forEach((t0: Value, tName0: Value) => {
const tName = Symbol.keyFor(strip(tName0) as symbol); const tName = Symbol.keyFor(strip(tName0) as symbol)!;
const t = peel(t0) as Record; const t = peel(t0) as Record;
switch (t.label) { switch (t.label) {
case Symbol.for('Test'): case Symbol.for('Test'):

View File

@ -1,6 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ES2017", "target": "ES2017",
"lib": ["es2019", "DOM"],
"declaration": true, "declaration": true,
"baseUrl": "./src", "baseUrl": "./src",
"rootDir": "./src", "rootDir": "./src",
@ -8,7 +9,8 @@
"declarationDir": "./lib", "declarationDir": "./lib",
"esModuleInterop": true, "esModuleInterop": true,
"moduleResolution": "node", "moduleResolution": "node",
"sourceMap": true "sourceMap": true,
"strict": true
}, },
"include": ["src/**/*"] "include": ["src/**/*"]
} }