From 3472bdcfd4ea0a6145dd68972f563e483baf7e6b Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 28 Nov 2017 11:16:35 -0600 Subject: Refactor docs to be more declarative, put all hard-coded doc-related data in one place so it easier to add new doc pages --- packages/website/ts/components/top_bar.tsx | 16 +- .../website/ts/pages/documentation/docs_info.ts | 52 ++++++ .../ts/pages/documentation/event_definition.tsx | 10 +- .../website/ts/pages/documentation/interface.tsx | 7 +- .../ts/pages/documentation/method_block.tsx | 4 + .../ts/pages/documentation/method_signature.tsx | 35 +++- .../smart_contracts_documentation.tsx | 67 +++++--- .../website/ts/pages/documentation/source_link.tsx | 3 +- packages/website/ts/pages/documentation/type.tsx | 13 +- .../ts/pages/documentation/type_definition.tsx | 8 +- .../documentation/zero_ex_js_documentation.tsx | 177 +++++++++++++++++---- .../ts/pages/shared/nested_sidebar_menu.tsx | 8 +- .../website/ts/pages/shared/version_drop_down.tsx | 5 +- packages/website/ts/types.ts | 52 +++--- packages/website/ts/utils/constants.ts | 131 +++------------ packages/website/ts/utils/typedoc_utils.ts | 126 ++++++--------- 16 files changed, 428 insertions(+), 286 deletions(-) create mode 100644 packages/website/ts/pages/documentation/docs_info.ts diff --git a/packages/website/ts/components/top_bar.tsx b/packages/website/ts/components/top_bar.tsx index a84f1324d..7b81253e2 100644 --- a/packages/website/ts/components/top_bar.tsx +++ b/packages/website/ts/components/top_bar.tsx @@ -15,8 +15,9 @@ import {PortalMenu} from 'ts/components/portal_menu'; import {TopBarMenuItem} from 'ts/components/top_bar_menu_item'; import {DropDownMenuItem} from 'ts/components/ui/drop_down_menu_item'; import {Identicon} from 'ts/components/ui/identicon'; +import {DocsInfo} from 'ts/pages/documentation/docs_info'; import {NestedSidebarMenu} from 'ts/pages/shared/nested_sidebar_menu'; -import {Docs, MenuSubsectionsBySection, Styles, TypeDocNode, WebsitePaths} from 'ts/types'; +import {DocsMenu, MenuSubsectionsBySection, Styles, TypeDocNode, WebsitePaths} from 'ts/types'; import {configs} from 'ts/utils/configs'; import {constants} from 'ts/utils/constants'; import {typeDocUtils} from 'ts/utils/typedoc_utils'; @@ -30,9 +31,10 @@ interface TopBarProps { location: Location; docsVersion?: string; availableDocVersions?: string[]; + menu?: DocsMenu; menuSubsectionsBySection?: MenuSubsectionsBySection; shouldFullWidth?: boolean; - doc?: Docs; + docPath?: string; style?: React.CSSProperties; isNightVersion?: boolean; } @@ -272,25 +274,21 @@ export class TopBar extends React.Component { ); } private renderDocsMenu() { - if (!this.isViewing0xjsDocs() && !this.isViewingSmartContractsDocs()) { + if (!this.isViewing0xjsDocs() && !this.isViewingSmartContractsDocs() || _.isUndefined(this.props.menu)) { return; } - const topLevelMenu = this.isViewing0xjsDocs() ? - typeDocUtils.getFinal0xjsMenu(this.props.docsVersion) : - constants.menuSmartContracts; - const sectionTitle = this.isViewing0xjsDocs() ? '0x.js Docs' : 'Smart contract Docs'; return (
{sectionTitle}
diff --git a/packages/website/ts/pages/documentation/docs_info.ts b/packages/website/ts/pages/documentation/docs_info.ts new file mode 100644 index 000000000..326ebb31c --- /dev/null +++ b/packages/website/ts/pages/documentation/docs_info.ts @@ -0,0 +1,52 @@ +import compareVersions = require('compare-versions'); +import * as _ from 'lodash'; +import {DocsInfoConfig, DocsMenu, SectionsMap} from 'ts/types'; + +export class DocsInfo { + public packageName: string; + public packageUrl: string; + public websitePath: string; + public docsJsonRoot: string; + public menu: DocsMenu; + public sections: SectionsMap; + public sectionNameToMarkdown: {[sectionName: string]: string}; + private docsInfo: DocsInfoConfig; + constructor(config: DocsInfoConfig) { + this.packageName = config.packageName; + this.packageUrl = config.packageUrl; + this.websitePath = config.websitePath; + this.docsJsonRoot = config.docsJsonRoot; + this.sections = config.sections; + this.sectionNameToMarkdown = config.sectionNameToMarkdown; + this.docsInfo = config; + } + public isPublicType(typeName: string): boolean { + if (_.isUndefined(this.docsInfo.publicTypes)) { + return false; + } + const isPublic = _.includes(this.docsInfo.publicTypes, typeName); + return isPublic; + } + public getModulePathsIfExists(sectionName: string): string[] { + const modulePathsIfExists = this.docsInfo.sectionNameToModulePath[sectionName]; + return modulePathsIfExists; + } + public getMenu(selectedVersion?: string): {[section: string]: string[]} { + if (_.isUndefined(selectedVersion) || _.isUndefined(this.docsInfo.menuSubsectionToVersionWhenIntroduced)) { + return this.docsInfo.menu; + } + + const finalMenu = _.cloneDeep(this.docsInfo.menu); + finalMenu.contracts = _.filter(finalMenu.contracts, (contractName: string) => { + const versionIntroducedIfExists = this.docsInfo.menuSubsectionToVersionWhenIntroduced[contractName]; + if (!_.isUndefined(versionIntroducedIfExists)) { + const existsInSelectedVersion = compareVersions(selectedVersion, + versionIntroducedIfExists) >= 0; + return existsInSelectedVersion; + } else { + return true; + } + }); + return finalMenu; + } +} diff --git a/packages/website/ts/pages/documentation/event_definition.tsx b/packages/website/ts/pages/documentation/event_definition.tsx index ea75d78bc..3b1b86112 100644 --- a/packages/website/ts/pages/documentation/event_definition.tsx +++ b/packages/website/ts/pages/documentation/event_definition.tsx @@ -1,5 +1,6 @@ import * as _ from 'lodash'; import * as React from 'react'; +import {DocsInfo} from 'ts/pages/documentation/docs_info'; import {Type} from 'ts/pages/documentation/type'; import {AnchorTitle} from 'ts/pages/shared/anchor_title'; import {Event, EventArg, HeaderSizes} from 'ts/types'; @@ -11,6 +12,7 @@ const CUSTOM_GREEN = 'rgb(77, 162, 75)'; interface EventDefinitionProps { event: Event; + docsInfo: DocsInfo; } interface EventDefinitionState { @@ -53,9 +55,15 @@ export class EventDefinition extends React.Component indexed; const eventArgs = _.map(this.props.event.eventArgs, (eventArg: EventArg) => { + const t = ( + + ); return ( - {eventArg.name}{eventArg.isIndexed ? indexed : ''}: , + {eventArg.name}{eventArg.isIndexed ? indexed : ''}: {t}, ); }); diff --git a/packages/website/ts/pages/documentation/interface.tsx b/packages/website/ts/pages/documentation/interface.tsx index d8d4aec32..e671db2b8 100644 --- a/packages/website/ts/pages/documentation/interface.tsx +++ b/packages/website/ts/pages/documentation/interface.tsx @@ -1,11 +1,13 @@ import * as _ from 'lodash'; import * as React from 'react'; +import {DocsInfo} from 'ts/pages/documentation/docs_info'; import {MethodSignature} from 'ts/pages/documentation/method_signature'; import {Type} from 'ts/pages/documentation/type'; import {CustomType, TypeDocTypes} from 'ts/types'; interface InterfaceProps { type: CustomType; + docsInfo: DocsInfo; } export function Interface(props: InterfaceProps) { @@ -15,11 +17,12 @@ export function Interface(props: InterfaceProps) { {property.name}:{' '} {property.type.typeDocType !== TypeDocTypes.Reflection ? - : + : }, @@ -30,7 +33,7 @@ export function Interface(props: InterfaceProps) { const is = type.indexSignature; const param = ( - {is.keyName}: + {is.keyName}: ); properties.push(( diff --git a/packages/website/ts/pages/documentation/method_block.tsx b/packages/website/ts/pages/documentation/method_block.tsx index 026c46918..3f4eb7164 100644 --- a/packages/website/ts/pages/documentation/method_block.tsx +++ b/packages/website/ts/pages/documentation/method_block.tsx @@ -4,6 +4,7 @@ import {colors} from 'material-ui/styles'; import * as React from 'react'; import * as ReactMarkdown from 'react-markdown'; import {Comment} from 'ts/pages/documentation/comment'; +import {DocsInfo} from 'ts/pages/documentation/docs_info'; import {MethodSignature} from 'ts/pages/documentation/method_signature'; import {SourceLink} from 'ts/pages/documentation/source_link'; import {AnchorTitle} from 'ts/pages/shared/anchor_title'; @@ -23,6 +24,7 @@ interface MethodBlockProps { method: SolidityMethod|TypescriptMethod; libraryVersion: string; typeDefinitionByName: TypeDefinitionByName; + docsInfo: DocsInfo; } interface MethodBlockState { @@ -85,12 +87,14 @@ export class MethodBlock extends React.Component {(method as TypescriptMethod).source && } {method.comment && diff --git a/packages/website/ts/pages/documentation/method_signature.tsx b/packages/website/ts/pages/documentation/method_signature.tsx index e3806b2fa..197252fb4 100644 --- a/packages/website/ts/pages/documentation/method_signature.tsx +++ b/packages/website/ts/pages/documentation/method_signature.tsx @@ -1,5 +1,6 @@ import * as _ from 'lodash'; import * as React from 'react'; +import {DocsInfo} from 'ts/pages/documentation/docs_info'; import {Type} from 'ts/pages/documentation/type'; import {Parameter, SolidityMethod, TypeDefinitionByName, TypescriptMethod} from 'ts/types'; @@ -8,6 +9,7 @@ interface MethodSignatureProps { shouldHideMethodName?: boolean; shouldUseArrowSyntax?: boolean; typeDefinitionByName?: TypeDefinitionByName; + docsInfo: DocsInfo; } const defaultProps = { @@ -16,45 +18,64 @@ const defaultProps = { }; export const MethodSignature: React.SFC = (props: MethodSignatureProps) => { - const parameters = renderParameters(props.method, props.typeDefinitionByName); + const parameters = renderParameters(props.method, props.docsInfo, props.typeDefinitionByName); const paramString = _.reduce(parameters, (prev: React.ReactNode, curr: React.ReactNode) => { return [prev, ', ', curr]; }); const methodName = props.shouldHideMethodName ? '' : props.method.name; const typeParameterIfExists = _.isUndefined((props.method as TypescriptMethod).typeParameter) ? undefined : - renderTypeParameter(props.method, props.typeDefinitionByName); + renderTypeParameter(props.method, props.docsInfo, props.typeDefinitionByName); return ( {props.method.callPath}{methodName}{typeParameterIfExists}({paramString}) {props.shouldUseArrowSyntax ? ' => ' : ': '} {' '} {props.method.returnType && - + } ); }; -function renderParameters(method: TypescriptMethod|SolidityMethod, typeDefinitionByName?: TypeDefinitionByName) { +function renderParameters( + method: TypescriptMethod|SolidityMethod, docsInfo: DocsInfo, typeDefinitionByName?: TypeDefinitionByName, +) { const parameters = method.parameters; const params = _.map(parameters, (p: Parameter) => { const isOptional = p.isOptional; + const t = ( + + ); return ( - {p.name}{isOptional && '?'}: + {p.name}{isOptional && '?'}: {t} ); }); return params; } -function renderTypeParameter(method: TypescriptMethod, typeDefinitionByName?: TypeDefinitionByName) { +function renderTypeParameter( + method: TypescriptMethod, docsInfo: DocsInfo, typeDefinitionByName?: TypeDefinitionByName, +) { const typeParameter = method.typeParameter; const typeParam = ( {`<${typeParameter.name} extends `} - + {`>`} ); diff --git a/packages/website/ts/pages/documentation/smart_contracts_documentation.tsx b/packages/website/ts/pages/documentation/smart_contracts_documentation.tsx index 0d5751ffb..c7104e150 100644 --- a/packages/website/ts/pages/documentation/smart_contracts_documentation.tsx +++ b/packages/website/ts/pages/documentation/smart_contracts_documentation.tsx @@ -11,6 +11,7 @@ import semverSort = require('semver-sort'); import {TopBar} from 'ts/components/top_bar'; import {Badge} from 'ts/components/ui/badge'; import {Comment} from 'ts/pages/documentation/comment'; +import {DocsInfo} from 'ts/pages/documentation/docs_info'; import {EventDefinition} from 'ts/pages/documentation/event_definition'; import {MethodBlock} from 'ts/pages/documentation/method_block'; import {SourceLink} from 'ts/pages/documentation/source_link'; @@ -26,16 +27,17 @@ import { CustomType, DocAgnosticFormat, Docs, + DocsInfoConfig, DoxityDocObj, EtherscanLinkSuffixes, Event, MenuSubsectionsBySection, Networks, Property, - SmartContractsDocSections, SolidityMethod, Styles, TypeDefinitionByName, + WebsitePaths, } from 'ts/types'; import {constants} from 'ts/utils/constants'; import {docUtils} from 'ts/utils/doc_utils'; @@ -46,14 +48,36 @@ const IntroMarkdown = require('md/docs/smart_contracts/introduction'); /* tslint:enable:no-var-requires */ const SCROLL_TO_TIMEOUT = 500; +const SCROLL_TOP_ID = 'docsScrollTop'; const CUSTOM_PURPLE = '#690596'; const CUSTOM_RED = '#e91751'; const CUSTOM_TURQUOIS = '#058789'; -const DOC_JSON_ROOT = constants.S3_SMART_CONTRACTS_DOCUMENTATION_JSON_ROOT; -const sectionNameToMarkdown = { - [SmartContractsDocSections.Introduction]: IntroMarkdown, +const sections = constants.smartContractDocSections; + +const docsInfoConfig: DocsInfoConfig = { + packageName: '0x Smart Contracts', + packageUrl: 'https://github.com/0xProject/contracts', + websitePath: WebsitePaths.SmartContracts, + docsJsonRoot: 'https://s3.amazonaws.com/smart-contracts-docs-json', + menu: { + introduction: [ + sections.Introduction, + ], + contracts: [ + sections.Exchange, + sections.TokenRegistry, + sections.ZRXToken, + sections.EtherToken, + sections.TokenTransferProxy, + ], + }, + sectionNameToMarkdown: { + [sections.Introduction]: IntroMarkdown, + }, + sections, }; + const networkNameToColor: {[network: string]: string} = { [Networks.kovan]: CUSTOM_PURPLE, [Networks.ropsten]: CUSTOM_RED, @@ -90,6 +114,7 @@ const styles: Styles = { marginLeft: 20, }, }; +const docsInfo = new DocsInfo(docsInfoConfig); export class SmartContractsDocumentation extends React.Component { @@ -119,9 +144,10 @@ export class SmartContractsDocumentation extends location={this.props.location} docsVersion={this.props.docsVersion} availableDocVersions={this.props.availableDocVersions} + menu={docsInfo.getMenu(this.props.docsVersion)} menuSubsectionsBySection={menuSubsectionsBySection} shouldFullWidth={true} - doc={Docs.SmartContracts} + docPath={docsInfo.websitePath} /> {_.isUndefined(this.state.docAgnosticFormat) ?
@@ -162,7 +188,7 @@ export class SmartContractsDocumentation extends style={styles.mainContainers} className="absolute" > -
+

0x Smart Contracts @@ -177,19 +203,19 @@ export class SmartContractsDocumentation extends ); } private renderDocumentation(): React.ReactNode { - const subMenus = _.values(constants.menuSmartContracts); + const subMenus = _.values(docsInfo.getMenu()); const orderedSectionNames = _.flatten(subMenus); // Since smart contract method params are all base types, no need to pass // down the typeDefinitionByName const typeDefinitionByName = {}; - const sections = _.map(orderedSectionNames, this.renderSection.bind(this, typeDefinitionByName)); + const renderedSections = _.map(orderedSectionNames, this.renderSection.bind(this, typeDefinitionByName)); - return sections; + return renderedSections; } private renderSection(typeDefinitionByName: TypeDefinitionByName, sectionName: string): React.ReactNode { const docSection = this.state.docAgnosticFormat[sectionName]; - const markdownFileIfExists = sectionNameToMarkdown[sectionName]; + const markdownFileIfExists = docsInfo.sectionNameToMarkdown[sectionName]; if (!_.isUndefined(markdownFileIfExists)) { return ( ); }); @@ -293,7 +320,7 @@ export class SmartContractsDocumentation extends typeDefinitionByName: TypeDefinitionByName): React.ReactNode { const constructorDefs = _.map(constructors, constructor => { return this.renderMethodBlocks( - constructor, SmartContractsDocSections.zeroEx, constructor.isConstructor, typeDefinitionByName, + constructor, docsInfo.sections.zeroEx, constructor.isConstructor, typeDefinitionByName, ); }); return ( @@ -309,12 +336,13 @@ export class SmartContractsDocumentation extends className="pb3" > - {property.name}: + {property.name}: {property.source && } {property.comment && @@ -334,6 +362,7 @@ export class SmartContractsDocumentation extends method={method} typeDefinitionByName={typeDefinitionByName} libraryVersion={this.props.docsVersion} + docsInfo={docsInfo} /> ); } @@ -341,7 +370,7 @@ export class SmartContractsDocumentation extends const hashWithPrefix = this.props.location.hash; let hash = hashWithPrefix.slice(1); if (_.isEmpty(hash)) { - hash = 'smartContractsDocs'; // scroll to the top + hash = SCROLL_TOP_ID; // scroll to the top } scroller.scrollTo(hash, {duration: 0, offset: 0, containerId: 'documentation'}); @@ -352,14 +381,14 @@ export class SmartContractsDocumentation extends return menuSubsectionsBySection; } - const docSections = _.keys(SmartContractsDocSections); + const docSections = _.keys(docsInfo.sections); _.each(docSections, sectionName => { const docSection = docAgnosticFormat[sectionName]; if (_.isUndefined(docSection)) { return; // no-op } - if (sectionName === SmartContractsDocSections.types) { + if (sectionName === docsInfo.sections.types) { const sortedTypesNames = _.sortBy(docSection.types, 'name'); const typeNames = _.map(sortedTypesNames, t => t.name); menuSubsectionsBySection[sectionName] = typeNames; @@ -374,7 +403,7 @@ export class SmartContractsDocumentation extends return menuSubsectionsBySection; } private async fetchJSONDocsFireAndForgetAsync(preferredVersionIfExists?: string): Promise { - const versionToFileName = await docUtils.getVersionToFileNameAsync(DOC_JSON_ROOT); + const versionToFileName = await docUtils.getVersionToFileNameAsync(docsInfo.docsJsonRoot); const versions = _.keys(versionToFileName); this.props.dispatcher.updateAvailableDocVersions(versions); const sortedVersions = semverSort.desc(versions); @@ -390,7 +419,7 @@ export class SmartContractsDocumentation extends this.props.dispatcher.updateCurrentDocsVersion(versionToFetch); const versionFileNameToFetch = versionToFileName[versionToFetch]; - const versionDocObj = await docUtils.getJSONDocFileAsync(versionFileNameToFetch, DOC_JSON_ROOT); + const versionDocObj = await docUtils.getJSONDocFileAsync(versionFileNameToFetch, docsInfo.docsJsonRoot); const docAgnosticFormat = doxityUtils.convertToDocAgnosticFormat(versionDocObj as DoxityDocObj); this.setState({ diff --git a/packages/website/ts/pages/documentation/source_link.tsx b/packages/website/ts/pages/documentation/source_link.tsx index 0d40a4b7a..408dcabc7 100644 --- a/packages/website/ts/pages/documentation/source_link.tsx +++ b/packages/website/ts/pages/documentation/source_link.tsx @@ -5,6 +5,7 @@ import {constants} from 'ts/utils/constants'; interface SourceLinkProps { source: Source; + baseUrl: string; version: string; } @@ -12,7 +13,7 @@ const SUB_PKG = '0x.js'; export function SourceLink(props: SourceLinkProps) { const src = props.source; - const url = constants.GITHUB_0X_JS_URL; + const url = props.baseUrl; const sourceCodeUrl = `${url}/blob/${SUB_PKG}%40${props.version}/packages/${SUB_PKG}/${src.fileName}#L${src.line}`; return (
diff --git a/packages/website/ts/pages/documentation/type.tsx b/packages/website/ts/pages/documentation/type.tsx index b7d56f360..acd46ab72 100644 --- a/packages/website/ts/pages/documentation/type.tsx +++ b/packages/website/ts/pages/documentation/type.tsx @@ -3,6 +3,7 @@ import {colors} from 'material-ui/styles'; import * as React from 'react'; import {Link as ScrollLink} from 'react-scroll'; import * as ReactTooltip from 'react-tooltip'; +import {DocsInfo} from 'ts/pages/documentation/docs_info'; import {TypeDefinition} from 'ts/pages/documentation/type_definition'; import {Type as TypeDef, TypeDefinitionByName, TypeDocTypes} from 'ts/types'; import {constants} from 'ts/utils/constants'; @@ -38,6 +39,7 @@ const typeToSection: {[typeName: string]: string} = { interface TypeProps { type: TypeDef; + docsInfo: DocsInfo; typeDefinitionByName?: TypeDefinitionByName; } @@ -70,6 +72,7 @@ export function Type(props: TypeProps): any { key={key} type={arg.elementType} typeDefinitionByName={props.typeDefinitionByName} + docsInfo={props.docsInfo} />[] ); @@ -79,6 +82,7 @@ export function Type(props: TypeProps): any { key={`type-${arg.name}-${arg.value}-${arg.typeDocType}`} type={arg} typeDefinitionByName={props.typeDefinitionByName} + docsInfo={props.docsInfo} /> ); return subType; @@ -102,6 +106,7 @@ export function Type(props: TypeProps): any { key={`type-${t.name}-${t.value}-${t.typeDocType}`} type={t} typeDefinitionByName={props.typeDefinitionByName} + docsInfo={props.docsInfo} /> ); }); @@ -141,7 +146,7 @@ export function Type(props: TypeProps): any { ); } else if ((isReference || isArray) && - (typeDocUtils.isPublicType(typeName as string) || + (props.docsInfo.isPublicType(typeName as string) || !_.isUndefined(sectionNameIfExists))) { const id = Math.random().toString(); const typeDefinitionAnchorId = _.isUndefined(sectionNameIfExists) ? typeName : sectionNameIfExists; @@ -176,7 +181,11 @@ export function Type(props: TypeProps): any { id={id} className="typeTooltip" > - + } diff --git a/packages/website/ts/pages/documentation/type_definition.tsx b/packages/website/ts/pages/documentation/type_definition.tsx index 984c223b6..17b182c70 100644 --- a/packages/website/ts/pages/documentation/type_definition.tsx +++ b/packages/website/ts/pages/documentation/type_definition.tsx @@ -2,6 +2,7 @@ import * as _ from 'lodash'; import * as React from 'react'; import {Comment} from 'ts/pages/documentation/comment'; import {CustomEnum} from 'ts/pages/documentation/custom_enum'; +import {DocsInfo} from 'ts/pages/documentation/docs_info'; import {Enum} from 'ts/pages/documentation/enum'; import {Interface} from 'ts/pages/documentation/interface'; import {MethodSignature} from 'ts/pages/documentation/method_signature'; @@ -17,6 +18,7 @@ const KEYWORD_COLOR = '#a81ca6'; interface TypeDefinitionProps { customType: CustomType; shouldAddId?: boolean; + docsInfo: DocsInfo; } interface TypeDefinitionState { @@ -35,7 +37,7 @@ export class TypeDefinition extends React.Component ); break; @@ -81,11 +84,12 @@ export class TypeDefinition extends React.Component type {customType.name} ={' '} {customType.type.typeDocType !== TypeDocTypes.Reflection ? - : + : } diff --git a/packages/website/ts/pages/documentation/zero_ex_js_documentation.tsx b/packages/website/ts/pages/documentation/zero_ex_js_documentation.tsx index d64b196ed..5acd99b60 100644 --- a/packages/website/ts/pages/documentation/zero_ex_js_documentation.tsx +++ b/packages/website/ts/pages/documentation/zero_ex_js_documentation.tsx @@ -16,6 +16,7 @@ import semverSort = require('semver-sort'); import {TopBar} from 'ts/components/top_bar'; import {Loading} from 'ts/components/ui/loading'; import {Comment} from 'ts/pages/documentation/comment'; +import {DocsInfo} from 'ts/pages/documentation/docs_info'; import {MethodBlock} from 'ts/pages/documentation/method_block'; import {SourceLink} from 'ts/pages/documentation/source_link'; import {Type} from 'ts/pages/documentation/type'; @@ -29,6 +30,7 @@ import { CustomType, DocAgnosticFormat, Docs, + DocsInfoConfig, KindString, Property, ScreenWidths, @@ -36,7 +38,7 @@ import { TypeDefinitionByName, TypeDocNode, TypescriptMethod, - ZeroExJsDocSections, + WebsitePaths, } from 'ts/types'; import {constants} from 'ts/utils/constants'; import {docUtils} from 'ts/utils/doc_utils'; @@ -51,16 +53,127 @@ const versioningMarkdown = require('md/docs/0xjs/versioning'); /* tslint:enable:no-var-requires */ const SCROLL_TO_TIMEOUT = 500; -const DOC_JSON_ROOT = constants.S3_0XJS_DOCUMENTATION_JSON_ROOT; +const SCROLL_TOP_ID = 'docsScrollTop'; -const sectionNameToMarkdown = { - [ZeroExJsDocSections.introduction]: IntroMarkdown, - [ZeroExJsDocSections.installation]: InstallationMarkdown, - [ZeroExJsDocSections.async]: AsyncMarkdown, - [ZeroExJsDocSections.errors]: ErrorsMarkdown, - [ZeroExJsDocSections.versioning]: versioningMarkdown, +const zeroExJsDocSections = { + introduction: 'introduction', + installation: 'installation', + testrpc: 'testrpc', + async: 'async', + errors: 'errors', + versioning: 'versioning', + zeroEx: 'zeroEx', + exchange: 'exchange', + token: 'token', + tokenRegistry: 'tokenRegistry', + etherToken: 'etherToken', + proxy: 'proxy', + types: 'types', }; +const docsInfoConfig: DocsInfoConfig = { + packageName: '0x.js', + packageUrl: 'https://github.com/0xProject/0x.js', + websitePath: WebsitePaths.ZeroExJs, + docsJsonRoot: 'https://s3.amazonaws.com/0xjs-docs-jsons', + menu: { + introduction: [ + zeroExJsDocSections.introduction, + ], + install: [ + zeroExJsDocSections.installation, + ], + topics: [ + zeroExJsDocSections.async, + zeroExJsDocSections.errors, + zeroExJsDocSections.versioning, + ], + zeroEx: [ + zeroExJsDocSections.zeroEx, + ], + contracts: [ + zeroExJsDocSections.exchange, + zeroExJsDocSections.token, + zeroExJsDocSections.tokenRegistry, + zeroExJsDocSections.etherToken, + zeroExJsDocSections.proxy, + ], + types: [ + zeroExJsDocSections.types, + ], + }, + sectionNameToMarkdown: { + [zeroExJsDocSections.introduction]: IntroMarkdown, + [zeroExJsDocSections.installation]: InstallationMarkdown, + [zeroExJsDocSections.async]: AsyncMarkdown, + [zeroExJsDocSections.errors]: ErrorsMarkdown, + [zeroExJsDocSections.versioning]: versioningMarkdown, + }, + // Note: This needs to be kept in sync with the types exported in index.ts. Unfortunately there is + // currently no way to extract the re-exported types from index.ts via TypeDoc :( + publicTypes: [ + 'Order', + 'SignedOrder', + 'ECSignature', + 'ZeroExError', + 'EventCallback', + 'EventCallbackAsync', + 'EventCallbackSync', + 'ExchangeContractErrs', + 'ContractEvent', + 'Token', + 'ExchangeEvents', + 'IndexedFilterValues', + 'SubscriptionOpts', + 'BlockParam', + 'OrderFillOrKillRequest', + 'OrderCancellationRequest', + 'OrderFillRequest', + 'ContractEventEmitter', + 'Web3Provider', + 'ContractEventArgs', + 'LogCancelArgs', + 'LogFillArgs', + 'LogErrorContractEventArgs', + 'LogFillContractEventArgs', + 'LogCancelContractEventArgs', + 'TokenEvents', + 'ExchangeContractEventArgs', + 'TransferContractEventArgs', + 'ApprovalContractEventArgs', + 'TokenContractEventArgs', + 'ZeroExConfig', + 'TransactionReceiptWithDecodedLogs', + 'LogWithDecodedArgs', + 'DecodedLogArgs', + 'MethodOpts', + 'ValidateOrderFillableOpts', + 'OrderTransactionOpts', + 'ContractEventArg', + 'LogEvent', + 'LogEntry', + 'DecodedLogEvent', + ], + sectionNameToModulePath: { + [zeroExJsDocSections.zeroEx]: ['"src/0x"'], + [zeroExJsDocSections.exchange]: ['"src/contract_wrappers/exchange_wrapper"'], + [zeroExJsDocSections.tokenRegistry]: ['"src/contract_wrappers/token_registry_wrapper"'], + [zeroExJsDocSections.token]: ['"src/contract_wrappers/token_wrapper"'], + [zeroExJsDocSections.etherToken]: ['"src/contract_wrappers/ether_token_wrapper"'], + [zeroExJsDocSections.proxy]: [ + '"src/contract_wrappers/proxy_wrapper"', + '"src/contract_wrappers/token_transfer_proxy_wrapper"', + ], + [zeroExJsDocSections.types]: ['"src/types"'], + }, + menuSubsectionToVersionWhenIntroduced: { + [zeroExJsDocSections.etherToken]: '0.7.1', + [zeroExJsDocSections.proxy]: '0.8.0', + }, + sections: zeroExJsDocSections, +}; +const docsInfo = new DocsInfo(docsInfoConfig); + export interface ZeroExJSDocumentationPassedProps { source: string; location: Location; @@ -113,20 +226,21 @@ export class ZeroExJSDocumentation extends React.Component - + {_.isUndefined(this.state.docAgnosticFormat) ?
@@ -167,10 +281,10 @@ export class ZeroExJSDocumentation extends React.Component -
+

- - 0x.js + + {docsInfo.packageName}

{this.renderDocumentation()} @@ -182,10 +296,10 @@ export class ZeroExJSDocumentation extends React.Component ); }); @@ -231,7 +346,7 @@ export class ZeroExJSDocumentation extends React.Component - {sectionName === ZeroExJsDocSections.zeroEx && docSection.constructors.length > 0 && + {sectionName === docsInfo.sections.zeroEx && docSection.constructors.length > 0 &&

Constructor

{this.renderZeroExConstructors(docSection.constructors, typeDefinitionByName)} @@ -261,7 +376,7 @@ export class ZeroExJSDocumentation extends React.Component { return this.renderMethodBlocks( - constructor, ZeroExJsDocSections.zeroEx, constructor.isConstructor, typeDefinitionByName, + constructor, docsInfo.sections.zeroEx, constructor.isConstructor, typeDefinitionByName, ); }); return ( @@ -277,11 +392,12 @@ export class ZeroExJSDocumentation extends React.Component - {property.name}: + {property.name}: {property.comment && ); } @@ -307,13 +424,13 @@ export class ZeroExJSDocumentation extends React.Component { - const versionToFileName = await docUtils.getVersionToFileNameAsync(DOC_JSON_ROOT); + const versionToFileName = await docUtils.getVersionToFileNameAsync(docsInfo.docsJsonRoot); const versions = _.keys(versionToFileName); this.props.dispatcher.updateAvailableDocVersions(versions); const sortedVersions = semverSort.desc(versions); @@ -329,8 +446,12 @@ export class ZeroExJSDocumentation extends React.Component void; selectedVersion?: string; versions?: string[]; - doc?: Docs; + docPath?: string; isSectionHeaderClickable?: boolean; } @@ -77,11 +77,11 @@ export class NestedSidebarMenu extends React.Component {!_.isUndefined(this.props.versions) && !_.isUndefined(this.props.selectedVersion) && - !_.isUndefined(this.props.doc) && + !_.isUndefined(this.props.docPath) && } {navigation} diff --git a/packages/website/ts/pages/shared/version_drop_down.tsx b/packages/website/ts/pages/shared/version_drop_down.tsx index 8f4f1a35b..4af9a834f 100644 --- a/packages/website/ts/pages/shared/version_drop_down.tsx +++ b/packages/website/ts/pages/shared/version_drop_down.tsx @@ -8,7 +8,7 @@ import {constants} from 'ts/utils/constants'; interface VersionDropDownProps { selectedVersion: string; versions: string[]; - doc: Docs; + docPath: string; } interface VersionDropDownState {} @@ -40,7 +40,6 @@ export class VersionDropDown extends React.Component { const docSection = docAgnosticFormat[sectionName]; if (_.isUndefined(docSection)) { return; // no-op } - if (sectionName === ZeroExJsDocSections.types) { + if (!_.isUndefined(sections.types) && sectionName === sections.types) { const typeNames = _.map(docSection.types, t => t.name); menuSubsectionsBySection[sectionName] = typeNames; } else { @@ -94,27 +78,17 @@ export const typeDocUtils = { }); return menuSubsectionsBySection; }, - getFinal0xjsMenu(selectedVersion: string): {[section: string]: string[]} { - const finalMenu = _.cloneDeep(constants.menu0xjs); - finalMenu.contracts = _.filter(finalMenu.contracts, (contractName: string) => { - const versionIntroducedIfExists = constants.menuSubsectionToVersionWhenIntroduced[contractName]; - if (!_.isUndefined(versionIntroducedIfExists)) { - const existsInSelectedVersion = compareVersions(selectedVersion, - versionIntroducedIfExists) >= 0; - return existsInSelectedVersion; - } else { - return true; - } - }); - return finalMenu; - }, - convertToDocAgnosticFormat(typeDocJson: TypeDocNode): DocAgnosticFormat { - const subMenus = _.values(constants.menu0xjs); + convertToDocAgnosticFormat(docsInfo: DocsInfo, typeDocJson: TypeDocNode): 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 packageDefinitionIfExists = typeDocUtils.getModuleDefinitionBySectionNameIfExists( - typeDocJson, sectionName, + typeDocJson, modulePathsIfExists, ); if (_.isUndefined(packageDefinitionIfExists)) { return; // no-op @@ -125,7 +99,7 @@ export const typeDocUtils = { // for it. let entities; let packageComment = ''; - if (sectionName === ZeroExJsDocSections.types) { + if (sectionName === docsInfo.sections.types) { entities = packageDefinitionIfExists.children; } else { entities = packageDefinitionIfExists.children[0].children; @@ -133,13 +107,13 @@ export const typeDocUtils = { packageComment = !_.isUndefined(commentObj) ? commentObj.shortText : packageComment; } - const docSection = typeDocUtils._convertEntitiesToDocSection(entities, sectionName); + const docSection = typeDocUtils._convertEntitiesToDocSection(entities, docsInfo, sectionName); docSection.comment = packageComment; docAgnosticFormat[sectionName] = docSection; }); return docAgnosticFormat; }, - _convertEntitiesToDocSection(entities: TypeDocNode[], sectionName: string) { + _convertEntitiesToDocSection(entities: TypeDocNode[], docsInfo: DocsInfo, sectionName: string) { const docSection: DocSection = { comment: '', constructors: [], @@ -153,21 +127,25 @@ export const typeDocUtils = { switch (entity.kindString) { case KindString.Constructor: isConstructor = true; - const constructor = typeDocUtils._convertMethod(entity, isConstructor, sectionName); + const constructor = typeDocUtils._convertMethod( + entity, isConstructor, docsInfo.sections, sectionName, + ); docSection.constructors.push(constructor); break; case KindString.Method: if (entity.flags.isPublic) { isConstructor = false; - const method = typeDocUtils._convertMethod(entity, isConstructor, sectionName); + const method = typeDocUtils._convertMethod( + entity, isConstructor, docsInfo.sections, sectionName, + ); docSection.methods.push(method); } break; case KindString.Property: if (!typeDocUtils.isPrivateOrProtectedProperty(entity.name)) { - const property = typeDocUtils._convertProperty(entity, sectionName); + const property = typeDocUtils._convertProperty(entity, docsInfo.sections, sectionName); docSection.properties.push(property); } break; @@ -177,8 +155,8 @@ export const typeDocUtils = { case KindString.Variable: case KindString.Enumeration: case KindString['Type alias']: - if (typeDocUtils.isPublicType(entity.name)) { - const customType = typeDocUtils._convertCustomType(entity, sectionName); + if (docsInfo.isPublicType(entity.name)) { + const customType = typeDocUtils._convertCustomType(entity, docsInfo.sections, sectionName); docSection.types.push(customType); } break; @@ -189,16 +167,16 @@ export const typeDocUtils = { }); return docSection; }, - _convertCustomType(entity: TypeDocNode, sectionName: string): CustomType { + _convertCustomType(entity: TypeDocNode, sections: SectionsMap, sectionName: string): CustomType { const typeIfExists = !_.isUndefined(entity.type) ? - typeDocUtils._convertType(entity.type, sectionName) : + typeDocUtils._convertType(entity.type, sections, sectionName) : undefined; const isConstructor = false; const methodIfExists = !_.isUndefined(entity.declaration) ? - typeDocUtils._convertMethod(entity.declaration, isConstructor, sectionName) : + typeDocUtils._convertMethod(entity.declaration, isConstructor, sections, sectionName) : undefined; const indexSignatureIfExists = !_.isUndefined(entity.indexSignature) ? - typeDocUtils._convertIndexSignature(entity.indexSignature[0], sectionName) : + typeDocUtils._convertIndexSignature(entity.indexSignature[0], sections, sectionName) : undefined; const commentIfExists = !_.isUndefined(entity.comment) && !_.isUndefined(entity.comment.shortText) ? entity.comment.shortText : @@ -207,7 +185,7 @@ export const typeDocUtils = { const childrenIfExist = !_.isUndefined(entity.children) ? _.map(entity.children, (child: TypeDocNode) => { const childTypeIfExists = !_.isUndefined(child.type) ? - typeDocUtils._convertType(child.type, sectionName) : + typeDocUtils._convertType(child.type, sections, sectionName) : undefined; const c: CustomTypeChild = { name: child.name, @@ -230,21 +208,21 @@ export const typeDocUtils = { }; return customType; }, - _convertIndexSignature(entity: TypeDocNode, sectionName: string): IndexSignature { + _convertIndexSignature(entity: TypeDocNode, sections: SectionsMap, sectionName: string): IndexSignature { const key = entity.parameters[0]; const indexSignature = { keyName: key.name, - keyType: typeDocUtils._convertType(key.type, sectionName), + keyType: typeDocUtils._convertType(key.type, sections, sectionName), valueName: entity.type.name, }; return indexSignature; }, - _convertProperty(entity: TypeDocNode, sectionName: string): Property { + _convertProperty(entity: TypeDocNode, sections: SectionsMap, sectionName: 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, sectionName), + type: typeDocUtils._convertType(entity.type, sections, sectionName), source: { fileName: source.fileName, line: source.line, @@ -253,7 +231,9 @@ export const typeDocUtils = { }; return property; }, - _convertMethod(entity: TypeDocNode, isConstructor: boolean, sectionName: string): TypescriptMethod { + _convertMethod( + entity: TypeDocNode, isConstructor: boolean, sections: SectionsMap, sectionName: string, + ): TypescriptMethod { const signature = entity.signatures[0]; const source = entity.sources[0]; const hasComment = !_.isUndefined(signature.comment); @@ -262,18 +242,18 @@ export const typeDocUtils = { const topLevelInterface = isStatic ? 'ZeroEx.' : 'zeroEx.'; // 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 = (sectionName !== ZeroExJsDocSections.zeroEx) ? + let callPath = (!_.isUndefined(sections.zeroEx) && sectionName !== sections.zeroEx) ? `${topLevelInterface}${sectionName}.` : topLevelInterface; callPath = isConstructor ? '' : callPath; const parameters = _.map(signature.parameters, param => { - return typeDocUtils._convertParameter(param, sectionName); + return typeDocUtils._convertParameter(param, sections, sectionName); }); - const returnType = typeDocUtils._convertType(signature.type, sectionName); + const returnType = typeDocUtils._convertType(signature.type, sections, sectionName); const typeParameter = _.isUndefined(signature.typeParameter) ? undefined : - typeDocUtils._convertTypeParameter(signature.typeParameter[0], sectionName); + typeDocUtils._convertTypeParameter(signature.typeParameter[0], sections, sectionName); const method = { isConstructor, @@ -292,15 +272,15 @@ export const typeDocUtils = { }; return method; }, - _convertTypeParameter(entity: TypeDocNode, sectionName: string): TypeParameter { - const type = typeDocUtils._convertType(entity.type, sectionName); + _convertTypeParameter(entity: TypeDocNode, sections: SectionsMap, sectionName: string): TypeParameter { + const type = typeDocUtils._convertType(entity.type, sections, sectionName); const parameter = { name: entity.name, type, }; return parameter; }, - _convertParameter(entity: TypeDocNode, sectionName: string): Parameter { + _convertParameter(entity: TypeDocNode, sections: SectionsMap, sectionName: string): Parameter { let comment = ''; if (entity.comment && entity.comment.shortText) { comment = entity.comment.shortText; @@ -312,7 +292,7 @@ export const typeDocUtils = { entity.flags.isOptional : false; - const type = typeDocUtils._convertType(entity.type, sectionName); + const type = typeDocUtils._convertType(entity.type, sections, sectionName); const parameter = { name: entity.name, @@ -322,17 +302,17 @@ export const typeDocUtils = { }; return parameter; }, - _convertType(entity: TypeDocType, sectionName: string): Type { + _convertType(entity: TypeDocType, sections: SectionsMap, sectionName: string): Type { const typeArguments = _.map(entity.typeArguments, typeArgument => { - return typeDocUtils._convertType(typeArgument, sectionName); + return typeDocUtils._convertType(typeArgument, sections, sectionName); }); const types = _.map(entity.types, t => { - return typeDocUtils._convertType(t, sectionName); + return typeDocUtils._convertType(t, sections, sectionName); }); const isConstructor = false; const methodIfExists = !_.isUndefined(entity.declaration) ? - typeDocUtils._convertMethod(entity.declaration, isConstructor, sectionName) : + typeDocUtils._convertMethod(entity.declaration, isConstructor, sections, sectionName) : undefined; const elementTypeIfExists = !_.isUndefined(entity.elementType) ? -- cgit