BREAKING CHANGE: document contracts from sol-doc

Change website to accept smart contract documentation in the format
generated by sol-doc rather than that generated by Doxity.
This commit is contained in:
F. Eugene Aumson
2018-09-22 11:06:48 -04:00
parent 9f0dfb1e1a
commit 98d06d6d25
12 changed files with 48 additions and 236 deletions

View File

@@ -2,7 +2,7 @@
#### WARNING: Alpha software. Expect things to break when trying to use.
A full-page React component for rendering beautiful documentation for Solidity and Typescript code generated with [TypeDoc](http://typedoc.org/) or [Doxity](https://github.com/0xproject/doxity).
A full-page React component for rendering beautiful documentation for Solidity and Typescript code generated with [TypeDoc](http://typedoc.org/) or [sol-doc](https://github.com/0xProject/0x-monorepo/tree/development/packages/sol-doc).
<div style="text-align: center;">
<img src="https://s3.eu-west-2.amazonaws.com/0x-wiki-images/screenshot.png" style="padding-bottom: 20px; padding-top: 20px;" width="80%" />
@@ -47,7 +47,7 @@ Feel free to contribute to these improvements!
* Allow user to pass in styling for all major elements similar to [Material-UI](http://www.material-ui.com/).
* Allow user to define an alternative font and have it change everywhere.
* Add source links to Solidity docs (currently unsupported by Doxity).
* Add source links to Solidity docs (currently unsupported by solc, which underlies sol-doc).
## Contributing

View File

@@ -4,7 +4,7 @@
"engines": {
"node": ">=6.12"
},
"description": "React documentation component for rendering TypeDoc & Doxity generated JSON",
"description": "React documentation component for rendering TypeDoc & sol-doc generated JSON",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"scripts": {

View File

@@ -329,7 +329,7 @@ export class Documentation extends React.Component<DocumentationProps, Documenta
return <div>{externalExports}</div>;
}
private _renderNetworkBadgesIfExists(sectionName: string): React.ReactNode {
if (this.props.docsInfo.type !== SupportedDocJson.Doxity) {
if (this.props.docsInfo.type !== SupportedDocJson.Solidity) {
return null;
}

View File

@@ -1,18 +1,15 @@
import { MenuSubsectionsBySection } from '@0xproject/react-shared';
import { DocAgnosticFormat, GeneratedDocJson, TypeDefinitionByName } from '@0xproject/types';
import { DocAgnosticFormat, TypeDefinitionByName } from '@0xproject/types';
import * as _ from 'lodash';
import {
ContractsByVersionByNetworkId,
DocsInfoConfig,
DocsMenu,
DoxityDocObj,
SectionNameToMarkdownByVersion,
SectionsMap,
SupportedDocJson,
} from './types';
import { doxityUtils } from './utils/doxity_utils';
import { TypeDocUtils } from './utils/typedoc_utils';
export class DocsInfo {
public id: string;
@@ -93,12 +90,4 @@ export class DocsInfo {
const typeDefinitionByName = _.keyBy(typeDocSection.types, 'name') as any;
return typeDefinitionByName;
}
public convertToDocAgnosticFormat(docObj: DoxityDocObj | GeneratedDocJson): DocAgnosticFormat {
if (this.type === SupportedDocJson.Doxity) {
return doxityUtils.convertToDocAgnosticFormat(docObj as DoxityDocObj);
} else {
const typeDocUtils = new TypeDocUtils(docObj as GeneratedDocJson, this);
return typeDocUtils.convertToDocAgnosticFormat();
}
}
}

View File

@@ -14,9 +14,10 @@ export { Signature } from './components/signature';
export { SourceLink } from './components/source_link';
export { TypeDefinition } from './components/type_definition';
export { Type } from './components/type';
export { TypeDocUtils } from './utils/typedoc_utils';
export { DocsInfo } from './docs_info';
export { DocsInfoConfig, DoxityDocObj, DocsMenu, SupportedDocJson } from './types';
export { DocsInfoConfig, DocsMenu, SupportedDocJson } from './types';
export { constants } from './utils/constants';

View File

@@ -38,7 +38,7 @@ export enum KindString {
}
export enum SupportedDocJson {
Doxity = 'DOXITY',
Solidity = 'SOLIDITY',
TypeDoc = 'TYPEDOC',
}
@@ -50,40 +50,6 @@ export interface ContractsByVersionByNetworkId {
};
}
export interface DoxityDocObj {
[contractName: string]: DoxityContractObj;
}
export interface DoxityContractObj {
title: string;
fileName: string;
name: string;
abiDocs: DoxityAbiDoc[];
}
export interface DoxityAbiDoc {
constant: boolean;
inputs: DoxityInput[];
name: string;
outputs: DoxityOutput[];
payable: boolean;
type: string;
details?: string;
return?: string;
}
export interface DoxityOutput {
name: string;
type: string;
}
export interface DoxityInput {
name: string;
type: string;
description: string;
indexed?: boolean;
}
export interface AddressByContractName {
[contractName: string]: string;
}

View File

@@ -4,7 +4,7 @@ export const constants = {
TYPES_SECTION_NAME: 'types',
EXTERNAL_EXPORTS_SECTION_NAME: 'external exports',
TYPE_TO_SYNTAX: {
[SupportedDocJson.Doxity]: 'solidity',
[SupportedDocJson.Solidity]: 'solidity',
[SupportedDocJson.TypeDoc]: 'typescript',
} as { [supportedDocType: string]: string },
};

View File

@@ -1,173 +0,0 @@
import * as _ from 'lodash';
import {
DocAgnosticFormat,
DocSection,
EventArg,
Parameter,
Property,
SolidityMethod,
Type,
TypeDocTypes,
} from '@0xproject/types';
import { AbiTypes, DoxityAbiDoc, DoxityContractObj, DoxityDocObj, DoxityInput } 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: doxityUtils._convertParameters(doxityConstructor.inputs),
returnType: doxityUtils._convertType(doxityContractObj.name),
};
constructors.push(constructor);
}
const doxityMethods: DoxityAbiDoc[] = _.filter<DoxityAbiDoc>(
doxityContractObj.abiDocs,
(abiDoc: DoxityAbiDoc) => {
return doxityUtils._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 = doxityUtils._convertType(outputsType);
} else {
const outputsType = `[${_.map(outputs, output => output.type).join(', ')}]`;
returnTypeIfExists = doxityUtils._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: doxityUtils._convertParameters(doxityMethod.inputs),
returnType: returnTypeIfExists,
};
return method;
},
);
const doxityProperties: DoxityAbiDoc[] = _.filter<DoxityAbiDoc>(
doxityContractObj.abiDocs,
(abiDoc: DoxityAbiDoc) => {
return doxityUtils._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: doxityUtils._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: doxityUtils._convertEventArgs(doxityEvent.inputs),
};
return event;
});
const docSection: DocSection = {
comment: doxityContractObj.title,
constructors,
methods,
properties,
types: [],
functions: [],
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: doxityUtils._convertType(input.type),
};
return parameter;
});
return parameters;
},
_convertType(typeName: string): Type {
const type = {
name: typeName,
typeDocType: TypeDocTypes.Intrinsic,
};
return type;
},
_isMethod(abiDoc: DoxityAbiDoc): boolean {
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): boolean {
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: doxityUtils._convertType(input.type),
};
return eventArg;
});
return eventArgs;
},
};

