move scripts to monorepro-scripts

This commit is contained in:
Fabio Berger
2018-03-13 15:29:12 +01:00
parent df1968157c
commit ca25b816fa
122 changed files with 498 additions and 297 deletions

View File

@@ -0,0 +1,56 @@
import { Styles } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
const styles: Styles = {
badge: {
width: 50,
fontSize: 11,
height: 10,
borderRadius: 5,
lineHeight: 0.9,
fontFamily: 'Roboto Mono',
marginLeft: 3,
marginRight: 3,
},
};
export interface BadgeProps {
title: string;
backgroundColor: string;
}
export interface BadgeState {
isHovering: boolean;
}
export class Badge extends React.Component<BadgeProps, BadgeState> {
constructor(props: BadgeProps) {
super(props);
this.state = {
isHovering: false,
};
}
public render() {
const badgeStyle = {
...styles.badge,
backgroundColor: this.props.backgroundColor,
opacity: this.state.isHovering ? 0.7 : 1,
};
return (
<div
className="p1 center"
style={badgeStyle}
onMouseOver={this._setHoverState.bind(this, true)}
onMouseOut={this._setHoverState.bind(this, false)}
>
{this.props.title}
</div>
);
}
private _setHoverState(isHovering: boolean) {
this.setState({
isHovering,
});
}
}

View File

@@ -0,0 +1,23 @@
import { MarkdownCodeBlock } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import * as ReactMarkdown from 'react-markdown';
export interface CommentProps {
comment: string;
className?: string;
}
const defaultProps = {
className: '',
};
export const Comment: React.SFC<CommentProps> = (props: CommentProps) => {
return (
<div className={`${props.className} comment`}>
<ReactMarkdown source={props.comment} renderers={{ code: MarkdownCodeBlock }} />
</div>
);
};
Comment.defaultProps = defaultProps;

View File

