@cosmology/ast
Version:
Cosmos TypeScript AST generation
184 lines (183 loc) • 6.14 kB
JavaScript
import { isRefExcluded, getObjectName } from '@cosmology/utils';
import { getEnumFromJsonName, getEnumToJsonName, getFieldsTypeName } from './proto';
import { getPluginValue } from '../plugins';
export class GenericParseContext {
options;
imports = [];
derivedImports = [];
utils = {};
store;
ref;
constructor(ref, store, options) {
this.ref = ref;
this.store = store;
this.options = options;
if (!this.options) {
throw new Error('ParseContext requires options!');
}
}
pluginValue(name) {
return getPluginValue(name, this.ref?.proto?.package, this.options);
}
isExcluded() {
const excluded = this.pluginValue('prototypes.excluded');
return isRefExcluded(this.ref, excluded);
}
addUtil(util) {
this.utils[util] = true;
}
addImport(imp) {
// some local lookups don't have an import (local proto-style lookups do)
if (!imp.import)
return;
this.imports.push(imp);
}
addImportDerivative(imp) {
const found = this.derivedImports.find(a => {
return a.type === imp.type &&
a.symbol.symbolName === imp.symbol.symbolName &&
a.symbol.source === imp.symbol.source;
});
if (!found) {
this.derivedImports.push(imp);
}
}
getTypeNameFromFieldName(name, importSrc) {
let importedAs = name;
const names = this.ref.traversed?.importNames;
if (names
&& names.hasOwnProperty(importSrc)
&& names[importSrc].hasOwnProperty(name)) {
importedAs = names[importSrc][name];
}
this.addImport({
type: 'typeImport',
name,
importedAs,
import: importSrc
});
return importedAs;
}
getTypeName(field) {
let name = getFieldsTypeName(field);
return this.getTypeNameFromFieldName(name, field.import);
}
lookupTypeFromCurrentPath(field, currentProtoPath) {
const ref = this.store.findProto(currentProtoPath);
let lookup = this.store.get(ref, field.parsedType.name);
if (!lookup) {
// if we can't find it, use field import
if (field.import) {
const importRef = this.store.findProto(field.import);
if (!importRef) {
throw new Error(`bad import ${field.import}`);
}
lookup = this.store.get(importRef, field.parsedType.name);
}
if (!lookup) {
throw new Error('Undefined Symbol: ' + field.parsedType.name);
}
}
return lookup;
}
getTypeFromCurrentPath(field, currentProtoPath) {
const ref = this.store.findProto(currentProtoPath);
let lookup = this.store.get(ref, field.parsedType.name);
if (!lookup) {
// if we can't find it, use field import
if (field.import) {
const importRef = this.store.findProto(field.import);
if (!importRef) {
throw new Error(`bad import ${field.import}`);
}
lookup = this.store.get(importRef, field.parsedType.name);
}
if (!lookup) {
throw new Error('Undefined Symbol: ' + field.parsedType.name);
}
}
this.addImport({
type: 'typeImport',
name: lookup.importedName,
import: lookup.import
});
return lookup.obj;
}
}
export class AminoParseContext extends GenericParseContext {
aminoCasingFn;
constructor(ref, store, options) {
super(ref, store, options);
this.ref = ref;
this.store = store;
this.options = options;
this.setAminoCasingFn();
if (!this.aminoCasingFn) {
throw new Error('missing aminoCasingFn!');
}
this.aminoCaseField = this.aminoCaseField.bind(this);
}
setAminoCasingFn() {
if (this.aminoCasingFn)
return this.aminoCasingFn;
this.aminoCasingFn = this.pluginValue('aminoEncoding.casingFn');
return this.aminoCasingFn;
}
aminoCaseField(field) {
return field.options['(telescope:orig)'];
}
lookupEnumFromJson(field, currentProtoPath) {
const lookup = this.lookupTypeFromCurrentPath(field, currentProtoPath);
const Enum = lookup.obj;
const name = getEnumFromJsonName(getObjectName(Enum.name, Enum.scope));
this.addImport({
type: 'fromJSONEnum',
name,
import: lookup.import
});
return name;
}
lookupEnumToJson(field, currentProtoPath) {
const lookup = this.lookupTypeFromCurrentPath(field, currentProtoPath);
const Enum = lookup.obj;
const name = getEnumToJsonName(getObjectName(Enum.name, Enum.scope));
this.addImport({
type: 'toJSONEnum',
name,
import: lookup.import
});
return name;
}
}
export class ProtoParseContext extends GenericParseContext {
constructor(ref, store, options) {
super(ref, store, options);
this.ref = ref;
this.store = store;
this.options = options;
}
setEnumValues(pkg, name, protoSyntex, values) {
this.store.setEnumValues(pkg, name, protoSyntex, values);
}
getDefaultOrExistingSmallestEnumValue(pkg, name) {
return this.store.getDefaultOrExistingSmallestEnumValue(pkg, name);
}
getToEnum(field) {
const name = getEnumToJsonName(getFieldsTypeName(field));
this.addImport({
type: 'toJSONEnum',
name,
import: field.import
});
return name;
}
getFromEnum(field) {
const fromJSONFuncName = getEnumFromJsonName(getFieldsTypeName(field));
this.addImport({
type: 'fromJSONEnum',
name: fromJSONFuncName,
import: field.import
});
return fromJSONFuncName;
}
}