View File

@@ -0,0 +1,8 @@
Welcome to the [0x smart contracts](https://github.com/0xProject/contracts) documentation! This documentation is intended for dApp developers who want to integrate 0x exchange functionality directly into their own smart contracts.
### Helpful wiki articles:
* [Overview of 0x protocol architecture](https://0xproject.com/wiki#Architecture)
* [0x smart contract interactions](https://0xproject.com/wiki#Contract-Interactions)
* [Deployed smart contract addresses](https://0xproject.com/wiki#Deployed-Addresses)
* [0x protocol message format](https://0xproject.com/wiki#Message-Format)

View File

@@ -11,29 +11,28 @@ import { Translate } from 'ts/utils/translate';
/* tslint:disable:no-var-requires */
const IntroMarkdownV1 = require('md/docs/smart_contracts/1.0.0/introduction');
const IntroMarkdownV2 = require('md/docs/smart_contracts/2.0.0/introduction');
/* tslint:enable:no-var-requires */
const docsInfoConfig: DocsInfoConfig = {
id: DocPackages.SmartContracts,
packageName: 'contracts',
type: SupportedDocJson.Doxity,
type: SupportedDocJson.Solidity,
displayName: '0x Smart Contracts',
packageUrl: 'https://github.com/0xProject/contracts',
markdownMenu: {
introduction: [Sections.Introduction],
contracts: [Sections.Exchange, Sections.TokenRegistry, Sections.ZRXToken, Sections.TokenTransferProxy],
},
sectionNameToMarkdownByVersion: {
'0.0.1': {
[Sections.Introduction]: IntroMarkdownV1,
},
'2.0.0': {
[Sections.Introduction]: IntroMarkdownV2,
},
},
markdownSections: {
Introduction: Sections.Introduction,
Exchange: Sections.Exchange,
TokenTransferProxy: Sections.TokenTransferProxy,
TokenRegistry: Sections.TokenRegistry,
ZRXToken: Sections.ZRXToken,
},
contractsByVersionByNetworkId: {
'1.0.0': {

View File

@@ -1,4 +1,11 @@
import { DocAgnosticFormat, DocsInfo, Documentation } from '@0xproject/react-docs';
import {
DocAgnosticFormat,
DocsInfo,
Documentation,
GeneratedDocJson,
SupportedDocJson,
TypeDocUtils,
} from '@0xproject/react-docs';
import findVersions = require('find-versions');
import * as _ from 'lodash';
import * as React from 'react';
@@ -128,7 +135,22 @@ export class DocPage extends React.Component<DocPageProps, DocPageState> {
const versionFilePathToFetch = versionToFilePath[versionToFetch];
const versionDocObj = await docUtils.getJSONDocFileAsync(versionFilePathToFetch, docBucketRoot);
const docAgnosticFormat = this.props.docsInfo.convertToDocAgnosticFormat(versionDocObj);
let docAgnosticFormat;
if (this.props.docsInfo.type === SupportedDocJson.TypeDoc) {
docAgnosticFormat = new TypeDocUtils(
versionDocObj as GeneratedDocJson,
this.props.docsInfo,
).convertToDocAgnosticFormat();
} else if (this.props.docsInfo.type === SupportedDocJson.Solidity) {
// documenting solidity.
docAgnosticFormat = versionDocObj as DocAgnosticFormat;
// need to modify docsInfo like convertToDocAgnosticFormat() would do
this.props.docsInfo.menu.Contracts = [];
_.each(docAgnosticFormat, (docObj, contractName) => {
this.props.docsInfo.sections[contractName] = contractName;
this.props.docsInfo.menu.Contracts.push(contractName);
});
}
if (!this._isUnmounted) {
this.setState({

View File

@@ -1,4 +1,4 @@
import { DoxityDocObj, GeneratedDocJson } from '@0xproject/react-docs';
import { DocAgnosticFormat, GeneratedDocJson } from '@0xproject/react-docs';
import { fetchAsync, logUtils } from '@0xproject/utils';
import * as _ from 'lodash';
import { S3FileObject, VersionToFilePath } from 'ts/types';
@@ -70,7 +70,7 @@ export const docUtils = {
});
return versionFilePaths;
},
async getJSONDocFileAsync(filePath: string, s3DocJsonRoot: string): Promise<GeneratedDocJson | DoxityDocObj> {
async getJSONDocFileAsync(filePath: string, s3DocJsonRoot: string): Promise<GeneratedDocJson | DocAgnosticFormat> {
const endpoint = `${s3DocJsonRoot}/${filePath}`;
const response = await fetchAsync(endpoint);
if (response.status !== 200) {