From 9dc0d89118dba960e672e024411f3ef0af94f5c6 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Tue, 5 Jan 2016 18:37:21 +0100 Subject: [PATCH] skeleton for decorator-based schema validation --- extension/background/checkable.ts | 87 ++++++++++++++++++++++++++++++ extension/background/db.js | 4 +- extension/background/db.ts | 14 ++--- extension/background/emscriptif.ts | 2 +- extension/background/wallet.js | 24 ++++++++- extension/background/wallet.ts | 37 ++++++++++--- extension/manifest.json | 1 + extension/tsconfig.json | 1 + 8 files changed, 151 insertions(+), 19 deletions(-) create mode 100644 extension/background/checkable.ts diff --git a/extension/background/checkable.ts b/extension/background/checkable.ts new file mode 100644 index 000000000..63fbd3646 --- /dev/null +++ b/extension/background/checkable.ts @@ -0,0 +1,87 @@ +/* + This file is part of TALER + (C) 2016 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, If not, see + */ + +"use strict"; + +/** + * Decorators for type-checking JSON into + * an object. + * @module Checkable + * @author Florian Dold + */ + + +namespace Checkable { + let chkSym = Symbol("checkable"); + + function checkNumber(target, prop) { + return true; + } + + function checkString(target, prop) { + return true; + } + + export function Class(target) { + target.checked = (v) => { + let props = target.prototype[chkSym].props; + console.log("hello, world"); + let remainingPropNames = new Set(Object.getOwnPropertyNames(v)); + + for (let prop of props) { + remainingPropNames.delete(prop); + console.log("prop", prop); + } + + if (remainingPropNames.size != 0) { + throw Error("superfluous properties " + JSON.stringify(remainingPropNames.values())); + } + }; + return target; + } + + export function Value(type) { + function deco(target) { + } + + return deco; + } + + export function List(type) { + function deco(target) { + } + + return deco; + } + + export function Number(target: Object, propertyKey: string | symbol): void { + let chk = target[chkSym]; + if (!chk) { + chk = {props: []}; + target[chkSym] = chk; + } + chk.props.push({propertyKey: propertyKey, checker: checkNumber}); + } + + export function String(target: Object, propertyKey: string | symbol): void { + let chk = target[chkSym]; + if (!chk) { + chk = {props: []}; + target[chkSym] = chk; + } + chk.props.push({propertyKey: propertyKey, checker: checkString}); + } +} diff --git a/extension/background/db.js b/extension/background/db.js index 0e4576851..4b81555da 100644 --- a/extension/background/db.js +++ b/extension/background/db.js @@ -55,7 +55,7 @@ function exportDb(db) { }; return new Promise((resolve, reject) => { let tx = db.transaction(db.objectStoreNames); - tx.addEventListener('complete', (e) => { + tx.addEventListener("complete", (e) => { resolve(dump); }); for (let i = 0; i < db.objectStoreNames.length; i++) { @@ -64,7 +64,7 @@ function exportDb(db) { dump.stores[name] = storeDump; let store = tx.objectStore(name) .openCursor() - .addEventListener('success', (e) => { + .addEventListener("success", (e) => { let cursor = e.target.result; if (cursor) { storeDump[cursor.key] = cursor.value; diff --git a/extension/background/db.ts b/extension/background/db.ts index df24e1471..d3c6e9182 100644 --- a/extension/background/db.ts +++ b/extension/background/db.ts @@ -41,10 +41,10 @@ namespace Db { } export interface Denomination { - value: AmountJson; + value: AmountJson_interface; denom_pub: string; - fee_withdraw: AmountJson; - fee_deposit: AmountJson; + fee_withdraw: AmountJson_interface; + fee_deposit: AmountJson_interface; } export interface PreCoin { @@ -56,7 +56,7 @@ namespace Db { withdrawSig: string; coinEv: string; mintBaseUrl: string; - coinValue: AmountJson; + coinValue: AmountJson_interface; } export interface Coin { @@ -64,7 +64,7 @@ namespace Db { coinPriv: string; denomPub: string; denomSig: string; - currentAmount: AmountJson; + currentAmount: AmountJson_interface; mintBaseUrl: string; } @@ -119,7 +119,7 @@ function exportDb(db): Promise { return new Promise((resolve, reject) => { let tx = db.transaction(db.objectStoreNames); - tx.addEventListener('complete', (e) => { + tx.addEventListener("complete", (e) => { resolve(dump); }); for (let i = 0; i < db.objectStoreNames.length; i++) { @@ -128,7 +128,7 @@ function exportDb(db): Promise { dump.stores[name] = storeDump; let store = tx.objectStore(name) .openCursor() - .addEventListener('success', (e) => { + .addEventListener("success", (e) => { let cursor = e.target.result; if (cursor) { storeDump[cursor.key] = cursor.value; diff --git a/extension/background/emscriptif.ts b/extension/background/emscriptif.ts index 6b9d5014a..691c27379 100644 --- a/extension/background/emscriptif.ts +++ b/extension/background/emscriptif.ts @@ -291,7 +291,7 @@ arenaStack.push(new SyncArena()); class Amount extends ArenaObject { - constructor(args?: AmountJson, arena?: Arena) { + constructor(args?: AmountJson_interface, arena?: Arena) { super(arena); if (args) { this.nativePtr = emscAlloc.get_amount(args.value, diff --git a/extension/background/wallet.js b/extension/background/wallet.js index ebb04e832..120d177eb 100644 --- a/extension/background/wallet.js +++ b/extension/background/wallet.js @@ -21,7 +21,29 @@ */ /// /// -'use strict'; +"use strict"; +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +class MyClass { +} +let AmountJson = class { +}; +__decorate([ + Checkable.Number +], AmountJson.prototype, "value", void 0); +__decorate([ + Checkable.Number +], AmountJson.prototype, "fraction", void 0); +__decorate([ + Checkable.String +], AmountJson.prototype, "currency", void 0); +AmountJson = __decorate([ + Checkable.Class +], AmountJson); /** * See http://api.taler.net/wallet.html#general */ diff --git a/extension/background/wallet.ts b/extension/background/wallet.ts index 5f9bb65a6..bb4326ec5 100644 --- a/extension/background/wallet.ts +++ b/extension/background/wallet.ts @@ -24,10 +24,31 @@ /// /// -'use strict'; +"use strict"; -interface AmountJson { +class MyClass { + value: number; + fraction: number; + currency: string; +} + + +@Checkable.Class +class AmountJson { + @Checkable.Number + value: number; + + @Checkable.Number + fraction: number; + + @Checkable.String + currency: string; + + static check: (v: any) => AmountJson; +} + +interface AmountJson_interface { value: number; fraction: number currency: string; @@ -58,11 +79,11 @@ interface Offer { interface Contract { H_wire: string; - amount: AmountJson; + amount: AmountJson_interface; auditors: string[]; expiry: string, locations: string[]; - max_fee: AmountJson; + max_fee: AmountJson_interface; merchant: any; merchant_pub: string; mints: MintInfo[]; @@ -77,7 +98,7 @@ interface CoinPaySig { coin_pub: string; ub_sig: string; denom_pub: string; - f: AmountJson; + f: AmountJson_interface; } @@ -181,8 +202,8 @@ function signDeposit(db: IDBDatabase, * @param allowedMints */ function getPossibleMintCoins(db: IDBDatabase, - paymentAmount: AmountJson, - depositFeeLimit: AmountJson, + paymentAmount: AmountJson_interface, + depositFeeLimit: AmountJson_interface, allowedMints: MintInfo[]): Promise { @@ -617,7 +638,7 @@ function updateMintFromUrl(db, baseUrl) { function getBalances(db): Promise { function collectBalances(c: Db.Coin, byCurrency) { - let acc: AmountJson = byCurrency[c.currentAmount.currency]; + let acc: AmountJson_interface = byCurrency[c.currentAmount.currency]; if (!acc) { acc = Amount.getZero(c.currentAmount.currency).toJson(); } diff --git a/extension/manifest.json b/extension/manifest.json index 478c2a9b0..7c0f295b4 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -48,6 +48,7 @@ "background/db.js", "background/query.js", "background/messaging.js", + "background/checkable.js", "background/http.js", "background/wallet.js" ] diff --git a/extension/tsconfig.json b/extension/tsconfig.json index 2d166debd..5586d78bc 100644 --- a/extension/tsconfig.json +++ b/extension/tsconfig.json @@ -10,6 +10,7 @@ "background/db.ts", "background/query.ts", "background/http.ts", + "background/checkable.ts", "background/messaging.ts", "lib/util.ts", "lib/polyfill-react.ts",