From a5d4098e295a14f5a55561750cfb3dd690e5802e Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Fri, 15 Jan 2021 14:01:14 +0100 Subject: [PATCH] Strict tsconfig --- implementations/javascript/src/codec.ts | 2 +- implementations/javascript/src/flex.ts | 30 ++++++++-------- .../javascript/src/node_support.ts | 7 ++-- implementations/javascript/src/values.ts | 35 ++++++++++--------- implementations/javascript/test/bytes.test.ts | 2 +- implementations/javascript/test/codec.test.ts | 12 ++++--- implementations/javascript/tsconfig.json | 4 ++- 7 files changed, 52 insertions(+), 40 deletions(-) diff --git a/implementations/javascript/src/codec.ts b/implementations/javascript/src/codec.ts index 57b3278..fda9b3d 100644 --- a/implementations/javascript/src/codec.ts +++ b/implementations/javascript/src/codec.ts @@ -206,7 +206,7 @@ export interface EncoderOptions { } function chunkStr(bs: Uint8Array): string { - return String.fromCharCode.apply(null, bs); + return String.fromCharCode.apply(null, bs as any as number[]); } export class Encoder { diff --git a/implementations/javascript/src/flex.ts b/implementations/javascript/src/flex.ts index 4da65d8..7cc4585 100644 --- a/implementations/javascript/src/flex.ts +++ b/implementations/javascript/src/flex.ts @@ -36,16 +36,18 @@ Map.isMap = (x: any): x is Map => !!x?.[IsMap]; Object.defineProperty(Set.prototype, IsSet, { get() { return true; } }); Set.isSet = (x: any): x is Set => !!x?.[IsSet]; -export function _iterMap(i: Iterator | undefined, f : (s: S) => T): IterableIterator { - if (!i) return void 0; +export function _iterMap(i: Iterator, f : (s: S) => T): IterableIterator { const _f = (r: IteratorResult): IteratorResult => { - const { done, value } = r; - return { done, value: done ? void 0 : f(value) }; + if (r.done) { + return { done: true, value: null }; + } else { + return { done: false, value: f(r.value) }; + } }; return { next: (v?: any): IteratorResult => _f(i.next(v)), - return: (v?: any): IteratorResult => _f(i.return(v)), - throw: (e?: any): IteratorResult => _f(i.throw(e)), + return: (v?: any): IteratorResult => _f(i.return?.(v) ?? { done: true, value: null }), + throw: (e?: any): IteratorResult => _f(i.throw?.(e) ?? { done: true, value: null }), [Symbol.iterator]() { return this; }, }; } @@ -56,9 +58,9 @@ export class FlexMap implements Map { constructor(c: Canonicalizer, items?: Iterable) { this.canonicalizer = c; - this.items = new Map((items === void 0) - ? void 0 - : _iterMap(items[Symbol.iterator](), ([k, v]) => [this._key(k), [k, v]])); + this.items = (items === void 0) + ? new Map() + : new Map(_iterMap(items[Symbol.iterator](), ([k, v]) => [this._key(k), [k, v]])); } _key(k: K): string { @@ -130,7 +132,7 @@ export class FlexMap implements Map { { const ks = this._key(key); if (this.items.has(ks)) { - const oldValue = this.items.get(ks)[1]; + const oldValue = this.items.get(ks)![1]; const newValue = f(oldValue); if (newValue === void 0) { this.items.delete(ks); @@ -165,9 +167,9 @@ export class FlexSet implements Set { constructor(c: Canonicalizer, items?: Iterable) { this.canonicalizer = c; - this.items = new Map((items === void 0) - ? void 0 - : _iterMap(items[Symbol.iterator](), (v) => [this._key(v), v])); + this.items = (items === void 0) + ? new Map() + : new Map(_iterMap(items[Symbol.iterator](), (v) => [this._key(v), v])); } _key(v: V): string { @@ -181,7 +183,7 @@ export class FlexSet implements Set { get(v: V): {item: V} | null { const vs = this._key(v); if (this.items.has(vs)) { - return {item: this.items.get(vs)}; + return { item: this.items.get(vs)! }; } else { return null; } diff --git a/implementations/javascript/src/node_support.ts b/implementations/javascript/src/node_support.ts index 80c33d0..53b5de7 100644 --- a/implementations/javascript/src/node_support.ts +++ b/implementations/javascript/src/node_support.ts @@ -4,9 +4,10 @@ import * as util from 'util'; import { Record, Bytes, Annotated, Set, Dictionary } from './values'; [Bytes, Annotated, Record, Set, Dictionary].forEach((C) => { - C.prototype[util.inspect.custom] = function (_depth: any, _options: any) { - return this.asPreservesText(); - }; + (C as any).prototype[util.inspect.custom] = + function (_depth: any, _options: any) { + return this.asPreservesText(); + }; }); Record.fallbackToString = util.inspect; diff --git a/implementations/javascript/src/values.ts b/implementations/javascript/src/values.ts index 42430da..3bc0511 100644 --- a/implementations/javascript/src/values.ts +++ b/implementations/javascript/src/values.ts @@ -183,13 +183,13 @@ export class Bytes { static fromIO(io: string | BytesLike): string | Bytes { if (typeof io === 'string') 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 { if (typeof b === 'string') return b; if (Bytes.isBytes(b)) return b._view; - if (b instanceof Uint8Array) return b; + return b; } static concat = function (bss: BytesLike[]): Bytes { @@ -334,7 +334,7 @@ String.prototype.asPreservesText = function (): string { Symbol.prototype.asPreservesText = function (): string { // TODO: escaping - return this.description; + return this.description ?? '||'; }; Array.prototype.asPreservesText = function (): string { @@ -390,17 +390,20 @@ export interface Bytes { for (const k of `entries every find findIndex forEach includes indexOf join 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+/)) { - 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+/)) { - 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](); }; @@ -417,6 +420,7 @@ export class Record extends Array { // somewhat calling-convention-compatible. This is // something that isn't part of the user-facing API. super(label); + this.label = label; // needed just to keep the typechecker happy return; } @@ -426,7 +430,7 @@ export class Record extends Array { Object.freeze(this); } - get(index: number, defaultValue?: Value): Value { + get(index: number, defaultValue?: Value): Value | undefined { return (index < this.length) ? this[index] : defaultValue; } @@ -478,7 +482,7 @@ export class Record extends Array { static makeBasicConstructor(label0: any, fieldNames: string[]): RecordConstructor { const label = fromJS(label0); const arity = fieldNames.length; - const ctor = (...fields: any[]) => { + const ctor: RecordConstructor = (...fields: any[]) => { if (fields.length !== arity) { throw new Error("Record: cannot instantiate " + (label && label.toString()) + " expecting " + arity + " fields with " + fields.length + " fields"); @@ -490,7 +494,7 @@ export class Record extends Array { ctor.isClassOf = (v: any): v is Record => Record.isClassOf(constructorInfo, v); ctor._ = {}; fieldNames.forEach((name, i) => { - ctor._[name] = function (r: any): Value { + ctor._[name] = function (r: any): Value | undefined { if (!ctor.isClassOf(r)) { throw new Error("Record: attempt to retrieve field "+label.toString()+"."+name+ " from non-"+label.toString()+": "+(r && r.toString())); @@ -525,7 +529,7 @@ export interface RecordConstructor { (...fields: any[]): Record; constructorInfo: RecordConstructorInfo; isClassOf(v: any): v is Record; - _: { [getter: string]: (r: any) => Value }; + _: { [getter: string]: (r: any) => Value | undefined }; } export interface RecordConstructorInfo { @@ -569,15 +573,13 @@ export class Dictionary extends FlexMap { static fromJS(x: object): Dictionary { if (Dictionary.isDictionary(x)) return x as Dictionary; const d = new Dictionary(); - for (let key in x) { - const value = x[key]; - d.set(key, fromJS(value)); - } + Object.entries(x).forEach(([key, value]) => d.set(key, fromJS(value))); return d; } constructor(items?: Iterable) { - 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(f: (entry: [Value, T]) => [Value, R]): Dictionary { @@ -633,7 +635,8 @@ export class Set extends FlexSet { } constructor(items?: Iterable) { - 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 { diff --git a/implementations/javascript/test/bytes.test.ts b/implementations/javascript/test/bytes.test.ts index 65c3cb2..19b960b 100644 --- a/implementations/javascript/test/bytes.test.ts +++ b/implementations/javascript/test/bytes.test.ts @@ -22,7 +22,7 @@ describe('immutable byte arrays', () => { expect(bs.findIndex((b) => b > 50)).toBe(-1); }); it('should implement forEach', () => { - const vs = []; + const vs: number[] = []; bs.forEach((b) => vs.push(b)); expect(fromJS(vs)).is(fromJS([10, 20, 30, 40])); }); diff --git a/implementations/javascript/test/codec.test.ts b/implementations/javascript/test/codec.test.ts index fbbcc9c..bb8efef 100644 --- a/implementations/javascript/test/codec.test.ts +++ b/implementations/javascript/test/codec.test.ts @@ -88,7 +88,11 @@ describe('common test suite', () => { return encodeWithAnnotations(v); } - const expectedValues = { + interface ExpectedValues { + [testName: string]: { value: Value } | { forward: Value, back: Value }; + } + + const expectedValues: ExpectedValues = { annotation1: { forward: annotate(9, "abc"), back: 9 }, annotation2: { forward: annotate([[], annotate([], "x")], "abc", "def"), @@ -123,7 +127,7 @@ describe('common test suite', () => { describe(tName, () => { const textForm = strip(annotatedTextForm); const {forward, back} = (function () { - const entry = expectedValues[tName] || {value: textForm}; + const entry = expectedValues[tName] ?? {value: textForm}; if ('value' in entry) { return {forward: entry.value, back: entry.value}; } 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; + const tests = peel(TestCases._.cases(peel(samples))!) as Dictionary; 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; switch (t.label) { case Symbol.for('Test'): diff --git a/implementations/javascript/tsconfig.json b/implementations/javascript/tsconfig.json index 923fae5..299625c 100644 --- a/implementations/javascript/tsconfig.json +++ b/implementations/javascript/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { "target": "ES2017", + "lib": ["es2019", "DOM"], "declaration": true, "baseUrl": "./src", "rootDir": "./src", @@ -8,7 +9,8 @@ "declarationDir": "./lib", "esModuleInterop": true, "moduleResolution": "node", - "sourceMap": true + "sourceMap": true, + "strict": true }, "include": ["src/**/*"] }