@cosmology/ast
Version:
Cosmos TypeScript AST generation
352 lines (351 loc) • 15.7 kB
JavaScript
import * as t from '@babel/types';
import { getDefaultTSTypeFromProtoType } from '../../types';
import { getFieldOptionalityForDefaults } from '../types';
const notUndefinedSetValue = (messageProp, objProp, expr) => {
return t.expressionStatement(t.logicalExpression('&&', t.binaryExpression('!==', t.memberExpression(t.identifier('message'), t.identifier(messageProp)), t.identifier('undefined')), t.assignmentExpression('=', t.memberExpression(t.identifier('obj'), t.identifier(objProp)), expr)));
};
const getPropNames = (field) => {
const messageProp = field.name;
const objProp = field.options?.json_name ?? field.name;
return {
messageProp,
objProp
};
};
export const toJSON = {
// message.sender !== undefined && (obj.sender = message.sender);
identity(args) {
const { messageProp, objProp } = getPropNames(args.field);
return notUndefinedSetValue(messageProp, objProp, t.memberExpression(t.identifier('message'), t.identifier(messageProp)));
},
string(args) {
return toJSON.identity(args);
},
double(args) {
return toJSON.identity(args);
},
float(args) {
return toJSON.identity(args);
},
bool(args) {
return toJSON.identity(args);
},
// message.maxDepth !== undefined && (obj.maxDepth = Math.round(message.maxDepth));
number(args) {
const { messageProp, objProp } = getPropNames(args.field);
return notUndefinedSetValue(messageProp, objProp, t.callExpression(t.memberExpression(t.identifier('Math'), t.identifier('round')), [
t.memberExpression(t.identifier('message'), t.identifier(messageProp))
]));
},
// message.maxDepth !== undefined && (obj.maxDepth = Math.round(message.maxDepth));
int32(args) {
return toJSON.number(args);
},
uint32(args) {
return toJSON.number(args);
},
sint32(args) {
return toJSON.number(args);
},
fixed32(args) {
return toJSON.number(args);
},
sfixed32(args) {
return toJSON.number(args);
},
// message.poolId !== undefined && (obj.poolId = (message.poolId || Long.UZERO).toString());
// message.poolId !== undefined && (obj.poolId = (message.poolId || undefined).toString());
long(args) {
const { messageProp, objProp } = getPropNames(args.field);
const isOptional = getFieldOptionalityForDefaults(args.context, args.field, args.isOneOf);
if (isOptional) {
return t.ifStatement(t.binaryExpression("!==", t.memberExpression(t.identifier("message"), t.identifier(messageProp)), t.identifier("undefined")), t.blockStatement([
t.expressionStatement(t.assignmentExpression("=", t.memberExpression(t.identifier("obj"), t.identifier(objProp)), t.callExpression(t.memberExpression(t.memberExpression(t.identifier("message"), t.identifier(messageProp)), t.identifier("toString")), []))),
]));
}
else {
return notUndefinedSetValue(messageProp, objProp, t.callExpression(t.memberExpression(t.logicalExpression('||', t.memberExpression(t.identifier('message'), t.identifier(messageProp)), getDefaultTSTypeFromProtoType(args.context, args.field, args.isOneOf)), t.identifier('toString')), []));
}
},
int64(args) {
return toJSON.long(args);
},
uint64(args) {
return toJSON.long(args);
},
sint64(args) {
return toJSON.long(args);
},
fixed64(args) {
return toJSON.long(args);
},
sfixed64(args) {
return toJSON.long(args);
},
// message.signDoc !== undefined && (obj.signDoc = message.signDoc ? SignDocDirectAux.toJSON(message.signDoc) : undefined);
type(args) {
let name = args.context.getTypeName(args.field);
const { messageProp, objProp } = getPropNames(args.field);
if (!args.context.options.aminoEncoding.useLegacyInlineEncoding &&
args.context.options.interfaces.enabled &&
args.context.options.interfaces?.useGlobalDecoderRegistry &&
args.field.type === 'google.protobuf.Any' &&
args.field.options['(cosmos_proto.accepts_interface)']) {
name = 'GlobalDecoderRegistry';
}
// TODO isn't the nested conditional a waste? (using ts-proto as reference)
// maybe null is OK?
return notUndefinedSetValue(messageProp, objProp, t.conditionalExpression(t.memberExpression(t.identifier('message'), t.identifier(messageProp)), t.callExpression(t.memberExpression(t.identifier(name), t.identifier('toJSON')), [
t.memberExpression(t.identifier('message'), t.identifier(messageProp))
]), t.identifier('undefined')));
},
// message.mode !== undefined && (obj.mode = signModeToJSON(message.mode));
enum(args) {
const { messageProp, objProp } = getPropNames(args.field);
const enumFuncName = args.context.getToEnum(args.field);
return notUndefinedSetValue(messageProp, objProp, t.callExpression(t.identifier(enumFuncName), [
t.memberExpression(t.identifier('message'), t.identifier(messageProp))
]));
},
// TODO again, another ts-proto reference that does not necessarily make sense
// message.queryData !== undefined && (obj.queryData = base64FromBytes(message.queryData !== undefined ? message.queryData : new Uint8Array()));
// message.queryData !== undefined && (obj.queryData = base64FromBytes(message.queryData !== undefined ? message.queryData : undefined));
bytes(args) {
args.context.addUtil('base64FromBytes');
const { messageProp, objProp } = getPropNames(args.field);
let expr;
if (args.isOptional) {
// message.bytesValue !== undefined && (obj.bytesValue = message.bytesValue !== undefined ? base64FromBytes(message.bytesValue) : undefined);
expr = t.conditionalExpression(t.binaryExpression('!==', t.memberExpression(t.identifier('message'), t.identifier(messageProp)), t.identifier('undefined')), t.callExpression(t.identifier('base64FromBytes'), [
t.memberExpression(t.identifier('message'), t.identifier(messageProp))
]), t.identifier('undefined'));
}
else {
// message.queryData !== undefined && (obj.queryData = base64FromBytes(message.queryData !== undefined ? message.queryData : new Uint8Array()));
expr = t.callExpression(t.identifier('base64FromBytes'), [
t.conditionalExpression(t.binaryExpression('!==', t.memberExpression(t.identifier('message'), t.identifier(messageProp)), t.identifier('undefined')), t.memberExpression(t.identifier('message'), t.identifier(messageProp)), getDefaultTSTypeFromProtoType(args.context, args.field, args.isOneOf))
]);
}
return notUndefinedSetValue(messageProp, objProp, expr);
},
// message.period !== undefined && (obj.period = message.period);
duration(args) {
const durationFormat = args.context.pluginValue('prototypes.typingsFormat.duration');
switch (durationFormat) {
case 'string':
return toJSON.durationString(args);
case 'duration':
default:
return toJSON.type(args);
}
},
durationString(args) {
return toJSON.identity(args);
},
timestamp(args) {
const timestampFormat = args.context.pluginValue('prototypes.typingsFormat.timestamp');
switch (timestampFormat) {
case 'timestamp':
return toJSON.timestampTimestamp(args);
case 'date':
default:
return toJSON.timestampDate(args);
}
},
// message.periodReset !== undefined && (obj.periodReset = fromTimestamp(message.periodReset).toISOString());
timestampTimestamp(args) {
args.context.addUtil('fromTimestamp');
const { messageProp, objProp } = getPropNames(args.field);
return notUndefinedSetValue(messageProp, objProp, t.callExpression(t.memberExpression(t.callExpression(t.identifier('fromTimestamp'), [
t.memberExpression(t.identifier('message'), t.identifier(messageProp))
]), t.identifier('toISOString')), []));
},
// message.periodReset !== undefined && (obj.periodReset = message.periodReset.toISOString());
timestampDate(args) {
const { messageProp, objProp } = getPropNames(args.field);
return notUndefinedSetValue(messageProp, objProp, t.callExpression(t.memberExpression(t.memberExpression(t.identifier('message'), t.identifier(messageProp)), t.identifier('toISOString')), []));
},
// obj.labels = {};
// if (message.labels) {
// Object.entries(message.labels).forEach(([k, v]) => {
// obj.labels[k] = v;
// });
// }
// obj.typeMap = {};
// if (message.typeMap) {
// Object.entries(message.typeMap).forEach(([k, v]) => {
// obj.typeMap[k] = Type.toJSON(v);
// });
// }
keyHash(args) {
const { messageProp, objProp } = getPropNames(args.field);
const keyType = args.field.keyType;
const valueType = args.field.parsedType.name;
let toJSON = null;
switch (valueType) {
case 'string':
toJSON = t.identifier('v');
break;
case 'uint32':
case 'int32':
toJSON = t.callExpression(t.memberExpression(t.identifier('Math'), t.identifier('round')), [
t.identifier('v')
]);
break;
case 'int64':
case 'uint64':
toJSON = t.callExpression(t.memberExpression(t.identifier('v'), t.identifier('toString')), []);
break;
default:
toJSON = t.callExpression(t.memberExpression(t.identifier(valueType), t.identifier('toJSON')), [
t.identifier('v')
]);
}
return [
t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.identifier('obj'), t.identifier(objProp)), t.objectExpression([]))),
//
t.ifStatement(t.memberExpression(t.identifier('message'), t.identifier(messageProp)), t.blockStatement([
t.expressionStatement(t.callExpression(t.memberExpression(t.callExpression(t.memberExpression(t.identifier('Object'), t.identifier('entries')), [
t.memberExpression(t.identifier('message'), t.identifier(messageProp))
]), t.identifier('forEach')), [
t.arrowFunctionExpression([
t.arrayPattern([
t.identifier('k'),
t.identifier('v')
])
], t.blockStatement([
t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.memberExpression(t.identifier('obj'), t.identifier(objProp)), t.identifier('k'), true), toJSON))
]))
]))
]))
];
},
// if (message.codeIds) {
// obj.codeIds = message.codeIds.map(e => (e || Long.UZERO).toString());
// } else {
// obj.codeIds = [];
// }
array(args, expr) {
const { messageProp, objProp } = getPropNames(args.field);
return t.ifStatement(t.memberExpression(t.identifier('message'), t.identifier(messageProp)), t.blockStatement([
t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.identifier('obj'), t.identifier(objProp)), t.callExpression(t.memberExpression(t.memberExpression(t.identifier('message'), t.identifier(messageProp)), t.identifier('map')), [
t.arrowFunctionExpression([
t.identifier('e')
], expr)
])))
]), t.blockStatement([
t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.identifier('obj'), t.identifier(objProp)), t.arrayExpression([])))
]));
}
};
export const arrayTypes = {
identity() {
return t.identifier('e');
},
// if (message.overloadId) {
// obj.overloadId = message.overloadId.map(e => e);
// } else {
// obj.overloadId = [];
// }
string() {
return arrayTypes.identity();
},
double() {
return arrayTypes.identity();
},
float() {
return arrayTypes.identity();
},
bool() {
return arrayTypes.identity();
},
// if (message.lineOffsets) {
// obj.lineOffsets = message.lineOffsets.map(e => Math.round(e));
// } else {
// obj.lineOffsets = [];
// }
number() {
return t.callExpression(t.memberExpression(t.identifier('Math'), t.identifier('round')), [
t.identifier('e')
]);
},
int32() {
return arrayTypes.number();
},
uint32() {
return arrayTypes.number();
},
sint32() {
return arrayTypes.number();
},
fixed32() {
return arrayTypes.number();
},
sfixed32() {
return arrayTypes.number();
},
// if (message.codeIds) {
// obj.codeIds = message.codeIds.map(e => (e || Long.UZERO).toString());
// } else {
// obj.codeIds = [];
// }
long(args) {
return t.callExpression(t.memberExpression(t.logicalExpression('||', t.identifier('e'), getDefaultTSTypeFromProtoType(args.context, {
...args.field,
rule: undefined, // so it's treated as type not an array...
}, args.isOneOf)), t.identifier('toString')), []);
},
int64(args) {
return arrayTypes.long(args);
},
uint64(args) {
return arrayTypes.long(args);
},
sint64(args) {
return arrayTypes.long(args);
},
fixed64(args) {
return arrayTypes.long(args);
},
sfixed64(args) {
return arrayTypes.long(args);
},
// if (message.myBytesArray) {
// obj.myBytesArray = message.myBytesArray.map(e => base64FromBytes(e !== undefined ? e : new Uint8Array()));
// } else {
// obj.myBytesArray = [];
// }
bytes(args) {
args.context.addUtil('base64FromBytes');
return t.callExpression(t.identifier('base64FromBytes'), [
t.conditionalExpression(t.binaryExpression('!==', t.identifier('e'), t.identifier('undefined')), t.identifier('e'), getDefaultTSTypeFromProtoType(args.context, {
...args.field,
rule: undefined, // so it's treated as type not an array...
}, args.isOneOf))
]);
},
enum(args) {
const enumFuncName = args.context.getToEnum(args.field);
return t.callExpression(t.identifier(enumFuncName), [
t.identifier('e')
]);
},
// if (message.tokenInMaxs) {
// obj.tokenInMaxs = message.tokenInMaxs.map(e => e ? Coin.toJSON(e) : undefined);
// } else {
// obj.tokenInMaxs = [];
// }
type(args) {
let name = args.context.getTypeName(args.field);
if (!args.context.options.aminoEncoding.useLegacyInlineEncoding &&
args.context.options.interfaces.enabled &&
args.context.options.interfaces?.useGlobalDecoderRegistry &&
args.field.type === 'google.protobuf.Any' &&
args.field.options['(cosmos_proto.accepts_interface)']) {
name = 'GlobalDecoderRegistry';
}
return t.conditionalExpression(t.identifier('e'), t.callExpression(t.memberExpression(t.identifier(name), t.identifier('toJSON')), [
t.identifier('e')
]), t.identifier('undefined'));
}
};