aboutsummaryrefslogtreecommitdiffstats
path: root/packages/react-docs/src/utils
diff options
context:
space:
mode:
Diffstat (limited to 'packages/react-docs/src/utils')
-rw-r--r--packages/react-docs/src/utils/constants.ts9
-rw-r--r--packages/react-docs/src/utils/doxity_utils.ts175
-rw-r--r--packages/react-docs/src/utils/typedoc_utils.ts370
-rw-r--r--packages/react-docs/src/utils/utils.ts5
4 files changed, 559 insertions, 0 deletions
diff --git a/packages/react-docs/src/utils/constants.ts b/packages/react-docs/src/utils/constants.ts
new file mode 100644
index 000000000..c3c74fd11
--- /dev/null
+++ b/packages/react-docs/src/utils/constants.ts
@@ -0,0 +1,9 @@
+import { SupportedDocJson } from '../types';
+
+export const constants = {
+ TYPES_SECTION_NAME: 'types',
+ TYPE_TO_SYNTAX: {
+ [SupportedDocJson.Doxity]: 'solidity',
+ [SupportedDocJson.TypeDoc]: 'typescript',
+ } as { [supportedDocType: string]: string },
+};
diff --git a/packages/react-docs/src/utils/doxity_utils.ts b/packages/react-docs/src/utils/doxity_utils.ts
new file mode 100644
index 000000000..26dea6966
--- /dev/null
+++ b/packages/react-docs/src/utils/doxity_utils.ts
@@ -0,0 +1,175 @@
+import * as _ from 'lodash';
+
+import {
+ AbiTypes,
+ DocAgnosticFormat,
+ DocSection,
+ DoxityAbiDoc,
+ DoxityContractObj,
+ DoxityDocObj,
+ DoxityInput,
+ EventArg,
+ Parameter,
+ Property,
+ SolidityMethod,
+ Type,
+ TypeDocTypes,
+} from '../types';
+
+export const doxityUtils = {
+ convertToDocAgnosticFormat(doxityDocObj: DoxityDocObj): DocAgnosticFormat {
+ const docAgnosticFormat: DocAgnosticFormat = {};
+ _.each(doxityDocObj, (doxityContractObj: DoxityContractObj, contractName: string) => {
+ const doxityConstructor = _.find(doxityContractObj.abiDocs, (abiDoc: DoxityAbiDoc) => {
+ return abiDoc.type === AbiTypes.Constructor;
+ });
+ const constructors = [];
+ if (!_.isUndefined(doxityConstructor)) {
+ const constructor = {
+ isConstructor: true,
+ name: doxityContractObj.name,
+ comment: doxityConstructor.details,
+ returnComment: doxityConstructor.return,
+ callPath: '',
+ parameters: this._convertParameters(doxityConstructor.inputs),
+ returnType: this._convertType(doxityContractObj.name),
+ };
+ constructors.push(constructor);
+ }
+
+ const doxityMethods: DoxityAbiDoc[] = _.filter<DoxityAbiDoc>(
+ doxityContractObj.abiDocs,
+ (abiDoc: DoxityAbiDoc) => {
+ return this._isMethod(abiDoc);
+ },
+ );
+ const methods: SolidityMethod[] = _.map<DoxityAbiDoc, SolidityMethod>(
+ doxityMethods,
+ (doxityMethod: DoxityAbiDoc) => {
+ const outputs = !_.isUndefined(doxityMethod.outputs) ? doxityMethod.outputs : [];
+ let returnTypeIfExists: Type;
+ if (outputs.length === 0) {
+ // no-op. It's already undefined
+ } else if (outputs.length === 1) {
+ const outputsType = outputs[0].type;
+ returnTypeIfExists = this._convertType(outputsType);
+ } else {
+ const outputsType = `[${_.map(outputs, output => output.type).join(', ')}]`;
+ returnTypeIfExists = this._convertType(outputsType);
+ }
+ // For ZRXToken, we want to convert it to zrxToken, rather then simply zRXToken
+ const callPath =
+ contractName !== 'ZRXToken'
+ ? `${contractName[0].toLowerCase()}${contractName.slice(1)}.`
+ : `${contractName.slice(0, 3).toLowerCase()}${contractName.slice(3)}.`;
+ const method = {
+ isConstructor: false,
+ isConstant: doxityMethod.constant,
+ isPayable: doxityMethod.payable,
+ name: doxityMethod.name,
+ comment: doxityMethod.details,
+ returnComment: doxityMethod.return,
+ callPath,
+ parameters: this._convertParameters(doxityMethod.inputs),
+ returnType: returnTypeIfExists,
+ };
+ return method;
+ },
+ );
+
+ const doxityProperties: DoxityAbiDoc[] = _.filter<DoxityAbiDoc>(
+ doxityContractObj.abiDocs,
+ (abiDoc: DoxityAbiDoc) => {
+ return this._isProperty(abiDoc);
+ },
+ );
+ const properties = _.map<DoxityAbiDoc, Property>(doxityProperties, (doxityProperty: DoxityAbiDoc) => {
+ // We assume that none of our functions return more then a single return value
+ let typeName = doxityProperty.outputs[0].type;
+ if (!_.isEmpty(doxityProperty.inputs)) {
+ // Properties never have more then a single input
+ typeName = `(${doxityProperty.inputs[0].type} => ${typeName})`;
+ }
+ const property = {
+ name: doxityProperty.name,
+ type: this._convertType(typeName),
+ comment: doxityProperty.details,
+ };
+ return property;
+ });
+
+ const doxityEvents = _.filter(
+ doxityContractObj.abiDocs,
+ (abiDoc: DoxityAbiDoc) => abiDoc.type === AbiTypes.Event,
+ );
+ const events = _.map(doxityEvents, doxityEvent => {
+ const event = {
+ name: doxityEvent.name,
+ eventArgs: this._convertEventArgs(doxityEvent.inputs),
+ };
+ return event;
+ });
+
+ const docSection: DocSection = {
+ comment: doxityContractObj.title,
+ constructors,
+ methods,
+ properties,
+ types: [],
+ events,
+ };
+ docAgnosticFormat[contractName] = docSection;
+ });
+ return docAgnosticFormat;
+ },
+ _convertParameters(inputs: DoxityInput[]): Parameter[] {
+ const parameters = _.map(inputs, input => {
+ const parameter = {
+ name: input.name,
+ comment: input.description,
+ isOptional: false,
+ type: this._convertType(input.type),
+ };
+ return parameter;
+ });
+ return parameters;
+ },
+ _convertType(typeName: string): Type {
+ const type = {
+ name: typeName,
+ typeDocType: TypeDocTypes.Intrinsic,
+ };
+ return type;
+ },
+ _isMethod(abiDoc: DoxityAbiDoc) {
+ if (abiDoc.type !== AbiTypes.Function) {
+ return false;
+ }
+ const hasInputs = !_.isEmpty(abiDoc.inputs);
+ const hasNamedOutputIfExists = !hasInputs || !_.isEmpty(abiDoc.inputs[0].name);
+ const isNameAllCaps = abiDoc.name === abiDoc.name.toUpperCase();
+ const isMethod = hasNamedOutputIfExists && !isNameAllCaps;
+ return isMethod;
+ },
+ _isProperty(abiDoc: DoxityAbiDoc) {
+ if (abiDoc.type !== AbiTypes.Function) {
+ return false;
+ }
+ const hasInputs = !_.isEmpty(abiDoc.inputs);
+ const hasNamedOutputIfExists = !hasInputs || !_.isEmpty(abiDoc.inputs[0].name);
+ const isNameAllCaps = abiDoc.name === abiDoc.name.toUpperCase();
+ const isProperty = !hasNamedOutputIfExists || isNameAllCaps;
+ return isProperty;
+ },
+ _convertEventArgs(inputs: DoxityInput[]): EventArg[] {
+ const eventArgs = _.map(inputs, input => {
+ const eventArg = {
+ isIndexed: input.indexed,
+ name: input.name,
+ type: this._convertType(input.type),
+ };
+ return eventArg;
+ });
+ return eventArgs;
+ },
+};
diff --git a/packages/react-docs/src/utils/typedoc_utils.ts b/packages/react-docs/src/utils/typedoc_utils.ts
new file mode 100644
index 000000000..e4cea1e40
--- /dev/null
+++ b/packages/react-docs/src/utils/typedoc_utils.ts
@@ -0,0 +1,370 @@
+import * as _ from 'lodash';
+
+import { DocsInfo } from '../docs_info';
+import {
+ CustomType,
+ CustomTypeChild,
+ DocAgnosticFormat,
+ DocSection,
+ IndexSignature,
+ KindString,
+ Parameter,
+ Property,
+ SectionsMap,
+ Type,
+ TypeDocNode,
+ TypeDocType,
+ TypeParameter,
+ TypescriptMethod,
+} from '../types';
+import { utils } from '../utils/utils';
+
+export const typeDocUtils = {
+ isType(entity: TypeDocNode): boolean {
+ return (
+ entity.kindString === KindString.Interface ||
+ entity.kindString === KindString.Function ||
+ entity.kindString === KindString.TypeAlias ||
+ entity.kindString === KindString.Variable ||
+ entity.kindString === KindString.Enumeration
+ );
+ },
+ isMethod(entity: TypeDocNode): boolean {
+ return entity.kindString === KindString.Method;
+ },
+ isConstructor(entity: TypeDocNode): boolean {
+ return entity.kindString === KindString.Constructor;
+ },
+ isProperty(entity: TypeDocNode): boolean {
+ return entity.kindString === KindString.Property;
+ },
+ isPrivateOrProtectedProperty(propertyName: string): boolean {
+ return _.startsWith(propertyName, '_');
+ },
+ getModuleDefinitionsBySectionName(versionDocObj: TypeDocNode, configModulePaths: string[]): TypeDocNode[] {
+ const moduleDefinitions: TypeDocNode[] = [];
+ const jsonModules = versionDocObj.children;
+ _.each(jsonModules, jsonMod => {
+ _.each(configModulePaths, configModulePath => {
+ if (_.includes(configModulePath, jsonMod.name)) {
+ moduleDefinitions.push(jsonMod);
+ }
+ });
+ });
+ return moduleDefinitions;
+ },
+ convertToDocAgnosticFormat(typeDocJson: TypeDocNode, docsInfo: DocsInfo): DocAgnosticFormat {
+ const subMenus = _.values(docsInfo.getMenu());
+ const orderedSectionNames = _.flatten(subMenus);
+ const docAgnosticFormat: DocAgnosticFormat = {};
+ _.each(orderedSectionNames, sectionName => {
+ const modulePathsIfExists = docsInfo.getModulePathsIfExists(sectionName);
+ if (_.isUndefined(modulePathsIfExists)) {
+ return; // no-op
+ }
+ const packageDefinitions = typeDocUtils.getModuleDefinitionsBySectionName(typeDocJson, modulePathsIfExists);
+ let packageDefinitionWithMergedChildren;
+ if (_.isEmpty(packageDefinitions)) {
+ return; // no-op
+ } else if (packageDefinitions.length === 1) {
+ packageDefinitionWithMergedChildren = packageDefinitions[0];
+ } else {
+ // HACK: For now, if there are two modules to display in a single section,
+ // we simply concat the children. This works for our limited use-case where
+ // we want to display types stored in two files under a single section
+ packageDefinitionWithMergedChildren = packageDefinitions[0];
+ for (let i = 1; i < packageDefinitions.length; i++) {
+ packageDefinitionWithMergedChildren.children = [
+ ...packageDefinitionWithMergedChildren.children,
+ ...packageDefinitions[i].children,
+ ];
+ }
+ }
+
+ // Since the `types.ts` file is the only file that does not export a module/class but
+ // instead has each type export itself, we do not need to go down two levels of nesting
+ // for it.
+ let entities;
+ let packageComment = '';
+ if (sectionName === docsInfo.sections.types) {
+ entities = packageDefinitionWithMergedChildren.children;
+ } else {
+ entities = packageDefinitionWithMergedChildren.children[0].children;
+ const commentObj = packageDefinitionWithMergedChildren.children[0].comment;
+ packageComment = !_.isUndefined(commentObj) ? commentObj.shortText : packageComment;
+ }
+
+ const docSection = typeDocUtils._convertEntitiesToDocSection(entities, docsInfo, sectionName);
+ docSection.comment = packageComment;
+ docAgnosticFormat[sectionName] = docSection;
+ });
+ return docAgnosticFormat;
+ },
+ _convertEntitiesToDocSection(entities: TypeDocNode[], docsInfo: DocsInfo, sectionName: string) {
+ const docSection: DocSection = {
+ comment: '',
+ constructors: [],
+ methods: [],
+ properties: [],
+ types: [],
+ };
+
+ let isConstructor;
+ _.each(entities, entity => {
+ switch (entity.kindString) {
+ case KindString.Constructor:
+ isConstructor = true;
+ const constructor = typeDocUtils._convertMethod(
+ entity,
+ isConstructor,
+ docsInfo.sections,
+ sectionName,
+ docsInfo.id,
+ );
+ docSection.constructors.push(constructor);
+ break;
+
+ case KindString.Method:
+ if (entity.flags.isPublic) {
+ isConstructor = false;
+ const method = typeDocUtils._convertMethod(
+ entity,
+ isConstructor,
+ docsInfo.sections,
+ sectionName,
+ docsInfo.id,
+ );
+ docSection.methods.push(method);
+ }
+ break;
+
+ case KindString.Property:
+ if (!typeDocUtils.isPrivateOrProtectedProperty(entity.name)) {
+ const property = typeDocUtils._convertProperty(
+ entity,
+ docsInfo.sections,
+ sectionName,
+ docsInfo.id,
+ );
+ docSection.properties.push(property);
+ }
+ break;
+
+ case KindString.Interface:
+ case KindString.Function:
+ case KindString.Variable:
+ case KindString.Enumeration:
+ case KindString.TypeAlias:
+ if (docsInfo.isPublicType(entity.name)) {
+ const customType = typeDocUtils._convertCustomType(
+ entity,
+ docsInfo.sections,
+ sectionName,
+ docsInfo.id,
+ );
+ docSection.types.push(customType);
+ }
+ break;
+
+ default:
+ throw utils.spawnSwitchErr('kindString', entity.kindString);
+ }
+ });
+ return docSection;
+ },
+ _convertCustomType(entity: TypeDocNode, sections: SectionsMap, sectionName: string, docId: string): CustomType {
+ const typeIfExists = !_.isUndefined(entity.type)
+ ? typeDocUtils._convertType(entity.type, sections, sectionName, docId)
+ : undefined;
+ const isConstructor = false;
+ const methodIfExists = !_.isUndefined(entity.declaration)
+ ? typeDocUtils._convertMethod(entity.declaration, isConstructor, sections, sectionName, docId)
+ : undefined;
+ const doesIndexSignatureExist = !_.isUndefined(entity.indexSignature);
+ const isIndexSignatureArray = _.isArray(entity.indexSignature);
+ // HACK: TypeDoc Versions <0.9.0 indexSignature is of type TypeDocNode[]
+ // Versions >0.9.0 have it as type TypeDocNode
+ const indexSignature =
+ doesIndexSignatureExist && isIndexSignatureArray
+ ? (entity.indexSignature as TypeDocNode[])[0]
+ : (entity.indexSignature as TypeDocNode);
+ const indexSignatureIfExists = doesIndexSignatureExist
+ ? typeDocUtils._convertIndexSignature(indexSignature, sections, sectionName, docId)
+ : undefined;
+ const commentIfExists =
+ !_.isUndefined(entity.comment) && !_.isUndefined(entity.comment.shortText)
+ ? entity.comment.shortText
+ : undefined;
+
+ const childrenIfExist = !_.isUndefined(entity.children)
+ ? _.map(entity.children, (child: TypeDocNode) => {
+ const childTypeIfExists = !_.isUndefined(child.type)
+ ? typeDocUtils._convertType(child.type, sections, sectionName, docId)
+ : undefined;
+ const c: CustomTypeChild = {
+ name: child.name,
+ type: childTypeIfExists,
+ defaultValue: child.defaultValue,
+ };
+ return c;
+ })
+ : undefined;
+
+ const customType = {
+ name: entity.name,
+ kindString: entity.kindString,
+ type: typeIfExists,
+ method: methodIfExists,
+ indexSignature: indexSignatureIfExists,
+ defaultValue: entity.defaultValue,
+ comment: commentIfExists,
+ children: childrenIfExist,
+ };
+ return customType;
+ },
+ _convertIndexSignature(
+ entity: TypeDocNode,
+ sections: SectionsMap,
+ sectionName: string,
+ docId: string,
+ ): IndexSignature {
+ const key = entity.parameters[0];
+ const indexSignature = {
+ keyName: key.name,
+ keyType: typeDocUtils._convertType(key.type, sections, sectionName, docId),
+ valueName: entity.type.name,
+ };
+ return indexSignature;
+ },
+ _convertProperty(entity: TypeDocNode, sections: SectionsMap, sectionName: string, docId: string): Property {
+ const source = entity.sources[0];
+ const commentIfExists = !_.isUndefined(entity.comment) ? entity.comment.shortText : undefined;
+ const property = {
+ name: entity.name,
+ type: typeDocUtils._convertType(entity.type, sections, sectionName, docId),
+ source: {
+ fileName: source.fileName,
+ line: source.line,
+ },
+ comment: commentIfExists,
+ };
+ return property;
+ },
+ _convertMethod(
+ entity: TypeDocNode,
+ isConstructor: boolean,
+ sections: SectionsMap,
+ sectionName: string,
+ docId: string,
+ ): TypescriptMethod {
+ const signature = entity.signatures[0];
+ const source = entity.sources[0];
+ const hasComment = !_.isUndefined(signature.comment);
+ const isStatic = _.isUndefined(entity.flags.isStatic) ? false : entity.flags.isStatic;
+
+ // HACK: we use the fact that the sectionName is the same as the property name at the top-level
+ // of the public interface. In the future, we shouldn't use this hack but rather get it from the JSON.
+ let callPath;
+ if (isConstructor || entity.name === '__type') {
+ callPath = '';
+ // TODO: Get rid of this 0x-specific logic
+ } else if (docId === 'ZERO_EX_JS') {
+ const topLevelInterface = isStatic ? 'ZeroEx.' : 'zeroEx.';
+ callPath =
+ !_.isUndefined(sections.zeroEx) && sectionName !== sections.zeroEx
+ ? `${topLevelInterface}${sectionName}.`
+ : topLevelInterface;
+ } else {
+ callPath = `${sectionName}.`;
+ }
+
+ const parameters = _.map(signature.parameters, param => {
+ return typeDocUtils._convertParameter(param, sections, sectionName, docId);
+ });
+ const returnType = typeDocUtils._convertType(signature.type, sections, sectionName, docId);
+ const typeParameter = _.isUndefined(signature.typeParameter)
+ ? undefined
+ : typeDocUtils._convertTypeParameter(signature.typeParameter[0], sections, sectionName, docId);
+
+ const method = {
+ isConstructor,
+ isStatic,
+ name: signature.name,
+ comment: hasComment ? signature.comment.shortText : undefined,
+ returnComment: hasComment && signature.comment.returns ? signature.comment.returns : undefined,
+ source: {
+ fileName: source.fileName,
+ line: source.line,
+ },
+ callPath,
+ parameters,
+ returnType,
+ typeParameter,
+ };
+ return method;
+ },
+ _convertTypeParameter(
+ entity: TypeDocNode,
+ sections: SectionsMap,
+ sectionName: string,
+ docId: string,
+ ): TypeParameter {
+ const type = typeDocUtils._convertType(entity.type, sections, sectionName, docId);
+ const parameter = {
+ name: entity.name,
+ type,
+ };
+ return parameter;
+ },
+ _convertParameter(entity: TypeDocNode, sections: SectionsMap, sectionName: string, docId: string): Parameter {
+ let comment = '<No comment>';
+ if (entity.comment && entity.comment.shortText) {
+ comment = entity.comment.shortText;
+ } else if (entity.comment && entity.comment.text) {
+ comment = entity.comment.text;
+ }
+
+ const isOptional = !_.isUndefined(entity.flags.isOptional) ? entity.flags.isOptional : false;
+
+ const type = typeDocUtils._convertType(entity.type, sections, sectionName, docId);
+
+ const parameter = {
+ name: entity.name,
+ comment,
+ isOptional,
+ type,
+ };
+ return parameter;
+ },
+ _convertType(entity: TypeDocType, sections: SectionsMap, sectionName: string, docId: string): Type {
+ const typeArguments = _.map(entity.typeArguments, typeArgument => {
+ return typeDocUtils._convertType(typeArgument, sections, sectionName, docId);
+ });
+ const types = _.map(entity.types, t => {
+ return typeDocUtils._convertType(t, sections, sectionName, docId);
+ });
+
+ const isConstructor = false;
+ const methodIfExists = !_.isUndefined(entity.declaration)
+ ? typeDocUtils._convertMethod(entity.declaration, isConstructor, sections, sectionName, docId)
+ : undefined;
+
+ const elementTypeIfExists = !_.isUndefined(entity.elementType)
+ ? {
+ name: entity.elementType.name,
+ typeDocType: entity.elementType.type,
+ }
+ : undefined;
+
+ const type = {
+ name: entity.name,
+ value: entity.value,
+ typeDocType: entity.type,
+ typeArguments,
+ elementType: elementTypeIfExists,
+ types,
+ method: methodIfExists,
+ };
+ return type;
+ },
+};
diff --git a/packages/react-docs/src/utils/utils.ts b/packages/react-docs/src/utils/utils.ts
new file mode 100644
index 000000000..f8c1fefff
--- /dev/null
+++ b/packages/react-docs/src/utils/utils.ts
@@ -0,0 +1,5 @@
+export const utils = {
+ spawnSwitchErr(name: string, value: any) {
+ return new Error(`Unexpected switch value: ${value} encountered for ${name}`);
+ },
+};