diff --git a/examples/contracts/Bar.sol b/examples/contracts/Bar.sol index 1c9c8c4..a4fd23b 100644 --- a/examples/contracts/Bar.sol +++ b/examples/contracts/Bar.sol @@ -21,11 +21,13 @@ interface IBar { /// @notice Emitted when transfer /// @dev Transfer some stuff /// @param foo Amount of stuff + /// @custom:danger This event exposes private info event Transfer(uint256 foo); /// @notice Thrown when doh /// @dev Bad doh error /// @param yay A bool + /// @custom:info Additional info error Doh(bool yay); } @@ -33,11 +35,14 @@ interface IBar { /// @author Primitive /// @notice Manages the bar /// @dev Blablou +/// @custom:version v2.0.1 contract Bar is IBar { /// @inheritdoc IBar function set(T memory t) external { } /// @notice Cool function bro + /// @custom:requirement Check first requirement + /// @custom:requirement Check second requirement function boop(uint256 bar) external { } /// @notice Alt cool function bro diff --git a/examples/docs/Bar.json b/examples/docs/Bar.json index f63e967..b491085 100644 --- a/examples/docs/Bar.json +++ b/examples/docs/Bar.json @@ -25,7 +25,8 @@ } }, "outputs": {}, - "notice": "Cool function bro" + "notice": "Cool function bro", + "custom:requirement": "Check first requirementCheck second requirement" }, "boop(uint256,uint256)": { "stateMutability": "nonpayable", @@ -74,7 +75,8 @@ } }, "notice": "Thrown when doh", - "details": "Bad doh error" + "details": "Bad doh error", + "custom:info": "Additional info" } }, "path": "", @@ -82,5 +84,6 @@ "notice": "Manages the bar", "details": "Blablou", "author": "Primitive", + "custom:version": "v2.0.1", "name": "Bar" } \ No newline at end of file diff --git a/examples/docs/Bar.md b/examples/docs/Bar.md index d5d9c54..53fe173 100644 --- a/examples/docs/Bar.md +++ b/examples/docs/Bar.md @@ -8,6 +8,8 @@ Manages the bar *Blablou* +**Version:** *v2.0.1* + ## Methods ### baap @@ -20,6 +22,8 @@ Baaps the yaps + + #### Parameters | Name | Type | Description | @@ -35,6 +39,8 @@ function boop(uint256 bar) external nonpayable Cool function bro +**Requirement:** *Check first requirementCheck second requirement* + #### Parameters @@ -53,6 +59,8 @@ Alt cool function bro + + #### Parameters | Name | Type | Description | @@ -70,6 +78,8 @@ function set(IBar.T t) external nonpayable + + #### Parameters | Name | Type | Description | @@ -90,6 +100,8 @@ Emitted when transfer + + #### Parameters | Name | Type | Description | @@ -107,9 +119,11 @@ error Doh(bool yay) ``` Thrown when doh - *Bad doh error* + +**Info:** *Additional info* + #### Parameters | Name | Type | Description | diff --git a/examples/docs/Foo.md b/examples/docs/Foo.md index 521495c..bf20b76 100644 --- a/examples/docs/Foo.md +++ b/examples/docs/Foo.md @@ -8,6 +8,8 @@ + + ## Methods ### nonces @@ -17,9 +19,11 @@ function nonces(address) external view returns (uint256) ``` Returns the nonce of an address - *Nonces much* + + + #### Parameters | Name | Type | Description | diff --git a/examples/docs/IBar.json b/examples/docs/IBar.json index 386b618..f73734f 100644 --- a/examples/docs/IBar.json +++ b/examples/docs/IBar.json @@ -32,7 +32,8 @@ } }, "notice": "Emitted when transfer", - "details": "Transfer some stuff" + "details": "Transfer some stuff", + "custom:danger": "This event exposes private info" } }, "errors": { @@ -45,7 +46,8 @@ } }, "notice": "Thrown when doh", - "details": "Bad doh error" + "details": "Bad doh error", + "custom:info": "Additional info" } }, "path": "", diff --git a/examples/docs/IBar.md b/examples/docs/IBar.md index 5d32d65..8c57f96 100644 --- a/examples/docs/IBar.md +++ b/examples/docs/IBar.md @@ -8,6 +8,8 @@ + + ## Methods ### boop @@ -20,6 +22,8 @@ function boop(uint256 bar) external nonpayable + + #### Parameters | Name | Type | Description | @@ -36,6 +40,8 @@ function set(IBar.T t) external nonpayable + + #### Parameters | Name | Type | Description | @@ -53,9 +59,11 @@ event Transfer(uint256 foo) ``` Emitted when transfer - *Transfer some stuff* +**Danger:** *This event exposes private info* + + #### Parameters | Name | Type | Description | @@ -73,9 +81,11 @@ error Doh(bool yay) ``` Thrown when doh - *Bad doh error* + +**Info:** *Additional info* + #### Parameters | Name | Type | Description | diff --git a/examples/docs/IExampleContract.md b/examples/docs/IExampleContract.md index 8cc1038..2a35fee 100644 --- a/examples/docs/IExampleContract.md +++ b/examples/docs/IExampleContract.md @@ -8,6 +8,8 @@ Put a simple description of the contract here. *And then a more complicated and tech oriented description of the contract there.* + + ## Methods ### anotherThing @@ -17,9 +19,11 @@ function anotherThing(uint256 num) external pure returns (uint256) ``` Does another thing when the function is called. - *More info about doing another thing when the function is called.* + + + #### Parameters | Name | Type | Description | @@ -43,6 +47,8 @@ Poorly documented function starting with weird spaces. + + #### Returns | Name | Type | Description | @@ -56,9 +62,11 @@ function doSomething(address a, uint256 b) external nonpayable returns (uint256 ``` Does something when this function is called. - *More info about the doSomething, and this even works when the explanation is on two lines.* + + + #### Parameters | Name | Type | Description | @@ -86,6 +94,8 @@ A bad documented payable function. + + ## Events ### DoSomething @@ -95,9 +105,11 @@ event DoSomething(address indexed a, uint256 b) ``` Emitted when the function doSomething is called. - *More info about the event can be added here.* + + + #### Parameters | Name | Type | Description | @@ -116,9 +128,11 @@ error RandomError(address expected, address actual) ``` Thrown when an error happens. - *More info about the error.* + + + #### Parameters | Name | Type | Description | diff --git a/examples/docs/IFoo.md b/examples/docs/IFoo.md index d5af430..cf80dd4 100644 --- a/examples/docs/IFoo.md +++ b/examples/docs/IFoo.md @@ -8,6 +8,8 @@ + + ## Methods ### nonces @@ -17,9 +19,11 @@ function nonces(address _0) external view returns (uint256) ``` Returns the nonce of an address - *Nonces much* + + + #### Parameters | Name | Type | Description | diff --git a/examples/docs/subfolder/AnotherContract.md b/examples/docs/subfolder/AnotherContract.md index efe9924..498d8a8 100644 --- a/examples/docs/subfolder/AnotherContract.md +++ b/examples/docs/subfolder/AnotherContract.md @@ -8,6 +8,8 @@ + + ## Methods ### tip @@ -17,9 +19,11 @@ function tip(uint256 much, address mop) external nonpayable ``` A strange function - *Someone wrote this weird function...* + + + #### Parameters | Name | Type | Description | diff --git a/src/dodocTypes.ts b/src/dodocTypes.ts index 40df0e8..e8d91fc 100644 --- a/src/dodocTypes.ts +++ b/src/dodocTypes.ts @@ -1,147 +1,157 @@ -import { CompilerOutputContract } from 'hardhat/types'; +import { CompilerOutputContract } from "hardhat/types"; + +export type CustomTag = `custom:${T}`; export interface ErrorDevdocArrayItem { - details?: string; - params?: { - [key: string]: string; - } + details?: string; + params?: { + [key: string]: string; + }; + [key: CustomTag]: string } declare interface ErrorUserdocArrayItem { - notice?: string; + notice?: string; } export interface CompilerOutputContractWithDocumentation extends CompilerOutputContract { - devdoc?: { - author?: string; - details?: string; - title?: string; - errors?: { - [key: string]: ErrorDevdocArrayItem[] - } - events?: { - [key: string]: { - details: string; - params: { - [key: string]: string; - } - } - } - methods?: { - [key: string]: { - details?: string; - params: { - [key: string]: string; - }, - returns: { - [key: string]: string; - } - } - }, - returns?: { - [key: string]: { - details?: string; - params: { - [key: string]: string; - } - } - } - stateVariables?: { - [key: string]: { + devdoc?: { + author?: string; details?: string; - params: { - [key: string]: string; - } - returns: { - [key: string]: string; - } - } - } - }, - userdoc?: { - errors?: { - [key: string]: ErrorUserdocArrayItem[] - }, - events?: { - [key: string]: { - notice: string; - }, - }, - methods?: { - [key: string]: { - notice: string; - }, - }, - notice?: string; - } + title?: string; + errors?: { + [key: string]: ErrorDevdocArrayItem[]; + }; + events?: { + [key: string]: { + details: string; + params: { + [key: string]: string; + }; + [key: CustomTag]: string + }; + }; + methods?: { + [key: string]: { + details?: string; + params: { + [key: string]: string; + }; + returns: { + [key: string]: string; + }; + [key: CustomTag]: string + }; + }; + returns?: { + [key: string]: { + details?: string; + params: { + [key: string]: string; + }; + }; + }; + stateVariables?: { + [key: string]: { + details?: string; + params: { + [key: string]: string; + }; + returns: { + [key: string]: string; + }; + }; + }; + [key: CustomTag]: string; + }; + userdoc?: { + errors?: { + [key: string]: ErrorUserdocArrayItem[]; + }; + events?: { + [key: string]: { + notice: string; + }; + }; + methods?: { + [key: string]: { + notice: string; + }; + }; + notice?: string; + }; } export interface AbiElementPut { - internalType: string; - name: string; - type: string; - indexed?: boolean; + internalType: string; + name: string; + type: string; + indexed?: boolean; } export interface AbiElement { - type: 'constructor' | 'function' | 'event' | 'error'; - name: string; - stateMutability?: string; - inputs: AbiElementPut[]; - outputs: AbiElementPut[]; + type: 'constructor' | 'function' | 'event' | 'error'; + name: string; + stateMutability?: string; + inputs: AbiElementPut[]; + outputs: AbiElementPut[]; } export interface Param { - type?: string; - description?: string; - indexed?: boolean; + type?: string; + description?: string; + indexed?: boolean; } export interface Method { - code?: string; - stateMutability?: string; - notice?: string; - details?: string; - inputs: { - [key: string]: Param; - } - outputs: { - [key: string]: Param; - } + code?: string; + stateMutability?: string; + notice?: string; + details?: string; + inputs: { + [key: string]: Param; + }; + outputs: { + [key: string]: Param; + }; + [key: CustomTag]: string } export interface Event { - code?: string; - notice?: string; - details?: string; - inputs: { - [key: string]: Param; - } + code?: string; + notice?: string; + details?: string; + inputs: { + [key: string]: Param; + }; + [key: CustomTag]: string } export interface Error { - code?: string; - description?: string; - details?: string; - inputs: { - [key: string]: Param; - } + code?: string; + notice?: string; + details?: string; + inputs: { + [key: string]: Param; + }; + [key: CustomTag]: string } export interface Doc { - path?: string; - name?: string; - title?: string; - notice?: string; - details?: string; - author?: string; - methods: { - [key: string]: Method; - } - events: { - [key: string]: Event; - } - errors: { - [key: string]: Event; - } + path?: string; + name?: string; + title?: string; + notice?: string; + details?: string; + author?: string; + [key: CustomTag]: string; + methods: { + [key: string]: Method; + }; + events: { + [key: string]: Event; + }; + errors: { + [key: string]: Error; + }; } diff --git a/src/index.ts b/src/index.ts index 56c4b08..2ee2af3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -62,7 +62,7 @@ async function generateDocumentation( console.log(JSON.stringify(info.devdoc, null, 4)); } - const doc = { ...decodeAbi(info.abi), path: source.substr(sourcesPath.length).split('/').slice(0, -1).join('/') }; // get file path without filename + const doc: Doc = { ...decodeAbi(info.abi), path: source.substr(sourcesPath.length).split('/').slice(0, -1).join('/') }; // get file path without filename // Fetches info from userdoc for (const errorSig in info.userdoc?.errors) { @@ -96,6 +96,15 @@ async function generateDocumentation( for (const param in error?.params) { if (doc.errors[errorName].inputs[param]) doc.errors[errorName].inputs[param].description = error?.params[param]; } + + for (const value in error) { + if (value.startsWith('custom:')) { + const strippedValue = value.substring(7); + if (strippedValue.length > 0) { + doc.errors[errorName][`custom:${strippedValue}`] = error[`custom:${strippedValue}`]; + } + } + } } for (const eventSig in info.devdoc?.events) { @@ -107,6 +116,15 @@ async function generateDocumentation( for (const param in event?.params) { if (doc.events[eventName].inputs[param]) doc.events[eventName].inputs[param].description = event?.params[param]; } + + for (const value in event) { + if (value.startsWith('custom:')) { + const strippedValue = value.substring(7); + if (strippedValue.length > 0) { + doc.events[eventName][`custom:${strippedValue}`] = event[`custom:${strippedValue}`]; + } + } + } } for (const methodSig in info.devdoc?.methods) { @@ -124,6 +142,15 @@ async function generateDocumentation( if (doc.methods[methodSig].outputs[output]) doc.methods[methodSig].outputs[output].description = method?.returns[output]; } } + + for (const value in method) { + if (value.startsWith('custom:')) { + const strippedValue = value.substring(7); + if (strippedValue.length > 0) { + doc.methods[methodSig][`custom:${strippedValue}`] = method[`custom:${strippedValue}`]; + } + } + } } for (const varName in info.devdoc?.stateVariables) { @@ -151,6 +178,15 @@ async function generateDocumentation( if (info.devdoc?.details) doc.details = info.devdoc.details; if (info.devdoc?.author) doc.author = info.devdoc.author; + for (const value in info.devdoc) { + if (value.startsWith('custom:')) { + const strippedValue = value.substring(7); + if (strippedValue.length > 0) { + doc[`custom:${strippedValue}`] = info.devdoc[`custom:${strippedValue}`]; + } + } + } + doc.name = name; docs.push(doc); } diff --git a/src/template.sqrl b/src/template.sqrl index 0c263db..15e3a20 100644 --- a/src/template.sqrl +++ b/src/template.sqrl @@ -13,6 +13,9 @@ {{@if (it.details)}}*{{it.details}}*{{/if}} +{{@if (it['custom:version'])}}**Version:** *{{it['custom:version']}}*{{/if}} + + {{@if (Object.keys(it.methods).length > 0)}} ## Methods @@ -27,9 +30,14 @@ {{@if (val.notice)}}{{val.notice}}{{/if}} - {{@if (val.details)}}*{{val.details}}*{{/if}} +{{@if (val['custom:requirement'])}}**Requirement:** *{{val['custom:requirement']}}*{{/if}} + +{{@if (val['custom:danger'])}}**Danger:** *{{val['custom:danger']}}*{{/if}} + +{{@if (val['custom:info'])}}**Info:** *{{val['custom:info']}}*{{/if}} + {{@if (Object.keys(val.inputs).length > 0)}} #### Parameters @@ -69,9 +77,14 @@ {{@if (val.notice)}}{{val.notice}}{{/if}} - {{@if (val.details)}}*{{val.details}}*{{/if}} +{{@if (val['custom:requirement'])}}**Requirement:** *{{val['custom:requirement']}}*{{/if}} + +{{@if (val['custom:danger'])}}**Danger:** *{{val['custom:danger']}}*{{/if}} + +{{@if (val['custom:info'])}}**Info:** *{{val['custom:info']}}*{{/if}} + {{@if (Object.keys(val.inputs).length > 0)}} #### Parameters @@ -101,9 +114,14 @@ {{@if (val.notice)}}{{val.notice}}{{/if}} - {{@if (val.details)}}*{{val.details}}*{{/if}} +{{@if (val['custom:requirement'])}}**Requirement:** *{{val['custom:requirement']}}*{{/if}} + +{{@if (val['custom:danger'])}}**Danger:** *{{val['custom:danger']}}*{{/if}} + +{{@if (val['custom:info'])}}**Info:** *{{val['custom:info']}}*{{/if}} + {{@if (Object.keys(val.inputs).length > 0)}} #### Parameters