@@ -0,0 +1,33 @@
import * as _ from 'lodash';
import * as React from 'react';
import { CustomType } from '../types';
import { utils } from '../utils/utils';
const STRING_ENUM_CODE_PREFIX = ' strEnum(';
export interface CustomEnumProps {
type: CustomType;
}
// This component renders custom string enums that was a work-around for versions of
// TypeScript <2.4.0 that did not support them natively. We keep it around to support
// older versions of 0x.js <0.9.0
export function CustomEnum(props: CustomEnumProps) {
const type = props.type;
if (!_.startsWith(type.defaultValue, STRING_ENUM_CODE_PREFIX)) {
utils.consoleLog('We do not yet support `Variable` types that are not strEnums');
return null;
}
// Remove the prefix and postfix, leaving only the strEnum values without quotes.
const enumValues = type.defaultValue.slice(10, -3).replace(/'/g, '');
return (
<span>
{`{`}
{'\t'}
{enumValues}
<br />
{`}`}
</span>
);
}

View File

@@ -0,0 +1,375 @@
import {
colors,
constants as sharedConstants,
EtherscanLinkSuffixes,
MarkdownSection,
MenuSubsectionsBySection,
NestedSidebarMenu,
Networks,
SectionHeader,
Styles,
utils as sharedUtils,
} from '@0xproject/react-shared';
import * as _ from 'lodash';
import CircularProgress from 'material-ui/CircularProgress';
import * as React from 'react';
import { scroller } from 'react-scroll';
import { DocsInfo } from '../docs_info';
import {
AddressByContractName,
DocAgnosticFormat,
DoxityDocObj,
Event,
Property,
SolidityMethod,
SupportedDocJson,
TypeDefinitionByName,
TypescriptMethod,
} from '../types';
import { constants } from '../utils/constants';
import { utils } from '../utils/utils';
import { Badge } from './badge';
import { Comment } from './comment';
import { EventDefinition } from './event_definition';
import { MethodBlock } from './method_block';
import { SourceLink } from './source_link';
import { Type } from './type';
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 DocumentationProps {
selectedVersion: string;
availableVersions: string[];
docsInfo: DocsInfo;
sourceUrl: string;
onVersionSelected: (semver: string) => void;
docAgnosticFormat?: DocAgnosticFormat;
sidebarHeader?: React.ReactNode;
topBarHeight?: number;
}
export interface DocumentationState {
isHoveringSidebar: boolean;
}
export class Documentation extends React.Component<DocumentationProps, DocumentationState> {
public static defaultProps: Partial<DocumentationProps> = {
topBarHeight: 0,
};
constructor(props: DocumentationProps) {
super(props);
this.state = {
isHoveringSidebar: false,
};
}
public componentDidMount() {
window.addEventListener('hashchange', this._onHashChanged.bind(this), false);
}
public componentWillUnmount() {
window.removeEventListener('hashchange', this._onHashChanged.bind(this), false);
}
public componentDidUpdate(prevProps: DocumentationProps, prevState: DocumentationState) {
if (!_.isEqual(prevProps.docAgnosticFormat, this.props.docAgnosticFormat)) {
const hash = window.location.hash.slice(1);
sharedUtils.scrollToHash(hash, sharedConstants.SCROLL_CONTAINER_ID);
}
}
public render() {
const styles: Styles = {
mainContainers: {
position: 'absolute',
top: 1,
left: 0,
bottom: 0,
right: 0,
overflowZ: 'hidden',
overflowY: 'scroll',
minHeight: `calc(100vh - ${this.props.topBarHeight}px)`,
WebkitOverflowScrolling: 'touch',
},
menuContainer: {
borderColor: colors.grey300,
maxWidth: 330,
marginLeft: 20,
},
};
const menuSubsectionsBySection = this.props.docsInfo.getMenuSubsectionsBySection(this.props.docAgnosticFormat);
return (
<div>
{_.isUndefined(this.props.docAgnosticFormat) ? (
this._renderLoading(styles.mainContainers)
) : (
<div style={{ width: '100%', height: '100%', backgroundColor: colors.gray40 }}>
<div
className="mx-auto max-width-4 flex"
style={{ color: colors.grey800, height: `calc(100vh - ${this.props.topBarHeight}px)` }}
>
<div
className="relative sm-hide xs-hide"
style={{ width: '36%', height: `calc(100vh - ${this.props.topBarHeight}px)` }}
>
<div
className="border-right absolute"
style={{
...styles.menuContainer,
...styles.mainContainers,
height: `calc(100vh - ${this.props.topBarHeight}px)`,
overflow: this.state.isHoveringSidebar ? 'auto' : 'hidden',
}}
onMouseEnter={this._onSidebarHover.bind(this)}
onMouseLeave={this._onSidebarHoverOff.bind(this)}
>
<NestedSidebarMenu
selectedVersion={this.props.selectedVersion}
versions={this.props.availableVersions}
sidebarHeader={this.props.sidebarHeader}
topLevelMenu={this.props.docsInfo.getMenu(this.props.selectedVersion)}
menuSubsectionsBySection={menuSubsectionsBySection}
onVersionSelected={this.props.onVersionSelected}
/>
</div>
</div>
<div
className="relative col lg-col-9 md-col-9 sm-col-12 col-12"
style={{ backgroundColor: colors.white }}
>
<div
id={sharedConstants.SCROLL_CONTAINER_ID}
style={styles.mainContainers}
className="absolute px1"
>
<div id={sharedConstants.SCROLL_TOP_ID} />
{this._renderDocumentation()}
</div>
</div>
</div>
</div>
)}
</div>
);
}
private _renderLoading(mainContainersStyles: React.CSSProperties) {
return (
<div className="col col-12" style={mainContainersStyles}>
<div
className="relative sm-px2 sm-pt2 sm-m1"
style={{ height: 122, top: '50%', transform: 'translateY(-50%)' }}
>
<div className="center pb2">
<CircularProgress size={40} thickness={5} />
</div>
<div className="center pt2" style={{ paddingBottom: 11 }}>
Loading documentation...
</div>
</div>
</div>
);
}
private _renderDocumentation(): React.ReactNode {
const subMenus = _.values(this.props.docsInfo.getMenu());
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 markdownFileIfExists = this.props.docsInfo.sectionNameToMarkdown[sectionName];
if (!_.isUndefined(markdownFileIfExists)) {
return (
<MarkdownSection
key={`markdown-section-${sectionName}`}
sectionName={sectionName}
markdownContent={markdownFileIfExists}
/>
);
}
const docSection = this.props.docAgnosticFormat[sectionName];
if (_.isUndefined(docSection)) {
return null;
}
const sortedTypes = _.sortBy(docSection.types, 'name');
const typeDefs = _.map(sortedTypes, customType => {
return (
<TypeDefinition
sectionName={sectionName}
key={`type-${customType.name}`}
customType={customType}
docsInfo={this.props.docsInfo}
/>
);
});
const sortedProperties = _.sortBy(docSection.properties, 'name');
const propertyDefs = _.map(sortedProperties, this._renderProperty.bind(this, sectionName));
const sortedMethods = _.sortBy(docSection.methods, 'name');
const methodDefs = _.map(sortedMethods, method => {
const isConstructor = false;
return this._renderMethodBlocks(method, sectionName, isConstructor, typeDefinitionByName);
});
const sortedEvents = _.sortBy(docSection.events, 'name');
const eventDefs = _.map(sortedEvents, (event: Event, i: number) => {
return (
<EventDefinition
key={`event-${event.name}-${i}`}
event={event}
sectionName={sectionName}
docsInfo={this.props.docsInfo}
/>
);
});
const headerStyle: React.CSSProperties = {
fontWeight: 100,
};
return (
<div key={`section-${sectionName}`} className="py2 pr3 md-pl2 sm-pl3">
<div className="flex pb2">
<div style={{ marginRight: 7 }}>
<SectionHeader sectionName={sectionName} />
</div>
{this._renderNetworkBadgesIfExists(sectionName)}
</div>
{docSection.comment && <Comment comment={docSection.comment} />}
{docSection.constructors.length > 0 &&
this.props.docsInfo.isVisibleConstructor(sectionName) && (
<div>
<h2 style={headerStyle}>Constructor</h2>
{this._renderConstructors(docSection.constructors, sectionName, typeDefinitionByName)}
</div>
)}
{docSection.properties.length > 0 && (
<div>
<h2 style={headerStyle}>Properties</h2>
<div>{propertyDefs}</div>
</div>
)}
{docSection.methods.length > 0 && (
<div>
<h2 style={headerStyle}>Methods</h2>
<div>{methodDefs}</div>
</div>
)}
{!_.isUndefined(docSection.events) &&
docSection.events.length > 0 && (
<div>
<h2 style={headerStyle}>Events</h2>
<div>{eventDefs}</div>
</div>
)}
{!_.isUndefined(typeDefs) &&
typeDefs.length > 0 && (
<div>
<div>{typeDefs}</div>
</div>
)}
</div>
);
}
private _renderNetworkBadgesIfExists(sectionName: string) {
if (this.props.docsInfo.type !== SupportedDocJson.Doxity) {
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 (
<a
key={`badge-${networkName}-${sectionName}`}
href={linkIfExists}
target="_blank"
style={{ color: colors.white, textDecoration: 'none' }}
>
<Badge title={networkName} backgroundColor={networkNameToColor[networkName]} />
</a>
);
},
);
return badges;
}
private _renderConstructors(
constructors: SolidityMethod[] | TypescriptMethod[],
sectionName: string,
typeDefinitionByName: TypeDefinitionByName,
): React.ReactNode {
const constructorDefs = _.map(constructors, constructor => {
return this._renderMethodBlocks(constructor, sectionName, constructor.isConstructor, typeDefinitionByName);
});
return <div>{constructorDefs}</div>;
}
private _renderProperty(sectionName: string, property: Property): React.ReactNode {
return (
<div key={`property-${property.name}-${property.type.name}`} className="pb3">
<code className={`hljs ${constants.TYPE_TO_SYNTAX[this.props.docsInfo.type]}`}>
{property.name}:
<Type type={property.type} sectionName={sectionName} docsInfo={this.props.docsInfo} />
</code>
{property.source && (
<SourceLink
version={this.props.selectedVersion}
source={property.source}
sourceUrl={this.props.sourceUrl}
/>
)}
{property.comment && <Comment comment={property.comment} className="py2" />}
</div>
);
}
private _renderMethodBlocks(
method: SolidityMethod | TypescriptMethod,
sectionName: string,
isConstructor: boolean,
typeDefinitionByName: TypeDefinitionByName,
): React.ReactNode {
return (
<MethodBlock
key={`method-${method.name}-${sectionName}`}
sectionName={sectionName}
method={method}
typeDefinitionByName={typeDefinitionByName}
libraryVersion={this.props.selectedVersion}
docsInfo={this.props.docsInfo}
sourceUrl={this.props.sourceUrl}
/>
);
}
private _onSidebarHover(event: React.FormEvent<HTMLInputElement>) {
this.setState({
isHoveringSidebar: true,
});
}
private _onSidebarHoverOff() {
this.setState({
isHoveringSidebar: false,
});
}
private _onHashChanged(event: any) {
const hash = window.location.hash.slice(1);
sharedUtils.scrollToHash(hash, sharedConstants.SCROLL_CONTAINER_ID);
}
}

