@cosmology/ast
Version:
Cosmos TypeScript AST generation
305 lines (304 loc) • 12.6 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isMethod = exports.createFieldTypeComparison = exports.createArrayTypeComparison = exports.createProtoTypeComparison = exports.createFieldExistingTest = exports.createScalarTypeComparison = exports.createInstanceOfTypeComparisonGroup = exports.createInstanceOfTypeComparison = void 0;
const t = __importStar(require("@babel/types"));
const utils_1 = require("../../../utils");
const types_1 = require("../types");
const types_2 = require("../../types");
const utils_2 = require("@cosmology/utils");
const INPUT_PARAM = "o";
const createInstanceOfTypeComparison = (args) => {
const { fieldName, type } = args;
return t.binaryExpression("instanceof", fieldName, t.identifier(type));
};
exports.createInstanceOfTypeComparison = createInstanceOfTypeComparison;
const createInstanceOfTypeComparisonGroup = (args) => {
const { context, fieldName, field, types } = args;
switch (types.length) {
case 0:
throw new Error("types shouldn't be empty.");
case 1:
return (0, exports.createInstanceOfTypeComparison)({
context,
fieldName,
field,
type: types[0],
});
default:
const current = types.shift();
return t.logicalExpression("||", (0, exports.createInstanceOfTypeComparison)({
context,
fieldName,
field,
type: current,
}), (0, exports.createInstanceOfTypeComparisonGroup)({
context,
fieldName,
field,
types,
}));
}
};
exports.createInstanceOfTypeComparisonGroup = createInstanceOfTypeComparisonGroup;
const createScalarTypeComparison = (args) => {
const { fieldName, type } = args;
return t.binaryExpression("===", t.unaryExpression("typeof", fieldName), t.stringLiteral(type));
};
exports.createScalarTypeComparison = createScalarTypeComparison;
const createFieldExistingTest = (args) => {
const { fieldName } = args;
args.context.addUtil("isSet");
return t.callExpression(t.identifier("isSet"), [fieldName]);
};
exports.createFieldExistingTest = createFieldExistingTest;
const createProtoTypeComparison = (args) => {
const { context, fieldName, field, methodName } = args;
switch (field.type) {
case "google.protobuf.Duration":
case "Duration":
const durationFormat = args.context.pluginValue("prototypes.typingsFormat.duration");
if (durationFormat === "string") {
return (0, exports.createScalarTypeComparison)({
context,
fieldName,
field,
type: "string",
});
}
case "google.protobuf.Timestamp":
case "Timestamp":
const timestampFormat = args.context.pluginValue("prototypes.typingsFormat.timestamp");
if (timestampFormat === "date") {
(0, exports.createInstanceOfTypeComparison)({
context,
fieldName,
field,
type: "Date",
});
}
case "Any":
case "google.protobuf.Any":
const lookupInterface = field.options?.["(cosmos_proto.accepts_interface)"];
const acceptedTypes = (0, utils_1.getAcceptedInterfacesTypes)(context, lookupInterface);
const acceptedTypeNames = acceptedTypes.map((acceptedType) => acceptedType.readAs);
const typeName = context.getTypeName(field);
acceptedTypeNames.push(typeName);
return acceptedTypeNames.reduce((comparison, acceptedTypeName) => {
const current = t.callExpression(t.memberExpression(t.identifier(acceptedTypeName), t.identifier(methodName)), [fieldName]);
return comparison
? t.logicalExpression("||", comparison, current)
: current;
}, undefined);
}
const typeName = context.getTypeName(field);
return t.callExpression(t.memberExpression(t.identifier(typeName), t.identifier(methodName)), [fieldName]);
};
exports.createProtoTypeComparison = createProtoTypeComparison;
const createArrayTypeComparison = (args) => {
const { fieldName, typeComparison } = args;
const isArrayExp = t.callExpression(t.memberExpression(t.identifier("Array"), t.identifier("isArray")), [t.memberExpression(t.identifier(INPUT_PARAM), t.identifier(fieldName))]);
return typeComparison
? t.logicalExpression("&&", isArrayExp, t.logicalExpression("||", t.unaryExpression("!", t.memberExpression(t.memberExpression(t.identifier(INPUT_PARAM), t.identifier(fieldName)), t.identifier("length"))), typeComparison))
: isArrayExp;
};
exports.createArrayTypeComparison = createArrayTypeComparison;
function getScalarExpression(args) {
//TODO:: Date, timestamp, etc
const { context, field, fieldName } = args;
switch (field.type) {
case "string":
return (0, exports.createScalarTypeComparison)({
context,
field,
fieldName,
type: "string",
});
case "bool":
return (0, exports.createScalarTypeComparison)({
context,
field,
fieldName,
type: "boolean",
});
case "float":
case "double":
case "int32":
case "sint32":
case "uint32":
case "fixed32":
case "sfixed32":
return (0, exports.createScalarTypeComparison)({
context,
field,
fieldName,
type: "number",
});
case "bytes":
return t.logicalExpression("||", (0, exports.createInstanceOfTypeComparison)({
context,
field,
fieldName,
type: "Uint8Array",
}), (0, exports.createScalarTypeComparison)({
context,
field,
fieldName,
type: "string",
}));
case "int64":
case "sint64":
case "uint64":
case "fixed64":
case "sfixed64":
return (0, exports.createScalarTypeComparison)({
context,
field,
fieldName,
type: "bigint",
});
}
return undefined;
}
const createFieldTypeComparison = (args) => {
const { context, field, fieldName, methodName } = args;
if (field.keyType) {
return (0, exports.createFieldExistingTest)({
context,
fieldName: t.memberExpression(t.identifier(INPUT_PARAM), t.identifier(fieldName)),
field,
});
}
switch (field.parsedType.type) {
case "Enum":
if (field.rule === "repeated") {
return (0, exports.createArrayTypeComparison)({
context,
field,
fieldName,
});
}
else {
return (0, exports.createFieldExistingTest)({
context,
fieldName: t.memberExpression(t.identifier(INPUT_PARAM), t.identifier(fieldName)),
field,
});
}
case "Type":
if (field.rule === "repeated") {
return (0, exports.createArrayTypeComparison)({
context,
field,
fieldName,
typeComparison: (0, exports.createProtoTypeComparison)({
context,
methodName,
field,
fieldName: t.memberExpression(t.memberExpression(t.identifier(INPUT_PARAM), t.identifier(fieldName)), t.numericLiteral(0), true),
}),
});
}
else {
return (0, exports.createProtoTypeComparison)({
context,
methodName,
fieldName: t.memberExpression(t.identifier(INPUT_PARAM), t.identifier(fieldName)),
field,
});
}
}
if (field.rule === "repeated") {
return (0, exports.createArrayTypeComparison)({
context,
field,
fieldName,
typeComparison: getScalarExpression({
context,
field,
fieldName: t.memberExpression(t.memberExpression(t.identifier(INPUT_PARAM), t.identifier(fieldName)), t.numericLiteral(0), true),
}),
});
}
const expr = getScalarExpression({
context,
field,
fieldName: t.memberExpression(t.identifier(INPUT_PARAM), t.identifier(fieldName)),
});
if (expr) {
return expr;
}
throw new Error(`need to implement is (${field.type} rules[${field.rule}] name[${fieldName}])`);
};
exports.createFieldTypeComparison = createFieldTypeComparison;
const isMethod = (args) => {
const { context, name, proto, getFieldName } = args;
const methodName = args.methodName ?? "is";
const typeName = getTypeName(name, methodName);
const typeUrl = (0, utils_2.getTypeUrl)(context.ref.proto, proto);
if (!typeUrl)
return;
const returnType = t.tsTypeAnnotation(t.tsTypePredicate(t.identifier(INPUT_PARAM), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(typeName)))));
const fieldTypesComparison = Object.keys(proto.fields ?? {}).reduce((comparison, fieldName) => {
const field = proto.fields[fieldName];
const oneOfs = (0, types_1.getOneOfs)(proto);
const isOneOf = oneOfs.includes(fieldName);
const isOptional = (0, types_1.getFieldOptionalityForDefaults)(context, field, isOneOf);
if (isOptional) {
return comparison;
}
const fieldNameWithCase = getFieldName
? getFieldName(fieldName, field, name, context)
: fieldName;
const current = (0, exports.createFieldTypeComparison)({
context,
methodName,
field,
fieldName: fieldNameWithCase,
});
return comparison
? t.logicalExpression("&&", comparison, current)
: current;
}, undefined);
const typeUrlExpr = t.binaryExpression("===", t.memberExpression(t.identifier(INPUT_PARAM), t.identifier("$typeUrl")), t.memberExpression(t.identifier(name), t.identifier("typeUrl")));
const method = (0, utils_1.objectMethod)("method", t.identifier(methodName), [(0, utils_1.identifier)(INPUT_PARAM, t.tsTypeAnnotation(t.tsAnyKeyword()), false)], t.blockStatement([
t.returnStatement(t.logicalExpression("&&", t.identifier(INPUT_PARAM), fieldTypesComparison
? t.logicalExpression("||", typeUrlExpr, fieldTypesComparison)
: typeUrlExpr)),
]), false, false, false, returnType);
return method;
};
exports.isMethod = isMethod;
function getTypeName(typeName, methodName) {
switch (methodName) {
case "isSDK":
return types_2.SymbolNames.SDKType(typeName);
case "isAmino":
return types_2.SymbolNames.Amino(typeName);
case "is":
default:
return typeName;
}
}
;