UNPKG

2.88 kBJavaScriptView Raw
1const qs = require('qs');
2
3/**
4 * URI parser and generator
5 */
6class URI {
7
8 /**
9 *
10 * URI Methods. Shall only be used on AmonLib.URI instance.
11 * Do not instanciate by yourself.
12 *
13 */
14 constructor(coins) {
15
16 this.coins = coins;
17
18 this.regex = /([a-z]+):\/?\/?([^?]+)(\?([^]+))?/;
19
20 }
21
22 /**
23 *
24 * This parses an URI to an object.
25 * Input is a string, either an address or a valid URI
26 *
27 * @param {Object} str address or URI
28 *
29 * @return {Object} obj
30 * @return {string} obj.address
31 * @return {?string} obj.coinCode [BTC, ETH]
32 * @return {?string} obj.amount Amount requested, optional
33 */
34 parse(str) {
35
36 if (this.isURI(str)) {
37
38 return this.parseURI(str);
39
40 } else {
41
42 const coin = this.getCoinFromAddress(str);
43
44 if (coin) {
45
46 return {
47 coinCode: coin.constructor.code,
48 address: str,
49 };
50
51 } else {
52
53 throw new Error(`Unable to parse URI: ${str}`)
54
55 }
56 }
57 }
58
59 /**
60 *
61 * This generate an URI string to be used in links or QR-code
62 *
63 * @param {Object} params
64 * @param {string} params.address
65 * @param {?string} params.coinCode [BTC, ETH]
66 * @param {?string} params.amount Amount requested, optional
67 *
68 * @return {string} URI as text
69 */
70 stringify(params) {
71
72 const { address, coinCode, amount } = params;
73
74 const coin = this.getCoinFromCode(coinCode);
75
76 if(!coin) {
77 throw new Error(`Unknown coin code: ${coinCode}`);
78 }
79
80 let uri = `${coin.getURIPrefix()}:`;
81 uri += address;
82
83 const options = {};
84
85 if (amount) {
86 options.amount = amount;
87 }
88
89 if (Object.keys(options).length > 0) {
90
91 uri += '?';
92 const query = qs.stringify(options);
93 uri += query;
94
95 }
96 return uri;
97
98 }
99
100
101 getCoinFromAddress(address) {
102 return this.findCoin(coin =>
103 !coin.constructor.isToken &&
104 coin.validAddress(address)
105 );
106 }
107 getCoinFromPrefix(prefix) {
108 return this.findCoin(coin => coin.getURIPrefix() === prefix);
109 }
110 getCoinFromCode(code) {
111 return this.coins[code];
112 }
113
114 findCoin(fn) {
115 return Object.keys(this.coins)
116 .map(coinCode => this.coins[coinCode])
117 .find(fn);
118 }
119
120 isURI(str) {
121 return this.regex.test(str);
122 }
123
124 isAddress(str) {
125 return !!this.getCoinFromAddress(str);
126 }
127
128 parseURI(str) {
129 const qregex = this.regex.exec(str);
130 if (!qregex) throw new Error(`Invalid URI: ${str}`);
131
132 const prefix = qregex[1];
133 const address = qregex[2];
134
135 const query = qregex[4];
136 const options = qs.parse(query);
137 const { amount } = options;
138
139 const coin = this.getCoinFromPrefix(prefix);
140
141 if(!coin) {
142 throw new Error(`Unknown URI protocol: ${prefix}`);
143 }
144
145 const data = {
146 coinCode: coin.constructor.code,
147 address,
148 amount,
149 };
150
151 return data;
152 }
153
154
155}
156
157module.exports = URI;