View File

@@ -0,0 +1,23 @@
import * as _ from 'lodash';
import * as React from 'react';
import { EnumValue } from '../types';
export interface EnumProps {
values: EnumValue[];
}
export function Enum(props: EnumProps) {
const values = _.map(props.values, (value, i) => {
const defaultValueIfAny = !_.isUndefined(value.defaultValue) ? ` = ${value.defaultValue}` : '';
return `\n\t${value.name}${defaultValueIfAny},`;
});
return (
<span>
{`{`}
{values}
<br />
{`}`}
</span>
);
}

View File

@@ -0,0 +1,84 @@
import { AnchorTitle, colors, HeaderSizes } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import { DocsInfo } from '../docs_info';
import { Event, EventArg } from '../types';
import { Type } from './type';
export interface EventDefinitionProps {
event: Event;
sectionName: string;
docsInfo: DocsInfo;
}
export interface EventDefinitionState {
shouldShowAnchor: boolean;
}
export class EventDefinition extends React.Component<EventDefinitionProps, EventDefinitionState> {
constructor(props: EventDefinitionProps) {
super(props);
this.state = {
shouldShowAnchor: false,
};
}
public render() {
const event = this.props.event;
const id = `${this.props.sectionName}-${event.name}`;
return (
<div
id={id}
className="pb2"
style={{ overflow: 'hidden', width: '100%' }}
onMouseOver={this._setAnchorVisibility.bind(this, true)}
onMouseOut={this._setAnchorVisibility.bind(this, false)}
>
<AnchorTitle
headerSize={HeaderSizes.H3}
title={`Event ${event.name}`}
id={id}
shouldShowAnchor={this.state.shouldShowAnchor}
/>
<div style={{ fontSize: 16 }}>
<pre>
<code className="hljs solidity">{this._renderEventCode()}</code>
</pre>
</div>
</div>
);
}
private _renderEventCode() {
const indexed = <span style={{ color: colors.green }}> indexed</span>;
const eventArgs = _.map(this.props.event.eventArgs, (eventArg: EventArg) => {
const type = (
<Type type={eventArg.type} sectionName={this.props.sectionName} docsInfo={this.props.docsInfo} />
);
return (
<span key={`eventArg-${eventArg.name}`}>
{eventArg.name}
{eventArg.isIndexed ? indexed : ''}: {type},
</span>
);
});
const argList = _.reduce(eventArgs, (prev: React.ReactNode, curr: React.ReactNode) => {
return [prev, '\n\t', curr];
});
return (
<span>
{`{`}
<br />
{'\t'}
{argList}
<br />
{`}`}
</span>
);
}
private _setAnchorVisibility(shouldShowAnchor: boolean) {
this.setState({
shouldShowAnchor,
});
}
}

