import { colors, constants as sharedConstants, EtherscanLinkSuffixes, HeaderSizes, Link, MarkdownSection, Networks, SectionHeader, utils as sharedUtils, } from '@0xproject/react-shared'; import { DocAgnosticFormat, Event, ExternalExportToLink, Property, SolidityMethod, TypeDefinitionByName, TypescriptFunction, TypescriptMethod, } from '@0xproject/types'; import * as _ from 'lodash'; import * as React from 'react'; import * as semver from 'semver'; import { DocsInfo } from '../docs_info'; import { AddressByContractName, SupportedDocJson } from '../types'; import { constants } from '../utils/constants'; import { Badge } from './badge'; import { Comment } from './comment'; import { EventDefinition } from './event_definition'; import { PropertyBlock } from './property_block'; import { SignatureBlock } from './signature_block'; import { TypeDefinition } from './type_definition'; const networkNameToColor: { [network: string]: string } = { [Networks.Kovan]: colors.purple, [Networks.Ropsten]: colors.red, [Networks.Mainnet]: colors.turquois, [Networks.Rinkeby]: colors.darkYellow, }; export interface DocReferenceProps { selectedVersion: string; availableVersions: string[]; docsInfo: DocsInfo; sourceUrl: string; docAgnosticFormat?: DocAgnosticFormat; } export interface DocReferenceState {} export class DocReference extends React.Component { public componentDidMount(): void { window.addEventListener('hashchange', this._onHashChanged.bind(this), false); } public componentWillUnmount(): void { window.removeEventListener('hashchange', this._onHashChanged.bind(this), false); } public componentDidUpdate(prevProps: DocReferenceProps, _prevState: DocReferenceState): void { if (!_.isEqual(prevProps.docAgnosticFormat, this.props.docAgnosticFormat)) { const hash = window.location.hash.slice(1); sharedUtils.scrollToHash(hash, sharedConstants.SCROLL_CONTAINER_ID); } } public render(): React.ReactNode { const subMenus = _.values(this.props.docsInfo.markdownMenu); const orderedSectionNames = _.flatten(subMenus); const typeDefinitionByName = this.props.docsInfo.getTypeDefinitionsByName(this.props.docAgnosticFormat); const renderedSections = _.map(orderedSectionNames, this._renderSection.bind(this, typeDefinitionByName)); return (
{renderedSections}
); } private _renderSection(typeDefinitionByName: TypeDefinitionByName, sectionName: string): React.ReactNode { const markdownVersions = _.keys(this.props.docsInfo.sectionNameToMarkdownByVersion); const eligibleVersions = _.filter(markdownVersions, mdVersion => { return semver.lte(mdVersion, this.props.selectedVersion); }); if (_.isEmpty(eligibleVersions)) { throw new Error( `No eligible markdown sections found for ${this.props.docsInfo.displayName} version ${ this.props.selectedVersion }.`, ); } const sortedEligibleVersions = eligibleVersions.sort(semver.rcompare.bind(semver)); const closestVersion = sortedEligibleVersions[0]; const markdownFileIfExists = this.props.docsInfo.sectionNameToMarkdownByVersion[closestVersion][sectionName]; if (!_.isUndefined(markdownFileIfExists)) { // Special-case replace the `introduction` sectionName with the package name const isIntroductionSection = sectionName === 'introduction'; const headerSize = isIntroductionSection ? HeaderSizes.H1 : HeaderSizes.H3; return ( ); } const docSection = this.props.docAgnosticFormat[sectionName]; if (_.isUndefined(docSection)) { return null; } const isExportedFunctionSection = docSection.functions.length === 1 && _.isEmpty(docSection.types) && _.isEmpty(docSection.methods) && _.isEmpty(docSection.constructors) && _.isEmpty(docSection.properties) && _.isEmpty(docSection.events); const sortedTypes = _.sortBy(docSection.types, 'name'); const typeDefs = _.map(sortedTypes, (customType, i) => { return ( ); }); const sortedProperties = _.sortBy(docSection.properties, 'name'); const propertyDefs = _.map( sortedProperties, this._renderProperty.bind(this, sectionName, typeDefinitionByName), ); const sortedMethods = _.sortBy(docSection.methods, 'name'); const methodDefs = _.map(sortedMethods, method => { return this._renderSignatureBlocks(method, sectionName, typeDefinitionByName); }); const sortedFunctions = _.sortBy(docSection.functions, 'name'); const functionDefs = _.map(sortedFunctions, func => { return this._renderSignatureBlocks(func, sectionName, typeDefinitionByName); }); const sortedEvents = _.sortBy(docSection.events, 'name'); const eventDefs = _.map(sortedEvents, (event: Event, i: number) => { return ( ); }); const headerStyle: React.CSSProperties = { fontWeight: 100, }; return (
{this._renderNetworkBadgesIfExists(sectionName)}
{docSection.comment && } {!_.isEmpty(docSection.constructors) && (

Constructor

{this._renderConstructors(docSection.constructors, sectionName, typeDefinitionByName)}
)} {!_.isEmpty(docSection.properties) && (

Properties

{propertyDefs}
)} {!_.isEmpty(docSection.methods) && (

Methods

{methodDefs}
)} {!_.isEmpty(docSection.functions) && (
{!isExportedFunctionSection && (
Functions
)}
{functionDefs}
)} {!_.isUndefined(docSection.events) && docSection.events.length > 0 && (

Events

{eventDefs}
)} {!_.isUndefined(docSection.externalExportToLink) && this._renderExternalExports(docSection.externalExportToLink)} {!_.isUndefined(typeDefs) && typeDefs.length > 0 && (
{typeDefs}
)}
); } private _renderExternalExports(externalExportToLink: ExternalExportToLink): React.ReactNode { const externalExports = _.map(externalExportToLink, (link: string, exportName: string) => { return (
{`import { `} {exportName} {` } from '${this.props.docsInfo.packageName}'`}
); }); return
{externalExports}
; } private _renderNetworkBadgesIfExists(sectionName: string): React.ReactNode { if (this.props.docsInfo.type !== SupportedDocJson.SolDoc) { return null; } const networkToAddressByContractName = this.props.docsInfo.contractsByVersionByNetworkId[ this.props.selectedVersion ]; const badges = _.map( networkToAddressByContractName, (addressByContractName: AddressByContractName, networkName: string) => { const contractAddress = addressByContractName[sectionName]; if (_.isUndefined(contractAddress)) { return null; } const linkIfExists = sharedUtils.getEtherScanLinkIfExists( contractAddress, sharedConstants.NETWORK_ID_BY_NAME[networkName], EtherscanLinkSuffixes.Address, ); return (
); }, ); return badges; } private _renderConstructors( constructors: SolidityMethod[] | TypescriptMethod[], sectionName: string, typeDefinitionByName: TypeDefinitionByName, ): React.ReactNode { const constructorDefs = _.map(constructors, constructor => { return this._renderSignatureBlocks(constructor, sectionName, typeDefinitionByName); }); return
{constructorDefs}
; } private _renderProperty( sectionName: string, typeDefinitionByName: TypeDefinitionByName, property: Property, ): React.ReactNode { return ( ); } private _renderSignatureBlocks( method: SolidityMethod | TypescriptFunction | TypescriptMethod, sectionName: string, typeDefinitionByName: TypeDefinitionByName, ): React.ReactNode { return ( ); } private _onHashChanged(_event: any): void { const hash = window.location.hash.slice(1); sharedUtils.scrollToHash(hash, sharedConstants.SCROLL_CONTAINER_ID); } }