@cosmology/ast
Version:
Cosmos TypeScript AST generation
244 lines (219 loc) • 6.53 kB
text/typescript
import * as t from "@babel/types";
import { ProtoField } from "@cosmology/types";
import { ProtoParseContext } from "../encoding";
const BILLION = t.numericLiteral(1_000_000_000);
BILLION.extra = { raw: "1_000_000_000", rawValue: 1000000000 };
export { BILLION };
export const cleanComment = (str) => {
return str.replace(/\*\//g, "*\\/");
};
const ensureOneSpace = (str) => {
if (/^[\s\n\t]+/.test(str)) return str;
return ` ${str}`;
};
export const makeCommentBlock = (comment: string): t.CommentBlock => {
if (!/[\n]+/.test(comment)) {
return {
type: "CommentBlock",
value: `* ${cleanComment(comment)} `,
start: null,
end: null,
loc: null,
};
}
let lines = comment.split("\n");
lines = ["*", ...lines, " "];
const comments = lines.map((line, i) => {
if (i == 0) return line;
if (i == 1) return ` *${ensureOneSpace(cleanComment(line))}`;
if (i == lines.length - 1) return cleanComment(line);
return ` *${ensureOneSpace(cleanComment(line))}`;
});
return {
type: "CommentBlock",
value: comments.join("\n"),
start: null,
end: null,
loc: null,
};
};
export const renderNameSafely = (name) => {
return name
.split("_")
.map((str) => {
const parts = str.split(".");
str = parts[parts.length - 1];
return str;
})
.join("_");
};
export const getProtoFieldTypeName = (
context: ProtoParseContext,
field: ProtoField
) => {
let name = context.getTypeName(field);
return renderNameSafely(name);
};
export const recursiveNamespace = (names, moduleBlockBody) => {
if (!names || !names.length) return moduleBlockBody;
const name = names.pop();
const body = [
t.exportNamedDeclaration(
t.tsModuleDeclaration(
t.identifier(name),
t.tsModuleBlock(recursiveNamespace(names, moduleBlockBody))
)
),
];
return body;
};
export const bindMethod = (name: string) => {
return t.expressionStatement(
t.assignmentExpression(
"=",
t.memberExpression(t.thisExpression(), t.identifier(name)),
t.callExpression(
t.memberExpression(
t.memberExpression(t.thisExpression(), t.identifier(name)),
t.identifier("bind")
),
[t.thisExpression()]
)
)
);
};
export const shorthandProperty = (prop: string) => {
return t.objectProperty(
t.identifier(prop),
t.identifier(prop),
false,
true
);
};
export const importStmt = (names: string[], path: string) => {
return t.importDeclaration(
names.map((name) =>
t.importSpecifier(t.identifier(name), t.identifier(name))
),
t.stringLiteral(path)
);
};
export const memberExpressionOrIdentifier = (names) => {
if (names.length === 1) {
return t.identifier(names[0]);
}
if (names.length === 2) {
const [b, a] = names;
return t.memberExpression(t.identifier(a), t.identifier(b));
}
const [name, ...rest] = names;
return t.memberExpression(
memberExpressionOrIdentifier(rest),
t.identifier(name)
);
};
export const memberExpressionOrIdentifierAminoCasing = (
names,
aminoCasingFn: Function
) => {
if (names.length === 1) {
return t.identifier(aminoCasingFn(names[0]));
}
if (names.length === 2) {
const [b, a] = names;
return t.memberExpression(
t.identifier(aminoCasingFn(a)),
t.identifier(aminoCasingFn(b))
);
}
const [name, ...rest] = names;
return t.memberExpression(
memberExpressionOrIdentifierAminoCasing(rest, aminoCasingFn),
t.identifier(aminoCasingFn(name))
);
};
export const memberExpressionOrIdentifierAminoCaseField = (
fields: ProtoField[],
aminoCaseFunc: Function,
useNullHandling: boolean = false
) => {
if (fields.length === 1) {
return t.identifier(aminoCaseFunc(fields[0]));
}
if (fields.length === 2) {
const [b, a] = fields;
return useNullHandling
? t.memberExpression(
t.identifier(aminoCaseFunc(a)),
t.identifier(aminoCaseFunc(b)),
false,
true
)
: t.memberExpression(
t.identifier(aminoCaseFunc(a)),
t.identifier(aminoCaseFunc(b))
);
}
const [field, ...rest] = fields;
return useNullHandling
? t.memberExpression(
memberExpressionOrIdentifierAminoCaseField(
rest,
aminoCaseFunc,
useNullHandling
),
t.identifier(aminoCaseFunc(field)),
false,
true
)
: t.memberExpression(
memberExpressionOrIdentifierAminoCaseField(
rest,
aminoCaseFunc,
useNullHandling
),
t.identifier(aminoCaseFunc(field))
);
};
export const promiseTypeAnnotation = (name) => {
return t.tsTypeAnnotation(
t.tsTypeReference(
t.identifier("Promise"),
t.tsTypeParameterInstantiation([
t.tsTypeReference(t.identifier(name)),
])
)
);
};
export const getAcceptedInterfacesTypes = (
context: ProtoParseContext,
lookupInterface: string
) => {
return lookupInterface
? context.store._symbols.filter(
(s) =>
s.implementsType === lookupInterface &&
s.ref === context.ref.filename
)
: [];
};
export const getSdkFieldName = (fieldName: string, field: ProtoField) => {
return field.options?.["(telescope:orig)"] ?? fieldName;
};
export const getAminoFieldName = (
fieldName: string,
field: ProtoField,
interfaceName: string,
context: ProtoParseContext
) => {
const orig = field.options?.["(telescope:orig)"] ?? fieldName;
if (
interfaceName === "Any" &&
context.ref.proto.package === "google.protobuf" &&
(orig === "type_url" || orig === "typeUrl")
) {
// type_url => type for amino
return "type";
}
return orig;
};