View File

@@ -0,0 +1,63 @@
import * as _ from 'lodash';
import * as React from 'react';
import { DocsInfo } from '../docs_info';
import { CustomType, TypeDocTypes } from '../types';
import { MethodSignature } from './method_signature';
import { Type } from './type';
export interface InterfaceProps {
type: CustomType;
sectionName: string;
docsInfo: DocsInfo;
}
export function Interface(props: InterfaceProps) {
const type = props.type;
const properties = _.map(type.children, property => {
return (
<span key={`property-${property.name}-${property.type}-${type.name}`}>
{property.name}:{' '}
{property.type.typeDocType !== TypeDocTypes.Reflection ? (
<Type type={property.type} sectionName={props.sectionName} docsInfo={props.docsInfo} />
) : (
<MethodSignature
method={property.type.method}
sectionName={props.sectionName}
shouldHideMethodName={true}
shouldUseArrowSyntax={true}
docsInfo={props.docsInfo}
/>
)},
</span>
);
});
const hasIndexSignature = !_.isUndefined(type.indexSignature);
if (hasIndexSignature) {
const is = type.indexSignature;
const param = (
<span key={`indexSigParams-${is.keyName}-${is.keyType}-${type.name}`}>
{is.keyName}: <Type type={is.keyType} sectionName={props.sectionName} docsInfo={props.docsInfo} />
</span>
);
properties.push(
<span key={`indexSignature-${type.name}-${is.keyType.name}`}>
[{param}]: {is.valueName},
</span>,
);
}
const propertyList = _.reduce(properties, (prev: React.ReactNode, curr: React.ReactNode) => {
return [prev, '\n\t', curr];
});
return (
<span>
{`{`}
<br />
{'\t'}
{propertyList}
<br />
{`}`}
</span>
);
}

View File

