@onekeyfe/hd-transport 0.1.39 → 0.1.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,283 @@
1
+ /* eslint-disable react-hooks/rules-of-hooks */
2
+ /* eslint-disable import/no-unresolved */
3
+ // flowtype only
4
+ // flowtype doesn't have `enum` declarations like typescript
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ const json = require('../messages.json');
10
+ const { RULE_PATCH, TYPE_PATCH, DEFINITION_PATCH, SKIP, UINT_TYPE } = require('./protobuf-patches');
11
+
12
+ const args = process.argv.slice(2);
13
+
14
+ const isTypescript = args.includes('typescript');
15
+
16
+ // proto types to javascript types
17
+ const FIELD_TYPES = {
18
+ uint32: 'number',
19
+ uint64: 'number',
20
+ sint32: 'number',
21
+ sint64: 'number',
22
+ bool: 'boolean',
23
+ bytes: 'string',
24
+ // 'bytes': 'Uint8Array | number[] | Buffer | string', // protobuf will handle conversion
25
+ };
26
+
27
+ const types = []; // { type: 'enum | message', name: string, value: string[], exact?: boolean };
28
+
29
+ // enums used as keys (string), used as values (number) by default
30
+ const ENUM_KEYS = [
31
+ 'InputScriptType',
32
+ 'OutputScriptType',
33
+ 'RequestType',
34
+ 'BackupType',
35
+ 'Capability',
36
+ 'SafetyCheckLevel',
37
+ 'ButtonRequestType',
38
+ 'PinMatrixRequestType',
39
+ 'WordRequestType',
40
+ ];
41
+
42
+ const parseEnumTypescript = (itemName, item) => {
43
+ const value = [];
44
+ const IS_KEY = ENUM_KEYS.includes(itemName);
45
+ // declare enum
46
+ if (IS_KEY) {
47
+ value.push(`export enum Enum_${itemName} {`);
48
+ } else {
49
+ value.push(`export enum ${itemName} {`);
50
+ }
51
+
52
+ // declare fields
53
+ Object.entries(item.values).forEach(([name, id]) => {
54
+ value.push(` ${name} = ${id},`);
55
+ });
56
+ // close enum declaration
57
+ value.push('}');
58
+
59
+ if (IS_KEY) {
60
+ value.push(`export type ${itemName} = keyof typeof Enum_${itemName};`);
61
+ }
62
+ // empty line
63
+ value.push('');
64
+
65
+ types.push({
66
+ type: 'enum',
67
+ name: itemName,
68
+ value: value.join('\n'),
69
+ });
70
+ };
71
+
72
+ const parseEnum = (itemName, item) => {
73
+ if (isTypescript) return parseEnumTypescript(itemName, item);
74
+ const value = [];
75
+ // declare enum
76
+ value.push(`export const Enum_${itemName} = Object.freeze({`);
77
+ // declare fields
78
+ Object.entries(item.values).forEach(([name, id]) => {
79
+ value.push(` ${name}: ${id},`);
80
+ });
81
+ // close enum declaration
82
+ value.push('});');
83
+ // declare enum type using Keys or Values
84
+ const KEY = ENUM_KEYS.includes(itemName) ? 'Keys' : 'Values';
85
+ value.push(`export type ${itemName} = $${KEY}<typeof Enum_${itemName}>;`);
86
+ // empty line
87
+ value.push('');
88
+
89
+ types.push({
90
+ type: 'enum',
91
+ name: itemName,
92
+ value: value.join('\n'),
93
+ });
94
+ };
95
+
96
+ const useDefinition = def => {
97
+ // remove flow overhead
98
+ const clean = def.replace(/\/\/ @flow/, '').replace(/\/\/ @overhead-start(.*)@overhead-end/s, '');
99
+
100
+ if (isTypescript) {
101
+ // use typescript variant
102
+ // replace flowtype $Exact declaration: {| foo: 1 |} => { foo: 1 }
103
+ // replace flowtype spread with typescript union: { ...T, foo: 1 } => T & { foo: 1 }, see TxInputType patch
104
+ return clean
105
+ .replace(/\/\/ @typescript-variant:/, '')
106
+ .replace(/\/\/ @flowtype-variant(.*)/, '')
107
+ .replace(/{\|/gi, '{')
108
+ .replace(/\|}/gi, '}')
109
+ .replace(/\{\n.*.\.{3}(.*?),/g, '$1 & {');
110
+ }
111
+ return clean.replace(/\/\/ @typescript-variant(.*)/, '').replace(/\/\/ @flowtype-variant:/, '');
112
+ };
113
+
114
+ const parseMessage = (messageName, message, depth = 0) => {
115
+ if (messageName === 'google') return;
116
+ const value = [];
117
+ // add comment line
118
+ if (!depth) value.push(`// ${messageName}`);
119
+ // declare nested enums
120
+
121
+ // declare nested values
122
+ if (message.nested) {
123
+ Object.keys(message.nested).map(item => parseMessage(item, message.nested[item], depth + 1));
124
+ }
125
+
126
+ if (message.values) {
127
+ return parseEnum(messageName, message);
128
+ }
129
+ if (!message.fields || !Object.keys(message.fields).length) {
130
+ // few types are just empty objects, make it one line
131
+ value.push(`export type ${messageName} = {};`);
132
+ value.push('');
133
+ } else {
134
+ // find patch
135
+ const definition = DEFINITION_PATCH[messageName];
136
+ if (definition) {
137
+ // replace whole declaration
138
+ value.push(useDefinition(definition));
139
+ } else {
140
+ // declare type
141
+ value.push(`export type ${messageName} = {`);
142
+ Object.keys(message.fields).forEach(fieldName => {
143
+ const field = message.fields[fieldName];
144
+ const fieldKey = `${messageName}.${fieldName}`;
145
+ // find patch for "rule"
146
+ const fieldRule = RULE_PATCH[fieldKey] || field.rule;
147
+ const rule = fieldRule === 'required' || fieldRule === 'repeated' ? ': ' : '?: ';
148
+ // find patch for "type"
149
+ let type = TYPE_PATCH[fieldKey] || FIELD_TYPES[field.type] || field.type;
150
+ // automatically convert all amount and fee fields to UINT_TYPE
151
+ if (['amount', 'fee'].includes(fieldName)) {
152
+ type = UINT_TYPE;
153
+ }
154
+ // array
155
+ if (field.rule === 'repeated') {
156
+ type = type.split('|').length > 1 ? `Array<${type}>` : `${type}[]`;
157
+ }
158
+ value.push(` ${fieldName}${rule}${type};`);
159
+ });
160
+ // close type declaration
161
+ value.push('};');
162
+ // empty line
163
+ value.push('');
164
+ }
165
+ }
166
+ // type doest have to be e
167
+ const exact = message.fields && Object.values(message.fields).find(f => f.rule === 'required');
168
+ types.push({
169
+ type: 'message',
170
+ name: messageName,
171
+ value: value.join('\n'),
172
+ exact,
173
+ });
174
+ };
175
+
176
+ // top level messages and nested messages
177
+ Object.keys(json.nested).map(e => parseMessage(e, json.nested[e]));
178
+
179
+ // types needs reordering (used before defined)
180
+ const ORDER = {
181
+ BinanceCoin: 'BinanceInputOutput',
182
+ HDNodeType: 'HDNodePathType',
183
+ CardanoAssetGroupType: 'CardanoTxOutputType',
184
+ CardanoTokenType: 'CardanoAssetGroupType',
185
+ TxAck: 'TxAckInputWrapper',
186
+ EthereumFieldType: 'EthereumStructMember',
187
+ EthereumDataType: 'EthereumFieldType',
188
+ PaymentRequestMemo: 'TxAckPaymentRequest',
189
+ };
190
+
191
+ Object.keys(ORDER).forEach(key => {
192
+ // find indexes
193
+ const indexA = types.findIndex(t => t && t.name === key);
194
+ const indexB = types.findIndex(t => t && t.name === ORDER[key]);
195
+ const prevA = types[indexA];
196
+ // replace values
197
+ delete types[indexA];
198
+ types.splice(indexB, 0, prevA);
199
+ });
200
+
201
+ // skip not needed types
202
+ SKIP.forEach(key => {
203
+ const index = types.findIndex(t => t && t.name === key);
204
+ delete types[index];
205
+ });
206
+
207
+ // create content from types
208
+ const content = types.flatMap(t => (t ? [t.value] : [])).join('\n');
209
+
210
+ const lines = []; // string[]
211
+ if (!isTypescript) lines.push('// @flow');
212
+ lines.push('// This file is auto generated from data/messages/message.json');
213
+ lines.push('');
214
+ lines.push('// custom type uint32/64 may be represented as string');
215
+ lines.push(`export type ${UINT_TYPE} = string | number;`);
216
+ lines.push('');
217
+ lines.push(content);
218
+
219
+ // create custom definition
220
+ if (!isTypescript) {
221
+ lines.push('// custom connect definitions');
222
+ lines.push('export type MessageType = {');
223
+ types
224
+ .flatMap(t => (t && t.type === 'message' ? [t] : []))
225
+ .forEach(t => {
226
+ if (t.exact) {
227
+ lines.push(` ${t.name}: $Exact<${t.name}>;`);
228
+ } else {
229
+ lines.push(` ${t.name}: ${t.name};`);
230
+ }
231
+ // lines.push(' ' + t.name + ': $Exact<' + t.name + '>;');
232
+ });
233
+ lines.push('};');
234
+
235
+ // additional types utilities
236
+ lines.push(`
237
+ export type MessageKey = $Keys<MessageType>;
238
+
239
+ export type MessageResponse<T: MessageKey> = {
240
+ type: T;
241
+ message: $ElementType<MessageType, T>;
242
+ };
243
+
244
+ export type TypedCall = <T: MessageKey, R: MessageKey>(
245
+ type: T,
246
+ resType: R,
247
+ message?: $ElementType<MessageType, T>
248
+ ) => Promise<MessageResponse<R>>;
249
+ `);
250
+ } else {
251
+ lines.push('// custom connect definitions');
252
+ lines.push('export type MessageType = {');
253
+ types
254
+ .flatMap(t => (t && t.type === 'message' ? [t] : []))
255
+ .forEach(t => {
256
+ lines.push(` ${t.name}: ${t.name};`);
257
+ });
258
+ lines.push('};');
259
+
260
+ // additional types utilities
261
+ lines.push(`
262
+ export type MessageKey = keyof MessageType;
263
+
264
+ export type MessageResponse<T extends MessageKey> = {
265
+ type: T;
266
+ message: MessageType[T];
267
+ };
268
+
269
+ export type TypedCall = <T extends MessageKey, R extends MessageKey>(
270
+ type: T,
271
+ resType: R,
272
+ message?: MessageType[T],
273
+ ) => Promise<MessageResponse<R>>;
274
+ `);
275
+ }
276
+
277
+ // save to file
278
+ const filePath = isTypescript
279
+ ? path.join(__dirname, '../src/types/messages.ts')
280
+ : path.join(__dirname, '../protobuf.js');
281
+ fs.writeFile(filePath, lines.join('\n'), err => {
282
+ if (err) return console.log(err);
283
+ });
@@ -1,5 +1,5 @@
1
- import ByteBuffer from 'bytebuffer';
2
1
  import { Type, Message, Field } from 'protobufjs/light';
2
+ import ByteBuffer from 'bytebuffer';
3
3
  import { isPrimitiveField } from '../../utils/protobuf';
4
4
 
5
5
  const transform = (field: Field, value: any) => {
@@ -1,6 +1,6 @@
1
- import ByteBuffer from 'bytebuffer';
2
1
  import { Type } from 'protobufjs/light';
3
2
  import { Buffer } from 'buffer';
3
+ import ByteBuffer from 'bytebuffer';
4
4
 
5
5
  import { isPrimitiveField } from '../../utils/protobuf';
6
6
 
@@ -1,5 +1,5 @@
1
- import ByteBuffer from 'bytebuffer';
2
1
  import { Root } from 'protobufjs/light';
2
+ import ByteBuffer from 'bytebuffer';
3
3
 
4
4
  import * as decodeProtobuf from './protobuf/decode';
5
5
  import * as decodeProtocol from './protocol/decode';
@@ -1,8 +1,8 @@
1
1
  // Logic of sending data to trezor
2
2
  //
3
3
  // Logic of "call" is broken to two parts - sending and receiving
4
- import ByteBuffer from 'bytebuffer';
5
4
  import { Root } from 'protobufjs/light';
5
+ import ByteBuffer from 'bytebuffer';
6
6
  import { encode as encodeProtobuf } from './protobuf';
7
7
  import { encode as encodeProtocol } from './protocol';
8
8
  import { createMessageFromName } from './protobuf/messages';