@cicctencent/tars2node-cli 0.0.1

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,508 @@
1
+ 'use strict';
2
+
3
+ const BaseDef = require('./base');
4
+
5
+ const TUP_INIT = 'const tup = new TarsStream.UniAttribute();';
6
+ const TUP_VER = 'tup.tupVersion = this.getRequestVersion();';
7
+ const TUP_VER_CUR = 'tup.tupVersion = current.getRequestVersion();';
8
+ const VERSION_CHECK = 'this.getRequestVersion() === TarsStream.Tup.TUP_SIMPLE || this.getRequestVersion() === TarsStream.Tup.TUP_COMPLEX';
9
+ const VERSION_CHECK_CUR = 'current.getRequestVersion() === TarsStream.Tup.TUP_SIMPLE || current.getRequestVersion() === TarsStream.Tup.TUP_COMPLEX';
10
+
11
+ const OS_INIT = 'const os = new TarsStream.TarsOutputStream();';
12
+ const IS_INIT = 'const is = new TarsStream.TarsInputStream(binBuffer);';
13
+
14
+ class InterfDef extends BaseDef {
15
+ /**
16
+ *
17
+ * 声明JCE-Struct节点类型
18
+ * @typedef { refType | vecType | string | mapType } tarsType
19
+ *
20
+ * @typedef {object} refType
21
+ * @property {string} target
22
+ * @property {string[]} nested
23
+ *
24
+ * @typedef {object} vecType
25
+ * @property {'vector'} type
26
+ * @property {tarsType} target
27
+ *
28
+ * @typedef {object} mapType
29
+ * @property {'map'} type
30
+ * @property {tarsType} key
31
+ * @property {tarsType} value
32
+ *
33
+ * @typedef {object} param
34
+ * @property {string} id
35
+ * @property {'in'|'out'} io
36
+ * @property {tarsType} type
37
+ *
38
+ * @typedef {object} TarsInterfMethod
39
+ * @property {string} id
40
+ * @property {'func'} type
41
+ * @property {tarsType} output
42
+ * @property {param[]} params
43
+ *
44
+ * @typedef {object} TarsInterfNode
45
+ * @property {string} id
46
+ * @property {'interface'} type
47
+ * @property {TarsInterfMethod[]} methods
48
+ *
49
+ * 工具类类型
50
+ * @typedef {import("../printer")} Printer
51
+ * @typedef {import("../typing")} Typing
52
+ *
53
+ * @typedef {object} CompilerOptions
54
+ * @property {'all'|'client'|'service'} mode
55
+ * @property {'string'|'number'|'bigint'} long
56
+ * @property {boolean} withReturn
57
+ * @property {boolean} gather
58
+ * @property {boolean} interface
59
+ * @property {string} [output]
60
+ *
61
+ * 创建Struct解析实例
62
+ * @constructor
63
+ * @param {Printer} printer - print类实例
64
+ * @param {Typing} typing - Typing类实例
65
+ * @param {CompilerOptions} options - 编译配置选项
66
+ */
67
+ constructor(printer, typing, options) {
68
+ super('', printer, typing, options);
69
+ this._id = '';
70
+ /** @type {TarsInterfMethod[]} */
71
+ this._methods = [];
72
+ this._imp = '';
73
+ this._beforeComment = '';
74
+ }
75
+
76
+ /**
77
+ * @param {string} name
78
+ * @param {TarsInterfNode} node
79
+ */
80
+ reset(name, node) {
81
+ this.setModuleName(name);
82
+ this.setNode(node);
83
+
84
+ return this;
85
+ }
86
+
87
+ /**
88
+ * @param {TarsInterfNode} node
89
+ */
90
+ setNode({ id, methods, beforeComment = '' }) {
91
+ this._id = id;
92
+ this._methods = methods;
93
+ this._imp = `${id}Imp`;
94
+ this._beforeComment = beforeComment;
95
+ }
96
+
97
+ build() {
98
+ this._interface();
99
+ this._class();
100
+ }
101
+
102
+ _interface() {
103
+ this._methods.forEach(this._methodParamsGatherInterface.bind(this));
104
+ this._methods.forEach(this._interfaceForMethod.bind(this));
105
+ }
106
+
107
+ /**
108
+ * @param {TarsInterfMethod} method
109
+ */
110
+ _interfaceForMethod({ params, output, id }) {
111
+ const ps = [];
112
+ if (output !== 'void') ps.push(['ret', this._typing.toTSType(output, this._moduleName)]);
113
+ params.filter(({ io }) => io === 'out')
114
+ .forEach(({ id: pid, type: ptype }) => {
115
+ ps.push([pid, this._typing.toTSType(ptype, this._moduleName)]);
116
+ });
117
+ this._printer
118
+ .word(this._beforeComment)
119
+ .newline()
120
+ .word('export', 'R')
121
+ .word('interface', 'R')
122
+ .word(this._methodConsts(id, 'CUR'), 'R')
123
+ .word('extends', 'R')
124
+ .word('TarsRpc.TarsCurrent', 'R')
125
+ .word('{')
126
+ .indent()
127
+ .line(`sendResponse(${ps.map(([k, t]) => `${k}: ${t}`).join(', ')}): void;`)
128
+ .dedent()
129
+ .line('}');
130
+ }
131
+
132
+ _class() {
133
+ this
134
+ ._printer
135
+ .newline()
136
+ .word('export', 'R')
137
+ .word('class', 'R')
138
+ .word(this._imp, 'R')
139
+ .scope(() => {
140
+ this._classCommon();
141
+ this._methods.forEach(this._method.bind(this));
142
+ });
143
+ }
144
+
145
+ _classCommon() {
146
+ this._printer
147
+ .classMethod({
148
+ name: 'initialize',
149
+ params: [],
150
+ returnType: 'Promise<any> | void',
151
+ type: 'protected',
152
+ callback: () => {},
153
+ })
154
+ .classMethod({
155
+ name: 'onDispatch',
156
+ params: [['current', 'TarsRpc.TarsCurrent'], ['funcName', 'string'], ['binBuffer', 'TarsStream.BinBuffer']],
157
+ returnType: 'number',
158
+ type: 'protected',
159
+ callback: () => {
160
+ this._printer
161
+ .line('if ("__" + funcName in this) ')
162
+ .scope(() => {
163
+ this._printer.line('return (<{[index: string]: Function}><unknown>this)["__" + funcName](current, binBuffer);');
164
+ })
165
+ .word('else', 'LR')
166
+ .scope(() => {
167
+ this._printer.line('return TarsRpc.error.SERVER.FUNC_NOT_FOUND;');
168
+ });
169
+ },
170
+ })
171
+ .classMethod({
172
+ name: '__taf_ping',
173
+ params: [['current', 'TarsRpc.TarsCurrent']],
174
+ returnType: 'number',
175
+ type: 'protected',
176
+ callback: () => {
177
+ this._tafPingRe();
178
+ },
179
+ });
180
+ }
181
+
182
+ _tafPingRe() {
183
+ this._printer
184
+ .line(`const ${this._methodReName('taf_ping')}`)
185
+ .word('= function (this: TarsRpc.TarsCurrent, _ret: number) {')
186
+ .indent()
187
+ .line('if (');
188
+ this._printer.word(VERSION_CHECK);
189
+ this._printer
190
+ .word(') {')
191
+ .indent().line(TUP_INIT).line(TUP_VER)
192
+ .line('tup.writeInt32("", _ret);')
193
+ .line('this.doResponse(tup.encode());')
194
+ .dedent()
195
+ .line('} else {')
196
+ .indent()
197
+ .line(OS_INIT)
198
+ .line('os.writeInt32(0, _ret);')
199
+ .line('this.doResponse(os.getBinBuffer());')
200
+ .dedent()
201
+ .line('}')
202
+ .dedent()
203
+ .line('}')
204
+ .semicolon()
205
+ .line(`${this._methodReName('taf_ping')}.call(current, 0);`)
206
+ .line('return TarsRpc.error.SUCCESS;');
207
+ }
208
+
209
+ /**
210
+ * @param {string} name
211
+ * @param {string} type
212
+ * @return {string}
213
+ */
214
+ _methodConsts(name, type) {
215
+ return `${this._id}$${name}$${type}`;
216
+ }
217
+
218
+ /**
219
+ * @param {string} name
220
+ * @return {string}
221
+ */
222
+ _methodReName(name) {
223
+ return `__${this._moduleName}_${this._id}$${name}$RE`;
224
+ }
225
+
226
+ /**
227
+ * @param {TarsInterfMethod} method
228
+ */
229
+ _method(method) {
230
+ const { id, output } = method;
231
+ this._printer
232
+ .classMethod({
233
+ name: id,
234
+ params: this._methodParams(method),
235
+ returnType: 'void',
236
+ callback: () => {
237
+ this._printer.line(`assert.fail("${id} function not implemented");`);
238
+ },
239
+ })
240
+ .classMethod({
241
+ name: `__${id}`,
242
+ type: 'protected',
243
+ params: [['current', this._methodConsts(id, 'CUR')], ['binBuffer', 'TarsStream.BinBuffer']],
244
+ returnType: 'number',
245
+ callback: () => {
246
+ method.params.forEach(({ id: pid }) => { this._printer.line(`let ${pid}: any = null;`); });
247
+ if (this._options.withReturn) {
248
+ const ret = this._typing.isNotObjectType(output, this._moduleName)
249
+ ? this._typing.toDefaultValue(output)
250
+ : `new ${this._typing.toTSType(output, this._moduleName)}`;
251
+ this._printer.line(`const ret = ${ret};`);
252
+ }
253
+ this._methodRe(method);
254
+ this._methodLogic(method);
255
+ },
256
+ });
257
+ }
258
+
259
+ /**
260
+ * @param {TarsInterfMethod} method
261
+ */
262
+ _methodRe({ id, output, params }) {
263
+ const outputParams = params.filter(param => param.io === 'out');
264
+ const ps = [['this', this._methodConsts(id, 'CUR')]];
265
+ if (output !== 'void') {
266
+ ps.push(['_ret', this._typing.toTSType(output, this._moduleName)]);
267
+ }
268
+ outputParams.forEach(({ id: pid, type: ptype }) => {
269
+ ps.push([pid, this._typing.toTSType(ptype, this._moduleName)]);
270
+ });
271
+ this
272
+ . _printer
273
+ .newline()
274
+ .word('const', 'R')
275
+ .word(this._methodReName(id), 'R')
276
+ .word('=', 'R')
277
+ .word(`function(${ps.map(([pid, ptype]) => `${pid}: ${ptype}`).join(', ')})`, 'R')
278
+ .word('{')
279
+ .indent();
280
+ this._printer.line('if (');
281
+ this._printer.word(VERSION_CHECK);
282
+ this._printer
283
+ .word(') {')
284
+ .indent().line(TUP_INIT).line(TUP_VER);
285
+ if (output !== 'void') {
286
+ this._printer
287
+ .line(this._tupWrite(output, '_ret'));
288
+ }
289
+ outputParams.forEach(({ id: pid, type: ptype }) => {
290
+ this._printer.line(this._tupWrite(ptype, pid, pid));
291
+ });
292
+ this._printer
293
+ .line('this.doResponse(tup.encode());')
294
+ .dedent()
295
+ .line('} else {')
296
+ .indent()
297
+ .line(OS_INIT);
298
+ if (output !== 'void') {
299
+ this._printer
300
+ .line(`os.write${this._typing.toIOType(output, this._moduleName)}(0, _ret${this._needGenerateParamForLong(output)})`);
301
+ }
302
+ outputParams.forEach(({ id: pid, type: ptype }) => {
303
+ const index = params.findIndex(({ id: mid }) => mid === pid) + 1;
304
+ this._printer
305
+ .line(`os.write${this._typing.toIOType(ptype, this._moduleName)}(${index}, ${pid}${this._needGenerateParamForLong(ptype)});`);
306
+ });
307
+ this._printer
308
+ .line('this.doResponse(os.getBinBuffer());')
309
+ .dedent().line('}').dedent()
310
+ .line('};');
311
+ }
312
+
313
+ /**
314
+ * @param {TarsInterfMethod} method
315
+ */
316
+ _methodLogic({ id, params }) {
317
+ this._printer.line('if (');
318
+ this._printer.word(VERSION_CHECK_CUR);
319
+ this._printer.word(')', 'R')
320
+ .scope(() => {
321
+ this._printer
322
+ .line(TUP_INIT).line(TUP_VER_CUR)
323
+ .line('tup.decode(binBuffer);');
324
+ params.forEach(({ type: ptype, id: pid, io }) => {
325
+ this._printer.line(this._tupRead(ptype, pid, io));
326
+ });
327
+ })
328
+ .word('else', 'LR')
329
+ .scope(() => {
330
+ this._printer.line(IS_INIT);
331
+ params.forEach(({ type: ptype, id: pid, io }) => {
332
+ let value;
333
+ if (this._typing.isNotObjectType(ptype, this._moduleName)) {
334
+ value = this._typing.toIOValue(ptype);
335
+ } else {
336
+ const { source, tafType } = this._typing.toTarsStreamType(ptype, this._moduleName);
337
+ if (source && source.type === 'enum') {
338
+ value = `${tafType}.${source.value[0].id}`;
339
+ } else {
340
+ value = tafType;
341
+ }
342
+ }
343
+
344
+ const index = params.findIndex(({ id: mid }) => mid === pid) + 1;
345
+
346
+ const result = `${pid} = is.read${this._typing.toIOType(ptype, this._moduleName)}(${index}, ${io === 'in'}, ${value}${this._needGenerateParamForLong(ptype)})`;
347
+
348
+ this._printer.line(result);
349
+ });
350
+ })
351
+ .line(`current.sendResponse = ${this._methodReName(id)};`);
352
+
353
+ const ps = ['current'];
354
+
355
+ if (this._options.withReturn) {
356
+ ps.push('ret');
357
+ }
358
+
359
+ if (this._options.gather) {
360
+ /** @type {(type: string, name: string) => void} */
361
+ const gatherParams = (type, name) => {
362
+ const p = params
363
+ .filter(({ io }) => io === type)
364
+ .map(({ id: pid }) => pid)
365
+ .join(', ');
366
+ this._printer.line(`const ${name} = { ${p} };`);
367
+ };
368
+
369
+ gatherParams('in', 'input');
370
+ gatherParams('out', 'output');
371
+
372
+ ps.push('input', 'output');
373
+ } else {
374
+ params.forEach(({ id: pid }) => {
375
+ ps.push(pid);
376
+ });
377
+ }
378
+
379
+ this._printer
380
+ .line(`this.${id}(${ps.join(', ')});`)
381
+ .line('return TarsRpc.error.SUCCESS;');
382
+ }
383
+
384
+ /**
385
+ * @param {tarsType} type
386
+ * @return {string}
387
+ */
388
+ _needGenerateParamForLong(type) {
389
+ const longLastParam = type === 'long' && this.generateLastParamForLong();
390
+ return longLastParam ? `, ${longLastParam}` : '';
391
+ }
392
+
393
+ /**
394
+ * @param {tarsType} type
395
+ * @param {string} id
396
+ * @param {string} [name = '']
397
+ * @return {string}
398
+ */
399
+ _tupWrite(type, id, name = '') {
400
+ return `tup.write${this._typing.toIOType(type, this._moduleName)}("${name}", ${id}${this._needGenerateParamForLong(type)});`;
401
+ }
402
+
403
+ /**
404
+ * @param {tarsType} type
405
+ * @param {string} id
406
+ * @param {'in'|'out'} io
407
+ * @return {string}
408
+ */
409
+ _tupRead(type, id, io) {
410
+ const ioType = this._typing.toIOType(type, this._moduleName);
411
+ const params = [`"${id}"`];
412
+ if (io === 'out') {
413
+ if (this._typing.isNotObjectType(type, this._moduleName)) {
414
+ params.push(/** @type string */ (this._typing.toIOValue(type)));
415
+ const longLastParam = type === 'long' && this.generateLastParamForLong();
416
+ if (longLastParam) {
417
+ params.push(`${longLastParam}`);
418
+ }
419
+ } else {
420
+ const { tafType } = this._typing.toTarsStreamType(type, this._moduleName);
421
+ params.push(tafType, `new ${tafType}`);
422
+ }
423
+ } else if (!this._typing.isNotObjectType(type, this._moduleName)) {
424
+ const { tafType } = this._typing.toTarsStreamType(type, this._moduleName);
425
+ params.push(tafType);
426
+ }
427
+
428
+ return `${id} = tup.read${ioType}(${params.join(', ')});`;
429
+ }
430
+
431
+ /**
432
+ *
433
+ * @typedef {{input: Array<[string, string]>, output: Array<[string, string]>}} Params
434
+ *
435
+ * @param {TarsInterfMethod} method
436
+ * @return {Array<[string, string]>}
437
+ */
438
+ _methodParams({ id, output, params }) {
439
+ /** @type {Array<[string, string]>} */
440
+ const ps = [['_current', this._methodConsts(id, 'CUR')]];
441
+ if (this._options.withReturn) ps.push(['_ret', this._typing.toTSType(output, this._moduleName)]);
442
+ if (this._options.gather) {
443
+ ps.push(['_input', this._methodConsts(id, 'Input')], ['_output', this._methodConsts(id, 'Output')]);
444
+ } else {
445
+ params.forEach(({ id: pid, type: ptype }) => {
446
+ ps.push([`_${pid}`, this._typing.toTSType(ptype, this._moduleName)]);
447
+ });
448
+ }
449
+
450
+ return ps;
451
+ }
452
+
453
+ /**
454
+ * @description: 生成method对应的input和output的interface
455
+ * @param {TarsInterfMethod} method
456
+ */
457
+ _methodParamsGatherInterface({ id, params, output: ret }) {
458
+ const inputInterfaceId = this._methodConsts(id, 'Input');
459
+ const outputInterfaceId = this._methodConsts(id, 'Output');
460
+ const curInterfaceId = this._methodConsts(id, 'CUR');
461
+ const cpsInterfaceId = this._methodConsts(id, 'CPS');
462
+ const { input, output } = params.reduce(
463
+ (acc, { id: pid, io, type: ptype }) => {
464
+ const t = [pid, this._typing.toTSObjectType(ptype, this._moduleName)];
465
+ if (io === 'out') {
466
+ return {
467
+ input: acc.input,
468
+ output: /** @type {Array<[string, string]>} */ ([...acc.output, t]),
469
+ };
470
+ }
471
+ return {
472
+ input: /** @type {Array<[string, string]>} */ ([...acc.input, t]),
473
+ output: acc.output,
474
+ };
475
+ },
476
+ /** @type {Params} */ ({ input: [], output: [] }),
477
+ );
478
+
479
+ const retType = this._typing.toTSObjectType(ret, this._moduleName);
480
+ /** @type {Array<[string, string]>} */
481
+ const cps = [
482
+ ['req', inputInterfaceId],
483
+ ['res', outputInterfaceId],
484
+ ['ret', retType],
485
+ ['cur', curInterfaceId],
486
+ [`send(ret?: ${retType}, res?: ${outputInterfaceId})`, 'void'],
487
+ ];
488
+
489
+ /**
490
+ * @type {(i: string, ps: Array<[string, string]>) => void}
491
+ */
492
+ const generateInterface = (i, ps) => {
493
+ this._printer.newline()
494
+ .word('export', 'R').word('interface', 'R').word(i, 'R')
495
+ .scope(() => {
496
+ ps.forEach(([pid, ptype]) => {
497
+ this._printer.line(`${pid}: ${ptype}`).semicolon();
498
+ });
499
+ });
500
+ };
501
+
502
+ generateInterface(inputInterfaceId, input);
503
+ generateInterface(outputInterfaceId, output);
504
+ generateInterface(cpsInterfaceId, cps);
505
+ }
506
+ }
507
+
508
+ module.exports = InterfDef;