@@ -0,0 +1,150 @@
import { AnchorTitle, colors, HeaderSizes, Styles } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import { DocsInfo } from '../docs_info';
import { Parameter, SolidityMethod, TypeDefinitionByName, TypescriptMethod } from '../types';
import { constants } from '../utils/constants';
import { typeDocUtils } from '../utils/typedoc_utils';
import { Comment } from './comment';
import { MethodSignature } from './method_signature';
import { SourceLink } from './source_link';
export interface MethodBlockProps {
method: SolidityMethod | TypescriptMethod;
sectionName: string;
libraryVersion: string;
typeDefinitionByName: TypeDefinitionByName;
docsInfo: DocsInfo;
sourceUrl: string;
}
export interface MethodBlockState {
shouldShowAnchor: boolean;
}
const styles: Styles = {
chip: {
fontSize: 13,
backgroundColor: colors.lightBlueA700,
color: colors.white,
height: 11,
borderRadius: 14,
lineHeight: 0.9,
},
};
export class MethodBlock extends React.Component<MethodBlockProps, MethodBlockState> {
constructor(props: MethodBlockProps) {
super(props);
this.state = {
shouldShowAnchor: false,
};
}
public render() {
const method = this.props.method;
if (typeDocUtils.isPrivateOrProtectedProperty(method.name)) {
return null;
}
return (
<div
id={`${this.props.sectionName}-${method.name}`}
style={{ overflow: 'hidden', width: '100%' }}
className="pb4"
onMouseOver={this._setAnchorVisibility.bind(this, true)}
onMouseOut={this._setAnchorVisibility.bind(this, false)}
>
{!method.isConstructor && (
<div className="flex pb2 pt2">
{(method as TypescriptMethod).isStatic && this._renderChip('Static')}
{(method as SolidityMethod).isConstant && this._renderChip('Constant')}
{(method as SolidityMethod).isPayable && this._renderChip('Payable')}
<div style={{ lineHeight: 1.3 }}>
<AnchorTitle
headerSize={HeaderSizes.H3}
title={method.name}
id={`${this.props.sectionName}-${method.name}`}
shouldShowAnchor={this.state.shouldShowAnchor}
/>
</div>
</div>
)}
<code className={`hljs ${constants.TYPE_TO_SYNTAX[this.props.docsInfo.type]}`}>
<MethodSignature
method={method}
sectionName={this.props.sectionName}
typeDefinitionByName={this.props.typeDefinitionByName}
docsInfo={this.props.docsInfo}
/>
</code>
{(method as TypescriptMethod).source && (
<SourceLink
version={this.props.libraryVersion}
source={(method as TypescriptMethod).source}
sourceUrl={this.props.sourceUrl}
/>
)}
{method.comment && <Comment comment={method.comment} className="py2" />}
{method.parameters &&
!_.isEmpty(method.parameters) && (
<div>
<h4 className="pb1 thin" style={{ borderBottom: '1px solid #e1e8ed' }}>
ARGUMENTS
</h4>
{this._renderParameterDescriptions(method.parameters)}
</div>
)}
{method.returnComment && (
<div className="pt1 comment">
<h4 className="pb1 thin" style={{ borderBottom: '1px solid #e1e8ed' }}>
RETURNS
</h4>
<Comment comment={method.returnComment} />
</div>
)}
</div>
);
}
private _renderChip(text: string) {
return (
<div className="p1 mr1" style={styles.chip}>
{text}
</div>
);
}
private _renderParameterDescriptions(parameters: Parameter[]) {
const descriptions = _.map(parameters, parameter => {
const isOptional = parameter.isOptional;
return (
<div
key={`param-description-${parameter.name}`}
className="flex pb1 mb2"
style={{ borderBottom: '1px solid #f0f4f7' }}
>
<div className="pl2 col lg-col-4 md-col-4 sm-col-12 col-12">
<div
className="bold"
style={{ overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' }}
>
{parameter.name}
</div>
<div className="pt1" style={{ color: colors.grey, fontSize: 14 }}>
{isOptional && 'optional'}
</div>
</div>
<div className="col lg-col-8 md-col-8 sm-col-12 col-12" style={{ paddingLeft: 5 }}>
{parameter.comment && <Comment comment={parameter.comment} />}
</div>
</div>
);
});
return descriptions;
}
private _setAnchorVisibility(shouldShowAnchor: boolean) {
this.setState({
shouldShowAnchor,
});
}
}

View File

@@ -0,0 +1,128 @@
import * as _ from 'lodash';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { DocsInfo } from '../docs_info';
import { Parameter, SolidityMethod, TypeDefinitionByName, TypescriptMethod } from '../types';
import { constants } from '../utils/constants';
import { Type } from './type';
export interface MethodSignatureProps {
method: TypescriptMethod | SolidityMethod;
sectionName: string;
shouldHideMethodName?: boolean;
shouldUseArrowSyntax?: boolean;
typeDefinitionByName?: TypeDefinitionByName;
docsInfo: DocsInfo;
}
const defaultProps = {
shouldHideMethodName: false,
shouldUseArrowSyntax: false,
};
export const MethodSignature: React.SFC<MethodSignatureProps> = (props: MethodSignatureProps) => {
const sectionName = constants.TYPES_SECTION_NAME;
const parameters = renderParameters(props.method, props.docsInfo, sectionName, props.typeDefinitionByName);
const paramStringArray: any[] = [];
// HACK: For now we don't put params on newlines if there are less then 2 of them.
// Ideally we would check the character length of the resulting method signature and
// if it exceeds the available space, put params on their own lines.
const hasMoreThenTwoParams = parameters.length > 2;
_.each(parameters, (param: React.ReactNode, i: number) => {
const finalParam = hasMoreThenTwoParams ? (
<span className="pl2" key={`param-${i}`}>
{param}
</span>
) : (
param
);
paramStringArray.push(finalParam);
const comma = hasMoreThenTwoParams ? (
<span key={`param-comma-${i}`}>
, <br />
</span>
) : (
', '
);
paramStringArray.push(comma);
});
if (!hasMoreThenTwoParams) {
paramStringArray.pop();
}
const methodName = props.shouldHideMethodName ? '' : props.method.name;
const typeParameterIfExists = _.isUndefined((props.method as TypescriptMethod).typeParameter)
? undefined
: renderTypeParameter(props.method, props.docsInfo, sectionName, props.typeDefinitionByName);
return (
<span style={{ fontSize: 15 }}>
{props.method.callPath}
{methodName}
{typeParameterIfExists}({hasMoreThenTwoParams && <br />}
{paramStringArray})
{props.method.returnType && (
<span>
{props.shouldUseArrowSyntax ? ' => ' : ': '}{' '}
<Type
type={props.method.returnType}
sectionName={sectionName}
typeDefinitionByName={props.typeDefinitionByName}
docsInfo={props.docsInfo}
/>
</span>
)}
</span>
);
};
MethodSignature.defaultProps = defaultProps;
function renderParameters(
method: TypescriptMethod | SolidityMethod,
docsInfo: DocsInfo,
sectionName: string,
typeDefinitionByName?: TypeDefinitionByName,
) {
const parameters = method.parameters;
const params = _.map(parameters, (p: Parameter) => {
const isOptional = p.isOptional;
const type = (
<Type
type={p.type}
sectionName={sectionName}
typeDefinitionByName={typeDefinitionByName}
docsInfo={docsInfo}
/>
);
return (
<span key={`param-${p.type}-${p.name}`}>
{p.name}
{isOptional && '?'}: {type}
</span>
);
});
return params;
}
function renderTypeParameter(
method: TypescriptMethod,
docsInfo: DocsInfo,
sectionName: string,
typeDefinitionByName?: TypeDefinitionByName,
) {
const typeParameter = method.typeParameter;
const typeParam = (
<span>
{`<${typeParameter.name} extends `}
<Type
type={typeParameter.type}
sectionName={sectionName}
typeDefinitionByName={typeDefinitionByName}
docsInfo={docsInfo}
/>
{`>`}
</span>
);
return typeParam;
}

View File

@@ -0,0 +1,23 @@
import { colors } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import { Source } from '../types';
export interface SourceLinkProps {
source: Source;
sourceUrl: string;
version: string;
}
export function SourceLink(props: SourceLinkProps) {
const src = props.source;
const sourceCodeUrl = `${props.sourceUrl}/${src.fileName}#L${src.line}`;
return (
<div className="pt2" style={{ fontSize: 14 }}>
<a href={sourceCodeUrl} target="_blank" className="underline" style={{ color: colors.grey }}>
Source
</a>
</div>
);
}

View File

@@ -0,0 +1,227 @@
import { colors, constants as sharedConstants, utils as sharedUtils } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import { Link as ScrollLink } from 'react-scroll';
import * as ReactTooltip from 'react-tooltip';
import { DocsInfo } from '../docs_info';
import { Type as TypeDef, TypeDefinitionByName, TypeDocTypes } from '../types';
import { constants } from '../utils/constants';
import { utils } from '../utils/utils';
import { TypeDefinition } from './type_definition';
const typeToSection: { [typeName: string]: string } = {
ExchangeWrapper: 'exchange',
TokenWrapper: 'token',
TokenRegistryWrapper: 'tokenRegistry',
EtherTokenWrapper: 'etherToken',
ProxyWrapper: 'proxy',
TokenTransferProxyWrapper: 'proxy',
OrderStateWatcher: 'orderWatcher',
};
export interface TypeProps {
type: TypeDef;
docsInfo: DocsInfo;
sectionName: string;
typeDefinitionByName?: TypeDefinitionByName;
}
// The return type needs to be `any` here so that we can recursively define <Type /> components within
// <Type /> components (e.g when rendering the union type).
export function Type(props: TypeProps): any {
const type = props.type;
const isReference = type.typeDocType === TypeDocTypes.Reference;
const isArray = type.typeDocType === TypeDocTypes.Array;
let typeNameColor = 'inherit';
let typeName: string | React.ReactNode;
let typeArgs: React.ReactNode[] = [];
switch (type.typeDocType) {
case TypeDocTypes.Intrinsic:
case TypeDocTypes.Unknown:
typeName = type.name;
typeNameColor = colors.orange;
break;
case TypeDocTypes.Reference:
typeName = type.name;
typeArgs = _.map(type.typeArguments, (arg: TypeDef) => {
if (arg.typeDocType === TypeDocTypes.Array) {
const key = `type-${arg.elementType.name}-${arg.elementType.typeDocType}`;
return (
<span>
<Type
key={key}
type={arg.elementType}
sectionName={props.sectionName}
typeDefinitionByName={props.typeDefinitionByName}
docsInfo={props.docsInfo}
/>[]
</span>
);
} else {
const subType = (
<Type
key={`type-${arg.name}-${arg.value}-${arg.typeDocType}`}
type={arg}
sectionName={props.sectionName}
typeDefinitionByName={props.typeDefinitionByName}
docsInfo={props.docsInfo}
/>
);
return subType;
}
});
break;
case TypeDocTypes.StringLiteral:
typeName = `'${type.value}'`;
typeNameColor = colors.green;
break;
case TypeDocTypes.Array:
typeName = type.elementType.name;
break;
case TypeDocTypes.Union:
const unionTypes = _.map(type.types, t => {
return (
<Type
key={`type-${t.name}-${t.value}-${t.typeDocType}`}
type={t}
sectionName={props.sectionName}
typeDefinitionByName={props.typeDefinitionByName}
docsInfo={props.docsInfo}
/>
);
});
typeName = _.reduce(unionTypes, (prev: React.ReactNode, curr: React.ReactNode) => {
return [prev, '|', curr];
});
break;
case TypeDocTypes.TypeParameter:
typeName = type.name;
break;
case TypeDocTypes.Intersection:
const intersectionsTypes = _.map(type.types, t => {
return (
<Type
key={`type-${t.name}-${t.value}-${t.typeDocType}`}
type={t}
sectionName={props.sectionName}
typeDefinitionByName={props.typeDefinitionByName}
docsInfo={props.docsInfo}
/>
);
});
typeName = _.reduce(intersectionsTypes, (prev: React.ReactNode, curr: React.ReactNode) => {
return [prev, '&', curr];
});
break;
default:
throw utils.spawnSwitchErr('type.typeDocType', type.typeDocType);
}
// HACK: Normalize BigNumber to simply BigNumber. For some reason the type
// name is unpredictably one or the other.
if (typeName === 'BigNumber') {
typeName = 'BigNumber';
}
const commaSeparatedTypeArgs = _.reduce(typeArgs, (prev: React.ReactNode, curr: React.ReactNode) => {
return [prev, ', ', curr];
});
let typeNameUrlIfExists;
let typePrefixIfExists;
let sectionNameIfExists;
if (!_.isUndefined(props.docsInfo.typeConfigs)) {
typeNameUrlIfExists = !_.isUndefined(props.docsInfo.typeConfigs.typeNameToExternalLink)
? props.docsInfo.typeConfigs.typeNameToExternalLink[typeName as string]
: undefined;
typePrefixIfExists = !_.isUndefined(props.docsInfo.typeConfigs.typeNameToPrefix)
? props.docsInfo.typeConfigs.typeNameToPrefix[typeName as string]
: undefined;
sectionNameIfExists = !_.isUndefined(props.docsInfo.typeConfigs.typeNameToDocSection)
? props.docsInfo.typeConfigs.typeNameToDocSection[typeName as string]
: undefined;
}
if (!_.isUndefined(typeNameUrlIfExists)) {
typeName = (
<a
href={typeNameUrlIfExists}
target="_blank"
className="text-decoration-none"
style={{ color: colors.lightBlueA700 }}
>
{!_.isUndefined(typePrefixIfExists) ? `${typePrefixIfExists}.` : ''}
{typeName}
</a>
);
} else if (
(isReference || isArray) &&
(props.docsInfo.isPublicType(typeName as string) || !_.isUndefined(sectionNameIfExists))
) {
const id = Math.random().toString();
const typeDefinitionAnchorId = _.isUndefined(sectionNameIfExists)
? `${props.sectionName}-${typeName}`
: sectionNameIfExists;
let typeDefinition;
if (props.typeDefinitionByName) {
typeDefinition = props.typeDefinitionByName[typeName as string];
}
typeName = (
<ScrollLink
to={typeDefinitionAnchorId}
offset={0}
duration={sharedConstants.DOCS_SCROLL_DURATION_MS}
containerId={sharedConstants.DOCS_CONTAINER_ID}
>
{_.isUndefined(typeDefinition) || sharedUtils.isUserOnMobile() ? (
<span
onClick={sharedUtils.setUrlHash.bind(null, typeDefinitionAnchorId)}
style={{ color: colors.lightBlueA700, cursor: 'pointer' }}
>
{typeName}
</span>
) : (
<span
data-tip={true}
data-for={id}
onClick={sharedUtils.setUrlHash.bind(null, typeDefinitionAnchorId)}
style={{
color: colors.lightBlueA700,
cursor: 'pointer',
display: 'inline-block',
}}
>
{typeName}
<ReactTooltip type="light" effect="solid" id={id} className="typeTooltip">
<TypeDefinition
sectionName={props.sectionName}
customType={typeDefinition}
shouldAddId={false}
docsInfo={props.docsInfo}
/>
</ReactTooltip>
</span>
)}
</ScrollLink>
);
}
return (
<span>
<span style={{ color: typeNameColor }}>{typeName}</span>
{isArray && '[]'}
{!_.isEmpty(typeArgs) && (
<span>
{'<'}
{commaSeparatedTypeArgs}
{'>'}
</span>
)}
</span>
);
}

View File

@@ -0,0 +1,131 @@
import { AnchorTitle, colors, HeaderSizes } from '@0xproject/react-shared';
import * as _ from 'lodash';
import * as React from 'react';
import { DocsInfo } from '../docs_info';
import { CustomType, CustomTypeChild, KindString, TypeDocTypes } from '../types';
import { constants } from '../utils/constants';
import { utils } from '../utils/utils';
import { Comment } from './comment';
import { CustomEnum } from './custom_enum';
import { Enum } from './enum';
import { Interface } from './interface';
import { MethodSignature } from './method_signature';
import { Type } from './type';
export interface TypeDefinitionProps {
sectionName: string;
customType: CustomType;
shouldAddId?: boolean;
docsInfo: DocsInfo;
}
export interface TypeDefinitionState {
shouldShowAnchor: boolean;
}
export class TypeDefinition extends React.Component<TypeDefinitionProps, TypeDefinitionState> {
public static defaultProps: Partial<TypeDefinitionProps> = {
shouldAddId: true,
};
constructor(props: TypeDefinitionProps) {
super(props);
this.state = {
shouldShowAnchor: false,
};
}
public render() {
const customType = this.props.customType;
if (!this.props.docsInfo.isPublicType(customType.name)) {
return null; // no-op
}
let typePrefix: string;
let codeSnippet: React.ReactNode;
switch (customType.kindString) {
case KindString.Interface:
typePrefix = 'Interface';
codeSnippet = (
<Interface type={customType} sectionName={this.props.sectionName} docsInfo={this.props.docsInfo} />
);
break;
case KindString.Variable:
typePrefix = 'Enum';
codeSnippet = <CustomEnum type={customType} />;
break;
case KindString.Enumeration:
typePrefix = 'Enum';
const enumValues = _.map(customType.children, (c: CustomTypeChild) => {
return {
name: c.name,
defaultValue: c.defaultValue,
};
});
codeSnippet = <Enum values={enumValues} />;
break;
case KindString.TypeAlias:
typePrefix = 'Type Alias';
codeSnippet = (
<span>
<span style={{ color: colors.lightPurple }}>type</span> {customType.name} ={' '}
{customType.type.typeDocType !== TypeDocTypes.Reflection ? (
<Type
type={customType.type}
sectionName={this.props.sectionName}
docsInfo={this.props.docsInfo}
/>
) : (
<MethodSignature
method={customType.type.method}
sectionName={this.props.sectionName}
shouldHideMethodName={true}
shouldUseArrowSyntax={true}
docsInfo={this.props.docsInfo}
/>
)}
</span>
);
break;
default:
throw utils.spawnSwitchErr('type.kindString', customType.kindString);
}
const typeDefinitionAnchorId = `${this.props.sectionName}-${customType.name}`;
return (
<div
id={this.props.shouldAddId ? typeDefinitionAnchorId : ''}
className="pb2"
style={{ overflow: 'hidden', width: '100%' }}
onMouseOver={this._setAnchorVisibility.bind(this, true)}
onMouseOut={this._setAnchorVisibility.bind(this, false)}
>
<AnchorTitle
headerSize={HeaderSizes.H3}
title={`${typePrefix} ${customType.name}`}
id={this.props.shouldAddId ? typeDefinitionAnchorId : ''}
shouldShowAnchor={this.state.shouldShowAnchor}
/>
<div style={{ fontSize: 16 }}>
<pre>
<code className={`hljs ${constants.TYPE_TO_SYNTAX[this.props.docsInfo.type]}`}>
{codeSnippet}
</code>
</pre>
</div>
<div style={{ maxWidth: 620 }}>
{customType.comment && <Comment comment={customType.comment} className="py2" />}
</div>
</div>
);
}
private _setAnchorVisibility(shouldShowAnchor: boolean) {
this.setState({
shouldShowAnchor,
});
}
}