├── .nvmrc ├── src ├── xss.d.ts ├── config.ts ├── specVersions │ ├── v0.0 │ │ ├── WrapVariable.ts │ │ ├── RicardianContext.ts │ │ ├── index.ts │ │ ├── RicardianContract.smoke.test.ts │ │ ├── validators.ts │ │ ├── VariableWrapper.test.ts │ │ ├── whitelist.ts │ │ ├── VariableWrapper.ts │ │ ├── helpers.ts │ │ ├── validators.test.ts │ │ ├── helpers.test.ts │ │ ├── testfixtures │ │ │ └── jscore-fixtures.ts │ │ └── RicardianContractProcessorImpl.ts │ ├── v0.1 │ │ ├── index.ts │ │ ├── helpers.ts │ │ ├── RicardianContractProcessorImpl.ts │ │ ├── RicardianContractProcessorImpl.test.ts │ │ └── helpers.test.ts │ └── v0.2 │ │ ├── index.ts │ │ ├── helpers.ts │ │ ├── RicardianContractProcessorImpl.ts │ │ ├── helpers.test.ts │ │ └── RicardianContractProcessorImpl.test.ts ├── index.ts ├── RicardianContractRenderError.test.ts ├── RicardianContractFactory.test.ts ├── RicardianContractRenderError.ts ├── factoryHelpers.ts ├── RicardianContractFactory.ts ├── utils │ ├── contractUtils.test.ts │ └── contractUtils.ts ├── interfaces.ts ├── bin │ └── rc.ts ├── factoryHelpers.test.ts └── testfixtures │ └── fixtures.ts ├── bin └── rc ├── .images └── styled-example.png ├── index.js ├── .gitignore ├── tsconfig.webpack.json ├── tslint.json ├── .npmignore ├── docs ├── modules │ ├── _ricardiancontractfactory_.md │ ├── _specversions_v0_0_variablewrapper_.md │ ├── _specversions_v0_0_ricardiancontext_.md │ ├── _config_.md │ ├── _ricardiancontractrendererror_.md │ ├── _specversions_v0_2_helpers_.md │ ├── _specversions_v0_1_helpers_.md │ ├── _interfaces_.md │ ├── _specversions_v0_0_wrapvariable_.md │ ├── _specversions_v0_1_ricardiancontractprocessorimpl_.md │ ├── _specversions_v0_2_ricardiancontractprocessorimpl_.md │ ├── _specversions_v0_0_ricardiancontractprocessorimpl_.md │ ├── _bin_rc_.md │ ├── _specversions_v0_0_validators_.md │ ├── _factoryhelpers_.md │ ├── _utils_contractutils_.md │ └── _specversions_v0_0_helpers_.md ├── interfaces │ ├── _interfaces_.ricardianclause.md │ ├── _specversions_v0_1_helpers_.asset.md │ ├── _interfaces_.transactionactionauthorization.md │ ├── _interfaces_.ricardiancontract.md │ ├── _ricardiancontractrendererror_.htmlvalidationerrorargs.md │ ├── _interfaces_.specversion.md │ ├── _interfaces_.abiaction.md │ ├── _interfaces_.contractmetadata.md │ ├── _specversions_v0_0_ricardiancontext_.ricardiancontext.md │ ├── _interfaces_.transactionaction.md │ ├── _interfaces_.abi.md │ ├── _interfaces_.ricardiancontractprocessor.md │ ├── _interfaces_.ricardiancontractconfig.md │ └── _interfaces_.transaction.md ├── classes │ ├── _ricardiancontractfactory_.ricardiancontractfactory.md │ ├── _ricardiancontractrendererror_.ricardiancontractrendererror.md │ ├── _specversions_v0_0_variablewrapper_.variablewrapper.md │ ├── _specversions_v0_2_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md │ └── _specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md └── README.md ├── jest.config.js ├── index-simple.js ├── index-complex.js ├── webpack.jscore.config.js ├── .github └── PULL_REQUEST_TEMPLATE.md ├── webpack.web.config.js ├── .travis.yml ├── LICENSE ├── examples ├── transaction.json └── abi.json ├── package.json ├── tsconfig.json ├── README.md └── CONTRIBUTING.md /.nvmrc: -------------------------------------------------------------------------------- 1 | 10.15.0 -------------------------------------------------------------------------------- /src/xss.d.ts: -------------------------------------------------------------------------------- 1 | declare module "xss" 2 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | export const MAX_PASSES = 3 2 | -------------------------------------------------------------------------------- /bin/rc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | let CLI = require('../dist/bin/rc.js') 4 | 5 | CLI.run() 6 | -------------------------------------------------------------------------------- /.images/styled-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EOSIO/ricardian-template-toolkit/HEAD/.images/styled-example.png -------------------------------------------------------------------------------- /src/specVersions/v0.0/WrapVariable.ts: -------------------------------------------------------------------------------- 1 | export type WrapVariable = (prefix: string, classname: string, variable: string, suffix: string) => string 2 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require("./index-simple") 2 | 3 | console.log("***********************************************************") 4 | 5 | require("./index-complex") 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | npm-debug.log* 3 | coverage 4 | lib 5 | node_modules 6 | .npm 7 | .idea 8 | .DS_Store 9 | .vscode 10 | dist 11 | dist-esm 12 | _bundles -------------------------------------------------------------------------------- /src/specVersions/v0.0/RicardianContext.ts: -------------------------------------------------------------------------------- 1 | export interface RicardianContext { 2 | $transaction: any 3 | $action: any 4 | $clauses: any 5 | [x: string]: any 6 | } 7 | -------------------------------------------------------------------------------- /src/specVersions/v0.0/index.ts: -------------------------------------------------------------------------------- 1 | import { RicardianContractProcessorImpl } from './RicardianContractProcessorImpl' 2 | 3 | export default RicardianContractProcessorImpl 4 | -------------------------------------------------------------------------------- /src/specVersions/v0.1/index.ts: -------------------------------------------------------------------------------- 1 | import { RicardianContractProcessorImpl } from './RicardianContractProcessorImpl' 2 | 3 | export default RicardianContractProcessorImpl 4 | -------------------------------------------------------------------------------- /src/specVersions/v0.2/index.ts: -------------------------------------------------------------------------------- 1 | import { RicardianContractProcessorImpl } from './RicardianContractProcessorImpl' 2 | 3 | export default RicardianContractProcessorImpl 4 | -------------------------------------------------------------------------------- /tsconfig.webpack.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "compilerOptions": { 4 | "sourceMap": true 5 | }, 6 | "exclude": [ 7 | "**/*.test.ts", 8 | "src/testfixtures", 9 | "node_modules" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /src/specVersions/v0.2/helpers.ts: -------------------------------------------------------------------------------- 1 | export const ifHasValue = function(this: any, val: any, options: Handlebars.HelperOptions) { 2 | const defined = (typeof val !== 'undefined') && (val !== null) 3 | if (defined) { 4 | return options.fn(this) 5 | } else { 6 | return options.inverse(this) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { ContractMetadata, RicardianContract, RicardianContractConfig } from './interfaces' 2 | import { RicardianContractFactory } from './RicardianContractFactory' 3 | 4 | export { 5 | RicardianContractFactory, 6 | ContractMetadata, 7 | RicardianContract, 8 | RicardianContractConfig, 9 | } 10 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "@blockone/tslint-config-blockone/tslint-config" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | }, 9 | "rulesDirectory": [], 10 | "linterOptions": { 11 | "exclude": [ 12 | "src/**/templates/", 13 | "**/*.js" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Exclude all files by default 2 | * 3 | 4 | # Include distribution bundle but exclude test files if they are built into dist 5 | !dist/** 6 | !bin/** 7 | *.test.* 8 | testfixtures 9 | 10 | # Include any additional source files which should be bundled 11 | 12 | 13 | # Include documentation and version information in bundle 14 | !CONTRIBUTING.md 15 | -------------------------------------------------------------------------------- /docs/modules/_ricardiancontractfactory_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["RicardianContractFactory"](../modules/_ricardiancontractfactory_.md) 2 | 3 | # External module: "RicardianContractFactory" 4 | 5 | ## Index 6 | 7 | ### Classes 8 | 9 | * [RicardianContractFactory](../classes/_ricardiancontractfactory_.ricardiancontractfactory.md) 10 | 11 | --- 12 | 13 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | roots: [ 3 | '/src', 4 | ], 5 | transform: { 6 | '^.+\\.ts?$': 'ts-jest', 7 | }, 8 | testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.ts?$', 9 | moduleFileExtensions: [ 10 | 'ts', 11 | 'js', 12 | 'json', 13 | 'node', 14 | ], 15 | coverageReporters: [ 16 | 'text', 17 | 'json-summary', 18 | ], 19 | } 20 | -------------------------------------------------------------------------------- /docs/modules/_specversions_v0_0_variablewrapper_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["specVersions/v0.0/VariableWrapper"](../modules/_specversions_v0_0_variablewrapper_.md) 2 | 3 | # External module: "specVersions/v0.0/VariableWrapper" 4 | 5 | ## Index 6 | 7 | ### Classes 8 | 9 | * [VariableWrapper](../classes/_specversions_v0_0_variablewrapper_.variablewrapper.md) 10 | 11 | --- 12 | 13 | -------------------------------------------------------------------------------- /docs/modules/_specversions_v0_0_ricardiancontext_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["specVersions/v0.0/RicardianContext"](../modules/_specversions_v0_0_ricardiancontext_.md) 2 | 3 | # External module: "specVersions/v0.0/RicardianContext" 4 | 5 | ## Index 6 | 7 | ### Interfaces 8 | 9 | * [RicardianContext](../interfaces/_specversions_v0_0_ricardiancontext_.ricardiancontext.md) 10 | 11 | --- 12 | 13 | -------------------------------------------------------------------------------- /docs/modules/_config_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["config"](../modules/_config_.md) 2 | 3 | # External module: "config" 4 | 5 | ## Index 6 | 7 | ### Variables 8 | 9 | * [MAX_PASSES](_config_.md#max_passes) 10 | 11 | --- 12 | 13 | ## Variables 14 | 15 | 16 | 17 | ### `` MAX_PASSES 18 | 19 | **● MAX_PASSES**: *`3`* = 3 20 | 21 | *Defined in [config.ts:1](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/config.ts#L1)* 22 | 23 | ___ 24 | 25 | -------------------------------------------------------------------------------- /docs/modules/_ricardiancontractrendererror_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["RicardianContractRenderError"](../modules/_ricardiancontractrendererror_.md) 2 | 3 | # External module: "RicardianContractRenderError" 4 | 5 | ## Index 6 | 7 | ### Classes 8 | 9 | * [RicardianContractRenderError](../classes/_ricardiancontractrendererror_.ricardiancontractrendererror.md) 10 | 11 | ### Interfaces 12 | 13 | * [HtmlValidationErrorArgs](../interfaces/_ricardiancontractrendererror_.htmlvalidationerrorargs.md) 14 | 15 | --- 16 | 17 | -------------------------------------------------------------------------------- /src/specVersions/v0.1/helpers.ts: -------------------------------------------------------------------------------- 1 | import { RicardianContractRenderError } from '../../RicardianContractRenderError' 2 | 3 | export interface Asset { 4 | amount: string, 5 | symbol: string 6 | } 7 | 8 | export const parseAsset = (asset: string): Asset => { 9 | const assetMatch = /^((\d+\.)?\d+) +([A-Z]+)$/ 10 | const match = assetMatch.exec(asset) 11 | if (match) { 12 | return { 13 | amount: match[1], 14 | symbol: match[3], 15 | } 16 | } 17 | 18 | throw new RicardianContractRenderError(`Unable to parse '${asset}' as an asset string`) 19 | } 20 | -------------------------------------------------------------------------------- /src/specVersions/v0.1/RicardianContractProcessorImpl.ts: -------------------------------------------------------------------------------- 1 | import { RicardianContractProcessorImpl as RCP_0_0 } from '../v0.0/RicardianContractProcessorImpl' 2 | import { parseAsset } from './helpers' 3 | 4 | const implVersion = { 5 | major: 0, 6 | minor: 1, 7 | } 8 | 9 | export class RicardianContractProcessorImpl extends RCP_0_0 { 10 | constructor() { 11 | super() 12 | 13 | this.registerWrappedHelper('amount_from_asset', (asset: string): string => { 14 | return parseAsset(asset).amount 15 | }) 16 | } 17 | 18 | public getSpecVersion() { 19 | return implVersion 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /index-simple.js: -------------------------------------------------------------------------------- 1 | const { RicardianContractFactory } = require('./dist/RicardianContractFactory') 2 | const { eosioTokenAbi, transferTransaction } = require('./dist/testfixtures/fixtures') 3 | 4 | const transaction = JSON.parse(transferTransaction) 5 | const abi = JSON.parse(eosioTokenAbi) 6 | 7 | /* eslint-disable no-console */ 8 | const factory = new RicardianContractFactory() 9 | const rc = factory.create({ 10 | abi, 11 | transaction, 12 | actionIndex: 0, 13 | }) 14 | 15 | console.log('\n\n***** Simple Transfer Example *****') 16 | console.log('\n\n~~~~~METADATA~~~~~') 17 | console.log(rc.getMetadata()) 18 | console.log('\n\n~~~~~HTML~~~~~') 19 | console.log(rc.getHtml()) 20 | -------------------------------------------------------------------------------- /index-complex.js: -------------------------------------------------------------------------------- 1 | const { RicardianContractFactory } = require('./dist/RicardianContractFactory') 2 | const { complexEosioTokenAbi, complexTransferTransaction } = require('./dist/testfixtures/complex-fixtures') 3 | 4 | const complexTransaction = JSON.parse(complexTransferTransaction) 5 | const complexAbi = JSON.parse(complexEosioTokenAbi) 6 | 7 | const factory = new RicardianContractFactory() 8 | const complexRc = factory.create({ 9 | abi: complexAbi, 10 | transaction: complexTransaction, 11 | actionIndex: 0, 12 | }) 13 | 14 | console.log('\n\n***** Complex Multi-Transfer Example *****') 15 | console.log('\n\n~~~~~METADATA~~~~~') 16 | console.log(complexRc.getMetadata()) 17 | console.log('\n\n~~~~~HTML~~~~~') 18 | console.log(complexRc.getHtml()) -------------------------------------------------------------------------------- /src/specVersions/v0.2/RicardianContractProcessorImpl.ts: -------------------------------------------------------------------------------- 1 | import * as Handlebars from 'handlebars' 2 | import { ifHasValue } from './helpers' 3 | 4 | import { RicardianContractProcessorImpl as RCP_0_1 } from '../v0.1/RicardianContractProcessorImpl' 5 | 6 | const implVersion = { 7 | major: 0, 8 | minor: 2, 9 | } 10 | 11 | export class RicardianContractProcessorImpl extends RCP_0_1 { 12 | 13 | constructor() { 14 | super() 15 | 16 | this.registerHelper('to_json', (obj: string) => { 17 | return new Handlebars.SafeString('```\n' + JSON.stringify(obj, null, 2) + '\n```') 18 | }) 19 | 20 | this.registerHelper('if_has_value', ifHasValue ) 21 | } 22 | 23 | public getSpecVersion() { 24 | return implVersion 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /webpack.jscore.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | // Inspiration: https://marcobotto.com/blog/compiling-and-bundling-typescript-libraries-with-webpack/ 3 | 4 | module.exports = { 5 | mode: 'production', 6 | entry: { 7 | 'contract-template-toolkit': './src/index.ts', 8 | }, 9 | output: { 10 | path: path.resolve(__dirname, '_bundles', 'jscore'), 11 | filename: '[name].js', 12 | libraryTarget: 'var', 13 | library: 'ContractTemplateToolkit', 14 | }, 15 | resolve: { 16 | extensions: ['.ts', '.js'], 17 | alias: { 18 | // https://github.com/wycats/handlebars.js/issues/1174#issuecomment-229918935 19 | handlebars: 'handlebars/dist/handlebars.min.js', 20 | }, 21 | }, 22 | module: { 23 | rules: [{ 24 | test: /\.ts?$/, 25 | loader: 'ts-loader?configFile=tsconfig.webpack.json', 26 | }], 27 | }, 28 | } 29 | -------------------------------------------------------------------------------- /docs/modules/_specversions_v0_2_helpers_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["specVersions/v0.2/helpers"](../modules/_specversions_v0_2_helpers_.md) 2 | 3 | # External module: "specVersions/v0.2/helpers" 4 | 5 | ## Index 6 | 7 | ### Functions 8 | 9 | * [ifHasValue](_specversions_v0_2_helpers_.md#ifhasvalue) 10 | 11 | --- 12 | 13 | ## Functions 14 | 15 | 16 | 17 | ### `` ifHasValue 18 | 19 | ▸ **ifHasValue**(this: *`any`*, val: *`any`*, options: *`HelperOptions`*): `string` 20 | 21 | *Defined in [specVersions/v0.2/helpers.ts:1](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.2/helpers.ts#L1)* 22 | 23 | **Parameters:** 24 | 25 | | Name | Type | 26 | | ------ | ------ | 27 | | this | `any` | 28 | | val | `any` | 29 | | options | `HelperOptions` | 30 | 31 | **Returns:** `string` 32 | 33 | ___ 34 | 35 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## Change Description 5 | 6 | 7 | 8 | ## API Changes 9 | - [ ] API Changes 10 | 11 | 12 | 13 | 14 | ## Documentation Additions 15 | - [ ] Documentation Additions 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/interfaces/_interfaces_.ricardianclause.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["interfaces"](../modules/_interfaces_.md) > [RicardianClause](../interfaces/_interfaces_.ricardianclause.md) 2 | 3 | # Interface: RicardianClause 4 | 5 | ## Hierarchy 6 | 7 | **RicardianClause** 8 | 9 | ## Index 10 | 11 | ### Properties 12 | 13 | * [body](_interfaces_.ricardianclause.md#body) 14 | * [id](_interfaces_.ricardianclause.md#id) 15 | 16 | --- 17 | 18 | ## Properties 19 | 20 | 21 | 22 | ### body 23 | 24 | **● body**: *`string`* 25 | 26 | *Defined in [interfaces.ts:3](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L3)* 27 | 28 | ___ 29 | 30 | 31 | ### id 32 | 33 | **● id**: *`string`* 34 | 35 | *Defined in [interfaces.ts:2](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L2)* 36 | 37 | ___ 38 | 39 | -------------------------------------------------------------------------------- /src/RicardianContractRenderError.test.ts: -------------------------------------------------------------------------------- 1 | import { RicardianContractRenderError } from './RicardianContractRenderError' 2 | 3 | describe('RicardianContractRenderError', () => { 4 | it('constructs message from string properly', () => { 5 | const expected = 'Danger, Will Robinson!' 6 | const error = new RicardianContractRenderError(expected) 7 | expect(error.message).toEqual(expected) 8 | expect(error.tag).toBeNull() 9 | expect(error.reason).toBeNull() 10 | }) 11 | 12 | it('constructs message from HtmlValidationErrorArgs properly', () => { 13 | const tag = 'body' 14 | const reason = `"${tag}" tag is present` 15 | const error = new RicardianContractRenderError({ tag, reason }) 16 | expect(error.message) 17 | .toEqual(`Invalid or unexpected HTML found near "${tag}" tag. Reason: ${reason}`) 18 | expect(error.tag).toEqual(tag) 19 | expect(error.reason).toEqual(reason) 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /webpack.web.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | // Inspiration: https://marcobotto.com/blog/compiling-and-bundling-typescript-libraries-with-webpack/ 3 | 4 | module.exports = { 5 | mode: 'production', 6 | devtool: 'source-map', 7 | entry: { 8 | 'contract-template-toolkit': './src/index.ts', 9 | }, 10 | output: { 11 | path: path.resolve(__dirname, '_bundles', 'web'), 12 | filename: '[name].js', 13 | libraryTarget: 'umd', 14 | library: 'ContractTemplateToolkit', 15 | umdNamedDefine: true, 16 | }, 17 | resolve: { 18 | extensions: ['.ts', '.js'], 19 | alias: { 20 | // https://github.com/wycats/handlebars.js/issues/1174#issuecomment-229918935 21 | handlebars: 'handlebars/dist/handlebars.min.js', 22 | }, 23 | }, 24 | module: { 25 | rules: [{ 26 | test: /\.tsx?$/, 27 | loader: 'ts-loader?configFile=tsconfig.webpack.json', 28 | }], 29 | }, 30 | } 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - '10.0.0' 5 | stages: 6 | - test 7 | jobs: 8 | include: 9 | - stage: test 10 | name: "Lint and Test" 11 | script: 12 | - yarn lint 13 | - yarn test 14 | notifications: 15 | webhooks: 16 | secure: "TyaFBYKarAvweyzIcslt37+3oVkRO0nb5RsDsWW/dpm8fzaenwZl/AF/YSC51XF9VVacEISBn/cBxzPsiZgSDJF8/xmjPdBBHcceBuMkLGVLG18eeKDFbb5Ao595CrfdT5ncjAj/VwuHLp4ZvS/9DhXRV8/NnL24WM69jyNA11uTKkAWWs3SzHAIjZppLJGkZG/2joI38v1jxqFe1+kmjXqyGSUjVR+fum0t1Ez3F+dzeggwwL3jIpSuP8fl9chvRmcb3+fFGMrLV82sYL6CKv4vgGygE9dg4tlhy/FnXguLJ6DgSZy6m9IYzapDA82qLWixPCERVRpjC4FSDxvasVIr2dpETfmVhVop0NDRkIwoKjIJtudx+YhM6Aw+kTJFqUXPuwHuwZHybjmvlvX1DnMUQ/tGk99oGpAOCHzuybfHFLNPKT+bEwS7VhM3FEHd5/ldWSq/ncibdAq1ZGtwkYQtUNgw6YULgx6AXLvZL8+g6UbqJzZUGGsGAstuCGPt3Wlvt2qcdQ5sis9EGem61ZJzB+qR4qT24I5G2+WoSmC/LG58bylXJOnhTIM8QChgV/3HJbM56lI46ckt39NjCPWOuI0ar2oajeqaBhLrto+Ra3UhY4jCCixWKRL3NqInfFz2JmX8Q8CjvDYlBxuD8I3Bf4ScF1DjwdCIEfIz9/8=" 17 | -------------------------------------------------------------------------------- /src/RicardianContractFactory.test.ts: -------------------------------------------------------------------------------- 1 | import { RicardianContractFactory } from './RicardianContractFactory' 2 | import { 3 | complexEosioTokenAbi, 4 | complexExpectedHtml, 5 | complexExpectedMetadata, 6 | complexTransferTransaction, 7 | } from './testfixtures/complex-fixtures' 8 | 9 | const complexMetadata = JSON.parse(complexExpectedMetadata) 10 | const complexTransaction = JSON.parse(complexTransferTransaction) 11 | const complexAbi = JSON.parse(complexEosioTokenAbi) 12 | 13 | describe('RicardianContractFactory', () => { 14 | 15 | it('successfully selects processor to create RicardianContract', () => { 16 | const factory = new RicardianContractFactory() 17 | const complexRc = factory.create({ 18 | abi: complexAbi, 19 | transaction: complexTransaction, 20 | actionIndex: 0, 21 | }) 22 | expect(complexRc.getMetadata()).toEqual(complexMetadata) 23 | expect(complexRc.getHtml()).toEqual(complexExpectedHtml) 24 | }) 25 | }) 26 | -------------------------------------------------------------------------------- /docs/modules/_specversions_v0_1_helpers_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["specVersions/v0.1/helpers"](../modules/_specversions_v0_1_helpers_.md) 2 | 3 | # External module: "specVersions/v0.1/helpers" 4 | 5 | ## Index 6 | 7 | ### Interfaces 8 | 9 | * [Asset](../interfaces/_specversions_v0_1_helpers_.asset.md) 10 | 11 | ### Functions 12 | 13 | * [parseAsset](_specversions_v0_1_helpers_.md#parseasset) 14 | 15 | --- 16 | 17 | ## Functions 18 | 19 | 20 | 21 | ### `` parseAsset 22 | 23 | ▸ **parseAsset**(asset: *`string`*): [Asset](../interfaces/_specversions_v0_1_helpers_.asset.md) 24 | 25 | *Defined in [specVersions/v0.1/helpers.ts:8](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.1/helpers.ts#L8)* 26 | 27 | **Parameters:** 28 | 29 | | Name | Type | 30 | | ------ | ------ | 31 | | asset | `string` | 32 | 33 | **Returns:** [Asset](../interfaces/_specversions_v0_1_helpers_.asset.md) 34 | 35 | ___ 36 | 37 | -------------------------------------------------------------------------------- /docs/interfaces/_specversions_v0_1_helpers_.asset.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["specVersions/v0.1/helpers"](../modules/_specversions_v0_1_helpers_.md) > [Asset](../interfaces/_specversions_v0_1_helpers_.asset.md) 2 | 3 | # Interface: Asset 4 | 5 | ## Hierarchy 6 | 7 | **Asset** 8 | 9 | ## Index 10 | 11 | ### Properties 12 | 13 | * [amount](_specversions_v0_1_helpers_.asset.md#amount) 14 | * [symbol](_specversions_v0_1_helpers_.asset.md#symbol) 15 | 16 | --- 17 | 18 | ## Properties 19 | 20 | 21 | 22 | ### amount 23 | 24 | **● amount**: *`string`* 25 | 26 | *Defined in [specVersions/v0.1/helpers.ts:4](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.1/helpers.ts#L4)* 27 | 28 | ___ 29 | 30 | 31 | ### symbol 32 | 33 | **● symbol**: *`string`* 34 | 35 | *Defined in [specVersions/v0.1/helpers.ts:5](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.1/helpers.ts#L5)* 36 | 37 | ___ 38 | 39 | -------------------------------------------------------------------------------- /docs/modules/_interfaces_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["interfaces"](../modules/_interfaces_.md) 2 | 3 | # External module: "interfaces" 4 | 5 | ## Index 6 | 7 | ### Interfaces 8 | 9 | * [Abi](../interfaces/_interfaces_.abi.md) 10 | * [AbiAction](../interfaces/_interfaces_.abiaction.md) 11 | * [ContractMetadata](../interfaces/_interfaces_.contractmetadata.md) 12 | * [RicardianClause](../interfaces/_interfaces_.ricardianclause.md) 13 | * [RicardianContract](../interfaces/_interfaces_.ricardiancontract.md) 14 | * [RicardianContractConfig](../interfaces/_interfaces_.ricardiancontractconfig.md) 15 | * [RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md) 16 | * [SpecVersion](../interfaces/_interfaces_.specversion.md) 17 | * [Transaction](../interfaces/_interfaces_.transaction.md) 18 | * [TransactionAction](../interfaces/_interfaces_.transactionaction.md) 19 | * [TransactionActionAuthorization](../interfaces/_interfaces_.transactionactionauthorization.md) 20 | 21 | --- 22 | 23 | -------------------------------------------------------------------------------- /docs/modules/_specversions_v0_0_wrapvariable_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["specVersions/v0.0/WrapVariable"](../modules/_specversions_v0_0_wrapvariable_.md) 2 | 3 | # External module: "specVersions/v0.0/WrapVariable" 4 | 5 | ## Index 6 | 7 | ### Type aliases 8 | 9 | * [WrapVariable](_specversions_v0_0_wrapvariable_.md#wrapvariable) 10 | 11 | --- 12 | 13 | ## Type aliases 14 | 15 | 16 | 17 | ### WrapVariable 18 | 19 | **Ƭ WrapVariable**: *`function`* 20 | 21 | *Defined in [specVersions/v0.0/WrapVariable.ts:1](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/WrapVariable.ts#L1)* 22 | 23 | #### Type declaration 24 | ▸(prefix: *`string`*, classname: *`string`*, variable: *`string`*, suffix: *`string`*): `string` 25 | 26 | **Parameters:** 27 | 28 | | Name | Type | 29 | | ------ | ------ | 30 | | prefix | `string` | 31 | | classname | `string` | 32 | | variable | `string` | 33 | | suffix | `string` | 34 | 35 | **Returns:** `string` 36 | 37 | ___ 38 | 39 | -------------------------------------------------------------------------------- /src/specVersions/v0.0/RicardianContract.smoke.test.ts: -------------------------------------------------------------------------------- 1 | // Extra smoke test file using some common shared data 2 | 3 | import RicardianContractImpl from '.' 4 | import { RicardianContractRenderError } from '../../RicardianContractRenderError' 5 | 6 | import Fixture from './testfixtures/jscore-fixtures' 7 | 8 | const transaction = Fixture.transaction 9 | const abi = Fixture.abis[0].abi 10 | 11 | describe('RicardianContract', (): void => { 12 | const rcp = new RicardianContractImpl() 13 | 14 | describe('provided a valid transaction and ABI', (): void => { 15 | 16 | it('parses a simple contract', () => { 17 | expect(() => rcp.process({ 18 | abi, 19 | transaction, 20 | actionIndex: 1, 21 | allowUnusedVariables: true, 22 | })).not.toThrow(RicardianContractRenderError) 23 | }) 24 | 25 | it('parses a complex contract', () => { 26 | expect(() => rcp.process({ 27 | abi, 28 | transaction, 29 | actionIndex: 0, 30 | })).not.toThrow(RicardianContractRenderError) 31 | }) 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /docs/interfaces/_interfaces_.transactionactionauthorization.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["interfaces"](../modules/_interfaces_.md) > [TransactionActionAuthorization](../interfaces/_interfaces_.transactionactionauthorization.md) 2 | 3 | # Interface: TransactionActionAuthorization 4 | 5 | ## Hierarchy 6 | 7 | **TransactionActionAuthorization** 8 | 9 | ## Indexable 10 | 11 | \[x: `string`\]: `any` 12 | ## Index 13 | 14 | ### Properties 15 | 16 | * [actor](_interfaces_.transactionactionauthorization.md#actor) 17 | * [permission](_interfaces_.transactionactionauthorization.md#permission) 18 | 19 | --- 20 | 21 | ## Properties 22 | 23 | 24 | 25 | ### actor 26 | 27 | **● actor**: *`string`* 28 | 29 | *Defined in [interfaces.ts:29](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L29)* 30 | 31 | ___ 32 | 33 | 34 | ### permission 35 | 36 | **● permission**: *`string`* 37 | 38 | *Defined in [interfaces.ts:30](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L30)* 39 | 40 | ___ 41 | 42 | -------------------------------------------------------------------------------- /docs/interfaces/_interfaces_.ricardiancontract.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["interfaces"](../modules/_interfaces_.md) > [RicardianContract](../interfaces/_interfaces_.ricardiancontract.md) 2 | 3 | # Interface: RicardianContract 4 | 5 | ## Hierarchy 6 | 7 | **RicardianContract** 8 | 9 | ## Index 10 | 11 | ### Methods 12 | 13 | * [getHtml](_interfaces_.ricardiancontract.md#gethtml) 14 | * [getMetadata](_interfaces_.ricardiancontract.md#getmetadata) 15 | 16 | --- 17 | 18 | ## Methods 19 | 20 | 21 | 22 | ### getHtml 23 | 24 | ▸ **getHtml**(): `string` 25 | 26 | *Defined in [interfaces.ts:69](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L69)* 27 | 28 | **Returns:** `string` 29 | 30 | ___ 31 | 32 | 33 | ### getMetadata 34 | 35 | ▸ **getMetadata**(): [ContractMetadata](_interfaces_.contractmetadata.md) 36 | 37 | *Defined in [interfaces.ts:70](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L70)* 38 | 39 | **Returns:** [ContractMetadata](_interfaces_.contractmetadata.md) 40 | 41 | ___ 42 | 43 | -------------------------------------------------------------------------------- /src/RicardianContractRenderError.ts: -------------------------------------------------------------------------------- 1 | export interface HtmlValidationErrorArgs { 2 | tag: string 3 | reason: string 4 | } 5 | 6 | export class RicardianContractRenderError extends Error implements RicardianContractRenderError { 7 | private static buildMessage(messageArgs: string | HtmlValidationErrorArgs): string { 8 | if (typeof messageArgs === 'string') { 9 | return messageArgs as string 10 | } 11 | const errorArgs = messageArgs as HtmlValidationErrorArgs 12 | return `Invalid or unexpected HTML found near "${errorArgs.tag}" tag. Reason: ${errorArgs.reason}` 13 | } 14 | 15 | public tag: string | null = null 16 | public reason: string | null = null 17 | 18 | constructor(message: string | HtmlValidationErrorArgs) { 19 | super(RicardianContractRenderError.buildMessage(message)) 20 | this.name = 'RicardianContractError' 21 | Object.setPrototypeOf(this, RicardianContractRenderError.prototype) 22 | 23 | if (typeof message !== 'string') { 24 | const messageArgs = message as HtmlValidationErrorArgs 25 | this.tag = messageArgs.tag 26 | this.reason = messageArgs.reason 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/interfaces/_ricardiancontractrendererror_.htmlvalidationerrorargs.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["RicardianContractRenderError"](../modules/_ricardiancontractrendererror_.md) > [HtmlValidationErrorArgs](../interfaces/_ricardiancontractrendererror_.htmlvalidationerrorargs.md) 2 | 3 | # Interface: HtmlValidationErrorArgs 4 | 5 | ## Hierarchy 6 | 7 | **HtmlValidationErrorArgs** 8 | 9 | ## Index 10 | 11 | ### Properties 12 | 13 | * [reason](_ricardiancontractrendererror_.htmlvalidationerrorargs.md#reason) 14 | * [tag](_ricardiancontractrendererror_.htmlvalidationerrorargs.md#tag) 15 | 16 | --- 17 | 18 | ## Properties 19 | 20 | 21 | 22 | ### reason 23 | 24 | **● reason**: *`string`* 25 | 26 | *Defined in [RicardianContractRenderError.ts:3](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/RicardianContractRenderError.ts#L3)* 27 | 28 | ___ 29 | 30 | 31 | ### tag 32 | 33 | **● tag**: *`string`* 34 | 35 | *Defined in [RicardianContractRenderError.ts:2](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/RicardianContractRenderError.ts#L2)* 36 | 37 | ___ 38 | 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2019 block.one and its contributors. All rights reserved. 2 | 3 | The MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/interfaces/_interfaces_.specversion.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["interfaces"](../modules/_interfaces_.md) > [SpecVersion](../interfaces/_interfaces_.specversion.md) 2 | 3 | # Interface: SpecVersion 4 | 5 | ## Hierarchy 6 | 7 | **SpecVersion** 8 | 9 | ## Index 10 | 11 | ### Properties 12 | 13 | * [major](_interfaces_.specversion.md#major) 14 | * [minor](_interfaces_.specversion.md#minor) 15 | * [patch](_interfaces_.specversion.md#patch) 16 | 17 | --- 18 | 19 | ## Properties 20 | 21 | 22 | 23 | ### major 24 | 25 | **● major**: *`number`* 26 | 27 | *Defined in [interfaces.ts:63](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L63)* 28 | 29 | ___ 30 | 31 | 32 | ### minor 33 | 34 | **● minor**: *`number`* 35 | 36 | *Defined in [interfaces.ts:64](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L64)* 37 | 38 | ___ 39 | 40 | 41 | ### `` patch 42 | 43 | **● patch**: *`undefined` \| `number`* 44 | 45 | *Defined in [interfaces.ts:65](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L65)* 46 | 47 | ___ 48 | 49 | -------------------------------------------------------------------------------- /docs/interfaces/_interfaces_.abiaction.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["interfaces"](../modules/_interfaces_.md) > [AbiAction](../interfaces/_interfaces_.abiaction.md) 2 | 3 | # Interface: AbiAction 4 | 5 | ## Hierarchy 6 | 7 | **AbiAction** 8 | 9 | ## Index 10 | 11 | ### Properties 12 | 13 | * [name](_interfaces_.abiaction.md#name) 14 | * [ricardian_contract](_interfaces_.abiaction.md#ricardian_contract) 15 | * [type](_interfaces_.abiaction.md#type) 16 | 17 | --- 18 | 19 | ## Properties 20 | 21 | 22 | 23 | ### name 24 | 25 | **● name**: *`string`* 26 | 27 | *Defined in [interfaces.ts:15](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L15)* 28 | 29 | ___ 30 | 31 | 32 | ### ricardian_contract 33 | 34 | **● ricardian_contract**: *`string`* 35 | 36 | *Defined in [interfaces.ts:17](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L17)* 37 | 38 | ___ 39 | 40 | 41 | ### type 42 | 43 | **● type**: *`string`* 44 | 45 | *Defined in [interfaces.ts:16](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L16)* 46 | 47 | ___ 48 | 49 | -------------------------------------------------------------------------------- /src/specVersions/v0.2/helpers.test.ts: -------------------------------------------------------------------------------- 1 | import * as Handlebars from 'handlebars' 2 | import { ifHasValue } from './helpers' 3 | 4 | describe('ifHasValue', () => { 5 | const context = { 6 | nullVal: null, 7 | goodVal: 7, 8 | } 9 | 10 | beforeAll(() => { 11 | Handlebars.registerHelper('if_has_value', ifHasValue) 12 | }) 13 | 14 | it ('does not render on undefined', () => { 15 | const template = 16 | `{{#if_has_value undefVal}}undefVal: {{ undefVal }}{{ else }}undefVal has no value{{/if_has_value}}` 17 | const t = Handlebars.compile(template) 18 | const result = t(context) 19 | expect(result).toEqual('undefVal has no value') 20 | }) 21 | 22 | it ('does not render on null', () => { 23 | const template = 24 | `{{#if_has_value nullVal}}nullVal: {{ nullVal }}{{ else }}nullVal has no value{{/if_has_value}}` 25 | const t = Handlebars.compile(template) 26 | const result = t(context) 27 | expect(result).toEqual('nullVal has no value') 28 | }) 29 | 30 | it ('does render on 0', () => { 31 | const template = 32 | `{{#if_has_value goodVal}}goodVal: {{ goodVal }}{{ else }}goodVal has no value{{/if_has_value}}` 33 | const t = Handlebars.compile(template) 34 | const result = t(context) 35 | expect(result).toEqual('goodVal: 7') 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /src/factoryHelpers.ts: -------------------------------------------------------------------------------- 1 | import { RicardianContractProcessor, SpecVersion } from './interfaces' 2 | 3 | export function compareProcessors(a: RicardianContractProcessor, b: RicardianContractProcessor): number { 4 | const aVer = a.getSpecVersion() 5 | const bVer = b.getSpecVersion() 6 | 7 | if (aVer.major < bVer.major) { return -1 } 8 | if (aVer.major > bVer.major) { return 1 } 9 | if (aVer.minor < bVer.minor) { return -1 } 10 | if (aVer.minor > bVer.minor) { return 1 } 11 | return 0 12 | } 13 | 14 | export function findProcessorForVersion(sortedProcessors: RicardianContractProcessor[], 15 | specVersion: SpecVersion): RicardianContractProcessor | null { 16 | const major = specVersion.major 17 | const minor = specVersion.minor 18 | 19 | let curProcessor: RicardianContractProcessor | null = null 20 | 21 | // Since processors are sorted by major and minor, the first match 22 | // with the same major value and a processor with the same or greater 23 | // minor value will be returned 24 | for (const processor of sortedProcessors) { 25 | const version = processor.getSpecVersion() 26 | if (major === version.major) { 27 | if (minor <= version.minor) { 28 | curProcessor = processor 29 | break 30 | } 31 | } 32 | } 33 | 34 | return curProcessor 35 | } 36 | -------------------------------------------------------------------------------- /examples/transaction.json: -------------------------------------------------------------------------------- 1 | { 2 | "transaction": { 3 | "expiration": "2018-08-14T20:38:58", 4 | "ref_block_num": 63462, 5 | "ref_block_prefix": 4279361130, 6 | "max_net_usage_words": 0, 7 | "max_cpu_usage_ms": 0, 8 | "delay_sec": 0, 9 | "context_free_actions": [], 10 | "actions": [ 11 | { 12 | "account": "eosio.token", 13 | "name": "multitransf", 14 | "authorization": [ 15 | { 16 | "actor": "bobsmith", 17 | "permission": "active" 18 | } 19 | ], 20 | "data": { 21 | "from": "bobsmith", 22 | "to": "alicejones", 23 | "quantities": [ 24 | "123.0000 EOS", 25 | "456.0000 ABC", 26 | "789.0000 DEF" 27 | ], 28 | "memos": [ 29 | "Super EOS", 30 | "I know you like ABC tokens" 31 | ] 32 | } 33 | }, 34 | { 35 | "account": "eosio.token", 36 | "name": "transfer", 37 | "authorization": [ 38 | { 39 | "actor": "alicejones", 40 | "permission": "active" 41 | } 42 | ], 43 | "data": { 44 | "from": "alicejones", 45 | "to": "bobsmith", 46 | "quantity": "123.0000 EOS", 47 | "memo": "Testing." 48 | } 49 | } 50 | ], 51 | "transaction_extensions": [] 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/RicardianContractFactory.ts: -------------------------------------------------------------------------------- 1 | import { compareProcessors, findProcessorForVersion } from './factoryHelpers' 2 | import { RicardianContract, RicardianContractConfig, 3 | RicardianContractProcessor, SpecVersion} from './interfaces' 4 | import { RicardianContractRenderError } from './RicardianContractRenderError' 5 | import RCP_v0_0 from './specVersions/v0.0' 6 | import RCP_v0_1 from './specVersions/v0.1' 7 | import RCP_v0_2 from './specVersions/v0.2' 8 | import { getContractSpecVersion } from './utils/contractUtils' 9 | 10 | export class RicardianContractFactory { 11 | private processors: RicardianContractProcessor[] = [] 12 | 13 | constructor() { 14 | this.processors.push(new RCP_v0_0()) 15 | this.processors.push(new RCP_v0_1()) 16 | this.processors.push(new RCP_v0_2()) 17 | 18 | this.processors.sort(compareProcessors) 19 | } 20 | 21 | private findProcessor(specVersion: SpecVersion): RicardianContractProcessor | null { 22 | return findProcessorForVersion(this.processors, specVersion) 23 | } 24 | 25 | public create(config: RicardianContractConfig): RicardianContract { 26 | const specVersion = getContractSpecVersion(config) 27 | 28 | const processor = this.findProcessor(specVersion) 29 | 30 | if (processor) { 31 | return processor.process(config) 32 | } else { 33 | throw new RicardianContractRenderError( 34 | `Unable to find a processor to handle specification version ${specVersion.major}.${specVersion.minor}`) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /docs/interfaces/_interfaces_.contractmetadata.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["interfaces"](../modules/_interfaces_.md) > [ContractMetadata](../interfaces/_interfaces_.contractmetadata.md) 2 | 3 | # Interface: ContractMetadata 4 | 5 | ## Hierarchy 6 | 7 | **ContractMetadata** 8 | 9 | ## Indexable 10 | 11 | \[x: `string`\]: `any` 12 | ## Index 13 | 14 | ### Properties 15 | 16 | * [icon](_interfaces_.contractmetadata.md#icon) 17 | * [spec_version](_interfaces_.contractmetadata.md#spec_version) 18 | * [summary](_interfaces_.contractmetadata.md#summary) 19 | * [title](_interfaces_.contractmetadata.md#title) 20 | 21 | --- 22 | 23 | ## Properties 24 | 25 | 26 | 27 | ### icon 28 | 29 | **● icon**: *`string`* 30 | 31 | *Defined in [interfaces.ts:24](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L24)* 32 | 33 | ___ 34 | 35 | 36 | ### spec_version 37 | 38 | **● spec_version**: *`string`* 39 | 40 | *Defined in [interfaces.ts:21](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L21)* 41 | 42 | ___ 43 | 44 | 45 | ### summary 46 | 47 | **● summary**: *`string`* 48 | 49 | *Defined in [interfaces.ts:23](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L23)* 50 | 51 | ___ 52 | 53 | 54 | ### title 55 | 56 | **● title**: *`string`* 57 | 58 | *Defined in [interfaces.ts:22](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L22)* 59 | 60 | ___ 61 | 62 | -------------------------------------------------------------------------------- /docs/modules/_specversions_v0_1_ricardiancontractprocessorimpl_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["specVersions/v0.1/RicardianContractProcessorImpl"](../modules/_specversions_v0_1_ricardiancontractprocessorimpl_.md) 2 | 3 | # External module: "specVersions/v0.1/RicardianContractProcessorImpl" 4 | 5 | ## Index 6 | 7 | ### Classes 8 | 9 | * [RicardianContractProcessorImpl](../classes/_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md) 10 | 11 | ### Object literals 12 | 13 | * [implVersion](_specversions_v0_1_ricardiancontractprocessorimpl_.md#implversion) 14 | 15 | --- 16 | 17 | ## Object literals 18 | 19 | 20 | 21 | ### `` implVersion 22 | 23 | **implVersion**: *`object`* 24 | 25 | *Defined in [specVersions/v0.1/RicardianContractProcessorImpl.ts:4](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.1/RicardianContractProcessorImpl.ts#L4)* 26 | 27 | 28 | 29 | #### major 30 | 31 | **● major**: *`number`* = 0 32 | 33 | *Defined in [specVersions/v0.1/RicardianContractProcessorImpl.ts:5](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.1/RicardianContractProcessorImpl.ts#L5)* 34 | 35 | ___ 36 | 37 | 38 | #### minor 39 | 40 | **● minor**: *`number`* = 1 41 | 42 | *Defined in [specVersions/v0.1/RicardianContractProcessorImpl.ts:6](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.1/RicardianContractProcessorImpl.ts#L6)* 43 | 44 | ___ 45 | 46 | ___ 47 | 48 | -------------------------------------------------------------------------------- /docs/modules/_specversions_v0_2_ricardiancontractprocessorimpl_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["specVersions/v0.2/RicardianContractProcessorImpl"](../modules/_specversions_v0_2_ricardiancontractprocessorimpl_.md) 2 | 3 | # External module: "specVersions/v0.2/RicardianContractProcessorImpl" 4 | 5 | ## Index 6 | 7 | ### Classes 8 | 9 | * [RicardianContractProcessorImpl](../classes/_specversions_v0_2_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md) 10 | 11 | ### Object literals 12 | 13 | * [implVersion](_specversions_v0_2_ricardiancontractprocessorimpl_.md#implversion) 14 | 15 | --- 16 | 17 | ## Object literals 18 | 19 | 20 | 21 | ### `` implVersion 22 | 23 | **implVersion**: *`object`* 24 | 25 | *Defined in [specVersions/v0.2/RicardianContractProcessorImpl.ts:6](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.2/RicardianContractProcessorImpl.ts#L6)* 26 | 27 | 28 | 29 | #### major 30 | 31 | **● major**: *`number`* = 0 32 | 33 | *Defined in [specVersions/v0.2/RicardianContractProcessorImpl.ts:7](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.2/RicardianContractProcessorImpl.ts#L7)* 34 | 35 | ___ 36 | 37 | 38 | #### minor 39 | 40 | **● minor**: *`number`* = 2 41 | 42 | *Defined in [specVersions/v0.2/RicardianContractProcessorImpl.ts:8](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.2/RicardianContractProcessorImpl.ts#L8)* 43 | 44 | ___ 45 | 46 | ___ 47 | 48 | -------------------------------------------------------------------------------- /docs/modules/_specversions_v0_0_ricardiancontractprocessorimpl_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["specVersions/v0.0/RicardianContractProcessorImpl"](../modules/_specversions_v0_0_ricardiancontractprocessorimpl_.md) 2 | 3 | # External module: "specVersions/v0.0/RicardianContractProcessorImpl" 4 | 5 | ## Index 6 | 7 | ### Classes 8 | 9 | * [RicardianContractProcessorImpl](../classes/_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md) 10 | 11 | ### Object literals 12 | 13 | * [implVersion](_specversions_v0_0_ricardiancontractprocessorimpl_.md#implversion) 14 | 15 | --- 16 | 17 | ## Object literals 18 | 19 | 20 | 21 | ### `` implVersion 22 | 23 | **implVersion**: *`object`* 24 | 25 | *Defined in [specVersions/v0.0/RicardianContractProcessorImpl.ts:21](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/RicardianContractProcessorImpl.ts#L21)* 26 | 27 | 28 | 29 | #### major 30 | 31 | **● major**: *`number`* = 0 32 | 33 | *Defined in [specVersions/v0.0/RicardianContractProcessorImpl.ts:22](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/RicardianContractProcessorImpl.ts#L22)* 34 | 35 | ___ 36 | 37 | 38 | #### minor 39 | 40 | **● minor**: *`number`* = 0 41 | 42 | *Defined in [specVersions/v0.0/RicardianContractProcessorImpl.ts:23](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/RicardianContractProcessorImpl.ts#L23)* 43 | 44 | ___ 45 | 46 | ___ 47 | 48 | -------------------------------------------------------------------------------- /src/specVersions/v0.1/RicardianContractProcessorImpl.test.ts: -------------------------------------------------------------------------------- 1 | import { Abi } from '../../interfaces' 2 | import { RicardianContractProcessorImpl } from './RicardianContractProcessorImpl' 3 | 4 | import { eosioTokenAbi, transferTransaction } from '../../testfixtures/fixtures' 5 | 6 | const transaction = JSON.parse(transferTransaction) 7 | const abi = JSON.parse(eosioTokenAbi) 8 | 9 | // tslint:disable:max-line-length 10 | describe('RicardianContractProcessorImp - v0.1', () => { 11 | const rcp = new RicardianContractProcessorImpl() 12 | const contractMetadata = '---\ntitle: Token Transfer\nsummary: Transfer tokens between accounts.\nicon: https://a.com/token-transfer.png#00506E08A55BCF269FE67F202BBC08CFF55F9E3C7CD4459ECB90205BF3C3B562\n---\n\n' 13 | 14 | describe('amount_from_asset', () => { 15 | it('extracts the amount from an asset variable string', () => { 16 | const expectedHtml = `

Transfer Terms & Conditions

\nTransferring
1500.0000
units of something
\n` 17 | const newAbi: Abi = { 18 | ...abi, 19 | actions: [ 20 | { 21 | name: 'transfer', 22 | type: 'transfer', 23 | ricardian_contract: contractMetadata + 24 | '## Transfer Terms & Conditions\n\nTransferring {{amount_from_asset quantity}} units of something\n', 25 | }, 26 | ], 27 | } 28 | 29 | const rc = rcp.process({ 30 | abi: newAbi, 31 | transaction, 32 | actionIndex: 0, 33 | }) 34 | expect(rc.getHtml()).toEqual(expectedHtml) 35 | 36 | }) 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /docs/interfaces/_specversions_v0_0_ricardiancontext_.ricardiancontext.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["specVersions/v0.0/RicardianContext"](../modules/_specversions_v0_0_ricardiancontext_.md) > [RicardianContext](../interfaces/_specversions_v0_0_ricardiancontext_.ricardiancontext.md) 2 | 3 | # Interface: RicardianContext 4 | 5 | ## Hierarchy 6 | 7 | **RicardianContext** 8 | 9 | ## Indexable 10 | 11 | \[x: `string`\]: `any` 12 | ## Index 13 | 14 | ### Properties 15 | 16 | * [$action](_specversions_v0_0_ricardiancontext_.ricardiancontext.md#_action) 17 | * [$clauses](_specversions_v0_0_ricardiancontext_.ricardiancontext.md#_clauses) 18 | * [$transaction](_specversions_v0_0_ricardiancontext_.ricardiancontext.md#_transaction) 19 | 20 | --- 21 | 22 | ## Properties 23 | 24 | 25 | 26 | ### $action 27 | 28 | **● $action**: *`any`* 29 | 30 | *Defined in [specVersions/v0.0/RicardianContext.ts:3](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/RicardianContext.ts#L3)* 31 | 32 | ___ 33 | 34 | 35 | ### $clauses 36 | 37 | **● $clauses**: *`any`* 38 | 39 | *Defined in [specVersions/v0.0/RicardianContext.ts:4](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/RicardianContext.ts#L4)* 40 | 41 | ___ 42 | 43 | 44 | ### $transaction 45 | 46 | **● $transaction**: *`any`* 47 | 48 | *Defined in [specVersions/v0.0/RicardianContext.ts:2](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/RicardianContext.ts#L2)* 49 | 50 | ___ 51 | 52 | -------------------------------------------------------------------------------- /src/utils/contractUtils.test.ts: -------------------------------------------------------------------------------- 1 | import * as utils from './contractUtils' 2 | 3 | import { 4 | complexEosioTokenAbi, 5 | complexTransferTransaction, 6 | } from '../testfixtures/complex-fixtures' 7 | import { eosioTokenAbi, transferTransaction } from '../testfixtures/fixtures' 8 | 9 | const complexTransaction = JSON.parse(complexTransferTransaction) 10 | const complexAbi = JSON.parse(complexEosioTokenAbi) 11 | 12 | const transaction = JSON.parse(transferTransaction) 13 | const abi = JSON.parse(eosioTokenAbi) 14 | 15 | describe('getContractSpecVersion', () => { 16 | it('returns the default spec version if none found', () => { 17 | const specVersion = utils.getContractSpecVersion({ 18 | abi: complexAbi, 19 | transaction: complexTransaction, 20 | actionIndex: 0, 21 | }) 22 | expect(specVersion).toEqual({ major: 0, minor: 0, patch: 0 }) 23 | }) 24 | 25 | it('returns the spec version if found', () => { 26 | const newAbi = { 27 | ...abi, 28 | actions: [{ 29 | name: 'transfer', 30 | type: 'transfer', 31 | // tslint:disable-next-line:max-line-length 32 | ricardian_contract: '---\nspec_version: \'1.2.3\'\ntitle: Token Transfer\nsummary: \'{{$metadata.summary}}\'\nicon: https://a.com/token-transfer.png#00506E08A55BCF269FE67F202BBC08CFF55F9E3C7CD4459ECB90205BF3C3B562\n---\n\n## Transfer Terms & Conditions\n\n', 33 | }], 34 | } 35 | 36 | const specVersion = utils.getContractSpecVersion({ 37 | abi: newAbi, 38 | transaction, 39 | actionIndex: 0, 40 | }) 41 | 42 | expect(specVersion).toEqual({ major: 1, minor: 2, patch: 3 }) 43 | }) 44 | 45 | }) 46 | -------------------------------------------------------------------------------- /docs/interfaces/_interfaces_.transactionaction.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["interfaces"](../modules/_interfaces_.md) > [TransactionAction](../interfaces/_interfaces_.transactionaction.md) 2 | 3 | # Interface: TransactionAction 4 | 5 | ## Hierarchy 6 | 7 | **TransactionAction** 8 | 9 | ## Indexable 10 | 11 | \[x: `string`\]: `any` 12 | ## Index 13 | 14 | ### Properties 15 | 16 | * [account](_interfaces_.transactionaction.md#account) 17 | * [authorization](_interfaces_.transactionaction.md#authorization) 18 | * [data](_interfaces_.transactionaction.md#data) 19 | * [name](_interfaces_.transactionaction.md#name) 20 | 21 | --- 22 | 23 | ## Properties 24 | 25 | 26 | 27 | ### account 28 | 29 | **● account**: *`string`* 30 | 31 | *Defined in [interfaces.ts:35](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L35)* 32 | 33 | ___ 34 | 35 | 36 | ### authorization 37 | 38 | **● authorization**: *[TransactionActionAuthorization](_interfaces_.transactionactionauthorization.md)[]* 39 | 40 | *Defined in [interfaces.ts:37](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L37)* 41 | 42 | ___ 43 | 44 | 45 | ### data 46 | 47 | **● data**: *`any`* 48 | 49 | *Defined in [interfaces.ts:38](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L38)* 50 | 51 | ___ 52 | 53 | 54 | ### name 55 | 56 | **● name**: *`string`* 57 | 58 | *Defined in [interfaces.ts:36](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L36)* 59 | 60 | ___ 61 | 62 | -------------------------------------------------------------------------------- /docs/modules/_bin_rc_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["bin/rc"](../modules/_bin_rc_.md) 2 | 3 | # External module: "bin/rc" 4 | 5 | ## Index 6 | 7 | ### Functions 8 | 9 | * [loadAbi](_bin_rc_.md#loadabi) 10 | * [loadTransaction](_bin_rc_.md#loadtransaction) 11 | * [parseArgs](_bin_rc_.md#parseargs) 12 | * [run](_bin_rc_.md#run) 13 | 14 | --- 15 | 16 | ## Functions 17 | 18 | 19 | 20 | ### loadAbi 21 | 22 | ▸ **loadAbi**(abiPath: *`string`*): `any` 23 | 24 | *Defined in [bin/rc.ts:56](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/bin/rc.ts#L56)* 25 | 26 | **Parameters:** 27 | 28 | | Name | Type | 29 | | ------ | ------ | 30 | | abiPath | `string` | 31 | 32 | **Returns:** `any` 33 | 34 | ___ 35 | 36 | 37 | ### loadTransaction 38 | 39 | ▸ **loadTransaction**(transactionPath: *`string`*): `any` 40 | 41 | *Defined in [bin/rc.ts:51](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/bin/rc.ts#L51)* 42 | 43 | **Parameters:** 44 | 45 | | Name | Type | 46 | | ------ | ------ | 47 | | transactionPath | `string` | 48 | 49 | **Returns:** `any` 50 | 51 | ___ 52 | 53 | 54 | ### parseArgs 55 | 56 | ▸ **parseArgs**(): `object` 57 | 58 | *Defined in [bin/rc.ts:5](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/bin/rc.ts#L5)* 59 | 60 | **Returns:** `object` 61 | 62 | ___ 63 | 64 | 65 | ### run 66 | 67 | ▸ **run**(): `void` 68 | 69 | *Defined in [bin/rc.ts:61](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/bin/rc.ts#L61)* 70 | 71 | **Returns:** `void` 72 | 73 | ___ 74 | 75 | -------------------------------------------------------------------------------- /src/specVersions/v0.1/helpers.test.ts: -------------------------------------------------------------------------------- 1 | import { RicardianContractRenderError } from '../../RicardianContractRenderError' 2 | import { parseAsset } from './helpers' 3 | 4 | describe('parseAsset', () => { 5 | it('parses asset with int amount', () => { 6 | const asset = '40 EOS' 7 | const expectedAsset = { 8 | amount: '40', 9 | symbol: 'EOS', 10 | } 11 | 12 | const parsedAsset = parseAsset(asset) 13 | expect(parsedAsset).toEqual(expectedAsset) 14 | }) 15 | 16 | it('parses asset with float amount', () => { 17 | const asset = '40.123 EOS' 18 | const expectedAsset = { 19 | amount: '40.123', 20 | symbol: 'EOS', 21 | } 22 | 23 | const parsedAsset = parseAsset(asset) 24 | expect(parsedAsset).toEqual(expectedAsset) 25 | }) 26 | 27 | it('throws on asset with missing amount', () => { 28 | const asset = ' EOS' 29 | expect(() => parseAsset(asset)).toThrow(RicardianContractRenderError) 30 | }) 31 | 32 | it('throws on asset with missing symbol', () => { 33 | const asset = '40 ' 34 | expect(() => parseAsset(asset)).toThrow(RicardianContractRenderError) 35 | }) 36 | 37 | it('throws on empty string', () => { 38 | const asset = '' 39 | expect(() => parseAsset(asset)).toThrow(RicardianContractRenderError) 40 | }) 41 | 42 | it('throws on asset decimal with no leading digit', () => { 43 | const asset = '.45 EOS' 44 | expect(() => parseAsset(asset)).toThrow(RicardianContractRenderError) 45 | }) 46 | 47 | it('throws on lowercase symbol name', () => { 48 | const asset = '1.45 eos' 49 | expect(() => parseAsset(asset)).toThrow(RicardianContractRenderError) 50 | }) 51 | }) 52 | -------------------------------------------------------------------------------- /docs/interfaces/_interfaces_.abi.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["interfaces"](../modules/_interfaces_.md) > [Abi](../interfaces/_interfaces_.abi.md) 2 | 3 | # Interface: Abi 4 | 5 | ## Hierarchy 6 | 7 | **Abi** 8 | 9 | ## Index 10 | 11 | ### Properties 12 | 13 | * [actions](_interfaces_.abi.md#actions) 14 | * [ricardian_clauses](_interfaces_.abi.md#ricardian_clauses) 15 | * [structs](_interfaces_.abi.md#structs) 16 | * [types](_interfaces_.abi.md#types) 17 | * [version](_interfaces_.abi.md#version) 18 | 19 | --- 20 | 21 | ## Properties 22 | 23 | 24 | 25 | ### actions 26 | 27 | **● actions**: *[AbiAction](_interfaces_.abiaction.md)[]* 28 | 29 | *Defined in [interfaces.ts:10](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L10)* 30 | 31 | ___ 32 | 33 | 34 | ### ricardian_clauses 35 | 36 | **● ricardian_clauses**: *[RicardianClause](_interfaces_.ricardianclause.md)[]* 37 | 38 | *Defined in [interfaces.ts:11](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L11)* 39 | 40 | ___ 41 | 42 | 43 | ### structs 44 | 45 | **● structs**: *`Array`<`object`>* 46 | 47 | *Defined in [interfaces.ts:9](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L9)* 48 | 49 | ___ 50 | 51 | 52 | ### types 53 | 54 | **● types**: *`Array`<`object`>* 55 | 56 | *Defined in [interfaces.ts:8](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L8)* 57 | 58 | ___ 59 | 60 | 61 | ### version 62 | 63 | **● version**: *`string`* 64 | 65 | *Defined in [interfaces.ts:7](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L7)* 66 | 67 | ___ 68 | 69 | -------------------------------------------------------------------------------- /src/specVersions/v0.0/validators.ts: -------------------------------------------------------------------------------- 1 | import { RicardianContractRenderError } from '../../RicardianContractRenderError' 2 | import * as helpers from './helpers' 3 | 4 | import isUrl from 'is-url' 5 | 6 | export function validateTitle(title?: string | null) { 7 | const maxLen = 50 8 | if (!title || !title.trim()) { 9 | throw new RicardianContractRenderError('Missing Required Field: title') 10 | } else if (title.length > maxLen) { 11 | throw new RicardianContractRenderError(`Title must be no more than ${maxLen} characters`) 12 | } else if (helpers.hasVariable(title)) { 13 | throw new RicardianContractRenderError('Title must not contain variables') 14 | } 15 | } 16 | 17 | export function validateSummary(summary?: string | null) { 18 | const maxLen = 116 19 | if (!summary || !summary.trim()) { 20 | throw new RicardianContractRenderError('Missing Required Field: summary') 21 | } else { 22 | // Don't want to count HTML tags wrapping any vars as part of the len 23 | const stripped = summary.replace(/<.+?>/g, '') 24 | if (stripped.length > maxLen) { 25 | throw new RicardianContractRenderError(`Summary must be no more than ${maxLen} characters`) 26 | } 27 | } 28 | } 29 | 30 | export function validateIcon(icon?: string | null) { 31 | if (!icon || !icon.trim()) { 32 | throw new RicardianContractRenderError('Missing Required Field: icon') 33 | } else if (helpers.hasVariable(icon)) { 34 | throw new RicardianContractRenderError('Icon must not contain variables') 35 | } else if (!isUrl(icon)) { 36 | throw new RicardianContractRenderError('Icon must be a valid URL') 37 | } else { 38 | const sha256Match = /#[A-Fa-f0-9]{64}$/ 39 | if (!icon.match(sha256Match)) { 40 | throw new RicardianContractRenderError('Icon URL must end with a SHA256 hash') 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /docs/modules/_specversions_v0_0_validators_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["specVersions/v0.0/validators"](../modules/_specversions_v0_0_validators_.md) 2 | 3 | # External module: "specVersions/v0.0/validators" 4 | 5 | ## Index 6 | 7 | ### Functions 8 | 9 | * [validateIcon](_specversions_v0_0_validators_.md#validateicon) 10 | * [validateSummary](_specversions_v0_0_validators_.md#validatesummary) 11 | * [validateTitle](_specversions_v0_0_validators_.md#validatetitle) 12 | 13 | --- 14 | 15 | ## Functions 16 | 17 | 18 | 19 | ### validateIcon 20 | 21 | ▸ **validateIcon**(icon?: *`string` \| `null`*): `void` 22 | 23 | *Defined in [specVersions/v0.0/validators.ts:30](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/validators.ts#L30)* 24 | 25 | **Parameters:** 26 | 27 | | Name | Type | 28 | | ------ | ------ | 29 | | `Optional` icon | `string` \| `null` | 30 | 31 | **Returns:** `void` 32 | 33 | ___ 34 | 35 | 36 | ### validateSummary 37 | 38 | ▸ **validateSummary**(summary?: *`string` \| `null`*): `void` 39 | 40 | *Defined in [specVersions/v0.0/validators.ts:17](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/validators.ts#L17)* 41 | 42 | **Parameters:** 43 | 44 | | Name | Type | 45 | | ------ | ------ | 46 | | `Optional` summary | `string` \| `null` | 47 | 48 | **Returns:** `void` 49 | 50 | ___ 51 | 52 | 53 | ### validateTitle 54 | 55 | ▸ **validateTitle**(title?: *`string` \| `null`*): `void` 56 | 57 | *Defined in [specVersions/v0.0/validators.ts:6](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/validators.ts#L6)* 58 | 59 | **Parameters:** 60 | 61 | | Name | Type | 62 | | ------ | ------ | 63 | | `Optional` title | `string` \| `null` | 64 | 65 | **Returns:** `void` 66 | 67 | ___ 68 | 69 | -------------------------------------------------------------------------------- /src/interfaces.ts: -------------------------------------------------------------------------------- 1 | export interface RicardianClause { 2 | id: string 3 | body: string 4 | } 5 | 6 | export interface Abi { 7 | version: string 8 | types: Array<{ new_type_name: string, type: string }> 9 | structs: Array<{ name: string, base: string, fields: Array<{ name: string, type: string }> }> 10 | actions: AbiAction[] 11 | ricardian_clauses: RicardianClause[] 12 | } 13 | 14 | export interface AbiAction { 15 | name: string 16 | type: string 17 | ricardian_contract: string 18 | } 19 | 20 | export interface ContractMetadata { 21 | spec_version: string 22 | title: string 23 | summary: string 24 | icon: string 25 | [x: string]: any 26 | } 27 | 28 | export interface TransactionActionAuthorization { 29 | actor: string 30 | permission: string 31 | [x: string]: any 32 | } 33 | 34 | export interface TransactionAction { 35 | account: string 36 | name: string 37 | authorization: TransactionActionAuthorization[] 38 | data: any 39 | [x: string]: any 40 | } 41 | 42 | export interface Transaction { 43 | actions: TransactionAction[] 44 | expiration?: string 45 | ref_block_num?: number 46 | ref_block_prefix?: number 47 | max_net_usage_words?: number 48 | max_cpu_usage_ms?: number 49 | delay_sec?: number 50 | context_free_actions?: any[] 51 | transaction_extensions?: string[] 52 | } 53 | 54 | export interface RicardianContractConfig { 55 | abi: Abi 56 | transaction: Transaction 57 | actionIndex: number 58 | maxPasses?: number 59 | allowUnusedVariables?: boolean 60 | } 61 | 62 | export interface SpecVersion { 63 | major: number 64 | minor: number 65 | patch?: number 66 | } 67 | 68 | export interface RicardianContract { 69 | getHtml(): string 70 | getMetadata(): ContractMetadata 71 | } 72 | 73 | export interface RicardianContractProcessor { 74 | getSpecVersion(): SpecVersion 75 | process(config: RicardianContractConfig): RicardianContract 76 | } 77 | -------------------------------------------------------------------------------- /docs/interfaces/_interfaces_.ricardiancontractprocessor.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["interfaces"](../modules/_interfaces_.md) > [RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md) 2 | 3 | # Interface: RicardianContractProcessor 4 | 5 | ## Hierarchy 6 | 7 | **RicardianContractProcessor** 8 | 9 | ## Implemented by 10 | 11 | * [RicardianContractProcessorImpl](../classes/_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md) 12 | * [RicardianContractProcessorImpl](../classes/_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md) 13 | * [RicardianContractProcessorImpl](../classes/_specversions_v0_2_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md) 14 | 15 | ## Index 16 | 17 | ### Methods 18 | 19 | * [getSpecVersion](_interfaces_.ricardiancontractprocessor.md#getspecversion) 20 | * [process](_interfaces_.ricardiancontractprocessor.md#process) 21 | 22 | --- 23 | 24 | ## Methods 25 | 26 | 27 | 28 | ### getSpecVersion 29 | 30 | ▸ **getSpecVersion**(): [SpecVersion](_interfaces_.specversion.md) 31 | 32 | *Defined in [interfaces.ts:74](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L74)* 33 | 34 | **Returns:** [SpecVersion](_interfaces_.specversion.md) 35 | 36 | ___ 37 | 38 | 39 | ### process 40 | 41 | ▸ **process**(config: *[RicardianContractConfig](_interfaces_.ricardiancontractconfig.md)*): [RicardianContract](_interfaces_.ricardiancontract.md) 42 | 43 | *Defined in [interfaces.ts:75](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L75)* 44 | 45 | **Parameters:** 46 | 47 | | Name | Type | 48 | | ------ | ------ | 49 | | config | [RicardianContractConfig](_interfaces_.ricardiancontractconfig.md) | 50 | 51 | **Returns:** [RicardianContract](_interfaces_.ricardiancontract.md) 52 | 53 | ___ 54 | 55 | -------------------------------------------------------------------------------- /src/specVersions/v0.0/VariableWrapper.test.ts: -------------------------------------------------------------------------------- 1 | import { VariableWrapper } from './VariableWrapper' 2 | 3 | describe('VariableWrapper', () => { 4 | const variableWrapper = new VariableWrapper( 5 | [ 'lookup' ], 6 | (prefix, className, variable, suffix) => { 7 | return `${prefix}
${variable}
${suffix}` 8 | }) 9 | 10 | it('should wrap variables surrounded by {{ }}', () => { 11 | const template = 'This string has a {{var}} inside' 12 | const expectedWrapped = 'This string has a
{{var}}
inside' 13 | const wrapped = variableWrapper.wrap(template) 14 | expect(wrapped).toEqual(expectedWrapped) 15 | }) 16 | 17 | it('should wrap variables surrounded by {{lookup }}', () => { 18 | const template = 'This string has a {{lookup var}} inside' 19 | const expectedWrapped = 'This string has a
{{lookup var}}
inside' 20 | const wrapped = variableWrapper.wrap(template) 21 | expect(wrapped).toEqual(expectedWrapped) 22 | }) 23 | 24 | it('should wrap variables surrounded by {{{ }}}', () => { 25 | const template = 'This string has a {{{var}}} inside' 26 | const expectedWrapped = 'This string has a
{{{var}}}
inside' 27 | const wrapped = variableWrapper.wrap(template) 28 | expect(wrapped).toEqual(expectedWrapped) 29 | }) 30 | 31 | it('should not wrap variables surrounded by {{{{ }}}} or more', () => { 32 | const template = 'This string has a {{{{var}}}} inside' 33 | const expectedWrapped = template 34 | const wrapped = variableWrapper.wrap(template) 35 | expect(wrapped).toEqual(expectedWrapped) 36 | }) 37 | 38 | it('should not wrap variables surrounded by { }', () => { 39 | const template = 'This string has a {var} inside' 40 | const expectedWrapped = template 41 | const wrapped = variableWrapper.wrap(template) 42 | expect(wrapped).toEqual(expectedWrapped) 43 | }) 44 | }) 45 | -------------------------------------------------------------------------------- /docs/modules/_factoryhelpers_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["factoryHelpers"](../modules/_factoryhelpers_.md) 2 | 3 | # External module: "factoryHelpers" 4 | 5 | ## Index 6 | 7 | ### Functions 8 | 9 | * [compareProcessors](_factoryhelpers_.md#compareprocessors) 10 | * [findProcessorForVersion](_factoryhelpers_.md#findprocessorforversion) 11 | 12 | --- 13 | 14 | ## Functions 15 | 16 | 17 | 18 | ### compareProcessors 19 | 20 | ▸ **compareProcessors**(a: *[RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md)*, b: *[RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md)*): `number` 21 | 22 | *Defined in [factoryHelpers.ts:3](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/factoryHelpers.ts#L3)* 23 | 24 | **Parameters:** 25 | 26 | | Name | Type | 27 | | ------ | ------ | 28 | | a | [RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md) | 29 | | b | [RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md) | 30 | 31 | **Returns:** `number` 32 | 33 | ___ 34 | 35 | 36 | ### findProcessorForVersion 37 | 38 | ▸ **findProcessorForVersion**(sortedProcessors: *[RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md)[]*, specVersion: *[SpecVersion](../interfaces/_interfaces_.specversion.md)*): [RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md) \| `null` 39 | 40 | *Defined in [factoryHelpers.ts:14](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/factoryHelpers.ts#L14)* 41 | 42 | **Parameters:** 43 | 44 | | Name | Type | 45 | | ------ | ------ | 46 | | sortedProcessors | [RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md)[] | 47 | | specVersion | [SpecVersion](../interfaces/_interfaces_.specversion.md) | 48 | 49 | **Returns:** [RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md) \| `null` 50 | 51 | ___ 52 | 53 | -------------------------------------------------------------------------------- /docs/interfaces/_interfaces_.ricardiancontractconfig.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["interfaces"](../modules/_interfaces_.md) > [RicardianContractConfig](../interfaces/_interfaces_.ricardiancontractconfig.md) 2 | 3 | # Interface: RicardianContractConfig 4 | 5 | ## Hierarchy 6 | 7 | **RicardianContractConfig** 8 | 9 | ## Index 10 | 11 | ### Properties 12 | 13 | * [abi](_interfaces_.ricardiancontractconfig.md#abi) 14 | * [actionIndex](_interfaces_.ricardiancontractconfig.md#actionindex) 15 | * [allowUnusedVariables](_interfaces_.ricardiancontractconfig.md#allowunusedvariables) 16 | * [maxPasses](_interfaces_.ricardiancontractconfig.md#maxpasses) 17 | * [transaction](_interfaces_.ricardiancontractconfig.md#transaction) 18 | 19 | --- 20 | 21 | ## Properties 22 | 23 | 24 | 25 | ### abi 26 | 27 | **● abi**: *[Abi](_interfaces_.abi.md)* 28 | 29 | *Defined in [interfaces.ts:55](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L55)* 30 | 31 | ___ 32 | 33 | 34 | ### actionIndex 35 | 36 | **● actionIndex**: *`number`* 37 | 38 | *Defined in [interfaces.ts:57](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L57)* 39 | 40 | ___ 41 | 42 | 43 | ### `` allowUnusedVariables 44 | 45 | **● allowUnusedVariables**: *`undefined` \| `false` \| `true`* 46 | 47 | *Defined in [interfaces.ts:59](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L59)* 48 | 49 | ___ 50 | 51 | 52 | ### `` maxPasses 53 | 54 | **● maxPasses**: *`undefined` \| `number`* 55 | 56 | *Defined in [interfaces.ts:58](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L58)* 57 | 58 | ___ 59 | 60 | 61 | ### transaction 62 | 63 | **● transaction**: *[Transaction](_interfaces_.transaction.md)* 64 | 65 | *Defined in [interfaces.ts:56](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L56)* 66 | 67 | ___ 68 | 69 | -------------------------------------------------------------------------------- /src/bin/rc.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import yargs from 'yargs' 3 | import { RicardianContractFactory } from '../RicardianContractFactory' 4 | 5 | function parseArgs() { 6 | const argv = yargs 7 | .options({ 8 | 'abi': { 9 | alias: 'a', 10 | describe: 'Path to JSON file containing the ABI', 11 | normalize: true, 12 | requiresArg: true, 13 | }, 14 | 'transaction': { 15 | alias: 't', 16 | describe: 'Path to JSON file containing transaction data', 17 | normalize: true, 18 | requiresArg: true, 19 | }, 20 | 'action-index': { 21 | alias: 'i', 22 | describe: 'Index of the transaction action to use (zero-based)', 23 | default: 0, 24 | type: 'number', 25 | }, 26 | 'permissive': { 27 | alias: 'p', 28 | describe: 'Process the contract in permissive mode', 29 | default: false, 30 | type: 'boolean', 31 | }, 32 | 'max-passes': { 33 | alias: 'm', 34 | describe: 'Maximum number of variable interpolation passes to perform', 35 | default: 3, 36 | type: 'number', 37 | }, 38 | 'only-metadata': { 39 | describe: 'Only print the metadata', 40 | default: false, 41 | type: 'boolean', 42 | }, 43 | }) 44 | .demandOption(['transaction', 'abi']) 45 | .version() 46 | .parse() 47 | 48 | return argv 49 | } 50 | 51 | function loadTransaction(transactionPath: string): any { 52 | const txnStr = fs.readFileSync(transactionPath) 53 | return JSON.parse(txnStr.toString()) 54 | } 55 | 56 | function loadAbi(abiPath: string): any { 57 | const abiStr = fs.readFileSync(abiPath) 58 | return JSON.parse(abiStr.toString()) 59 | } 60 | 61 | function run(): void { 62 | const argv = parseArgs() 63 | const transaction = loadTransaction(argv.transaction) 64 | const abi = loadAbi(argv.abi) 65 | 66 | const config = { 67 | abi, 68 | transaction, 69 | actionIndex: argv['action-index'], 70 | maxPasses: argv['max-passes'], 71 | allowUnusedVariables: argv.permissive, 72 | } 73 | 74 | const rcf = new RicardianContractFactory() 75 | const rc = rcf.create(config) 76 | 77 | if (argv['only-metadata']) { 78 | console.info(JSON.stringify(rc.getMetadata(), null, 4)) 79 | } else { 80 | console.info(rc.getHtml()) 81 | } 82 | } 83 | 84 | module.exports.run = run 85 | -------------------------------------------------------------------------------- /src/specVersions/v0.0/whitelist.ts: -------------------------------------------------------------------------------- 1 | export const WhiteList: { [index: string]: string[] } = { 2 | h1: [], 3 | h2: [], 4 | h3: [], 5 | h4: [], 6 | h5: [], 7 | h6: [], 8 | h7: [], 9 | h8: [], 10 | br: [], 11 | b: [], 12 | i: [], 13 | strong: [], 14 | em: [], 15 | a: ['href'], 16 | pre: [], 17 | code: [], 18 | img: ['src', 'longdesc'], 19 | tt: [], 20 | div: ['itemscope', 'itemtype'], 21 | ins: ['cite'], 22 | del: ['cite'], 23 | sup: [], 24 | sub: [], 25 | p: [], 26 | ol: [], 27 | ul: [], 28 | table: [], 29 | thead: [], 30 | tbody: [], 31 | tfoot: [], 32 | blockquote: ['cite'], 33 | dl: [], 34 | dt: [], 35 | dd: [], 36 | kbd: [], 37 | q: ['cite'], 38 | samp: [], 39 | var: [], 40 | hr: [], 41 | ruby: [], 42 | rt: [], 43 | rp: [], 44 | li: [], 45 | tr: [], 46 | td: [], 47 | th: [], 48 | s: [], 49 | strike: [], 50 | summary: [], 51 | details: [], 52 | _commonattrs_: [ 53 | 'abbr', 54 | 'accept', 55 | 'accept-charset', 56 | 'accesskey', 57 | 'action', 58 | 'align', 59 | 'alt', 60 | 'axis', 61 | 'border', 62 | 'cellpadding', 63 | 'cellspacing', 64 | 'char', 65 | 'charoff', 66 | 'charset', 67 | 'checked', 68 | 'class', 69 | 'clear', 70 | 'cols', 71 | 'colspan', 72 | 'color', 73 | 'compact', 74 | 'coords', 75 | 'datetime', 76 | 'dir', 77 | 'disabled', 78 | 'enctype', 79 | 'for', 80 | 'frame', 81 | 'headers', 82 | 'height', 83 | 'hreflang', 84 | 'hspace', 85 | 'id', 86 | 'ismap', 87 | 'label', 88 | 'lang', 89 | 'maxlength', 90 | 'media', 91 | 'method', 92 | 'multiple', 93 | 'name', 94 | 'nohref', 95 | 'noshade', 96 | 'nowrap', 97 | 'open', 98 | 'prompt', 99 | 'readonly', 100 | 'rel', 101 | 'rev', 102 | 'rows', 103 | 'rowspan', 104 | 'rules', 105 | 'scope', 106 | 'selected', 107 | 'shape', 108 | 'size', 109 | 'span', 110 | 'start', 111 | 'summary', 112 | 'tabindex', 113 | 'target', 114 | 'title', 115 | 'type', 116 | 'usemap', 117 | 'valign', 118 | 'value', 119 | 'vspace', 120 | 'width', 121 | 'itemprop', 122 | ], 123 | } 124 | 125 | // List of known HTML5 empty elements - not used for whitelisting, do not edit. 126 | export const EmptyElements: string[] = [ 127 | 'area', 'base', 'br', 'col', 'command', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 128 | ] 129 | -------------------------------------------------------------------------------- /src/specVersions/v0.0/VariableWrapper.ts: -------------------------------------------------------------------------------- 1 | import { WrapVariable } from './WrapVariable' 2 | 3 | export class VariableWrapper { 4 | // Allow 2 or 3 brackets and no more. We don't want to end up with "{
{{{test}}}
}". 5 | private static start = /(^|[^{])({{{?)/.source // "{{" or "{{{" but not "{{{{" 6 | private static end = /(}}}?)([^}]|$)/.source // "}}" or "}}}" but not "}}}}" 7 | private static space = /(?:[\s]*)/.source 8 | 9 | private static createVariableMatcher() { 10 | const { source: variableRoot } = /(\$?)(\w+)/ // "from" or "$transaction" or "$clauses" 11 | const { source: variableChild } = /(\.[\w\d\[\]\.]+)?/ // suffix ".delay_sec" or ".actions.[0].data.from" 12 | // tslint:disable-next-line:max-line-length 13 | const { source: variable } = RegExp(`${VariableWrapper.space}(?!else)(${variableRoot}${variableChild})${VariableWrapper.space}`) // " $action.name " or "from" 14 | 15 | // /(^|[^{])({{{?)( *(\$?)(\w+)(?:\.[\w\d\[\]\.]+)? *)([^}](?:}}}?))([^}]|$)/g 16 | return RegExp(`${VariableWrapper.start}${variable}${VariableWrapper.end}`, 'g') 17 | } 18 | 19 | private static createWrappedHelperMatcher(wrappedHelpers: string[]): RegExp { 20 | const wrappedHelperStr = wrappedHelpers.join('|') 21 | // The extra () near the beginning acts as a placeholder so the number of captured elements match the main regex 22 | const wrappedHelper = `(()(${wrappedHelperStr})\\s([^}]+))` 23 | const { source: variable } = RegExp(`${VariableWrapper.space}${wrappedHelper}${VariableWrapper.space}`) 24 | 25 | return RegExp(`${VariableWrapper.start}${variable}${VariableWrapper.end}`, 'g') 26 | } 27 | 28 | private variableMatch: RegExp = VariableWrapper.createVariableMatcher() 29 | private wrappedHelperMatch: RegExp 30 | 31 | private wrapVariable: WrapVariable 32 | 33 | public constructor(wrappedHelpers: string[], wrapVariable: WrapVariable) { 34 | this.wrapVariable = wrapVariable 35 | this.wrappedHelperMatch = VariableWrapper.createWrappedHelperMatcher(wrappedHelpers) 36 | } 37 | 38 | public wrap(template: string) { 39 | const processVariable = this.processVariable.bind(this) 40 | const newTemplate = template.replace(this.variableMatch, processVariable) 41 | return newTemplate.replace(this.wrappedHelperMatch, processVariable) 42 | } 43 | 44 | private processVariable(...p: any[]): string { 45 | let className: string = 'data' 46 | if (p[4] === '$') { 47 | className = p[5] 48 | } 49 | const variable = p[2] + p[3] + p[7] 50 | 51 | return this.wrapVariable(p[1], className, variable, p[8]) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/specVersions/v0.2/RicardianContractProcessorImpl.test.ts: -------------------------------------------------------------------------------- 1 | import { Abi } from '../../interfaces' 2 | import { RicardianContractProcessorImpl } from './RicardianContractProcessorImpl' 3 | 4 | import { eosioTokenAbi, transferTransaction } from '../../testfixtures/fixtures' 5 | 6 | const transaction = JSON.parse(transferTransaction) 7 | const abi = JSON.parse(eosioTokenAbi) 8 | 9 | // tslint:disable:max-line-length 10 | describe('RicardianContractProcessorImp - v0.2', () => { 11 | const rcp = new RicardianContractProcessorImpl() 12 | 13 | it('dumps variable as JSON', () => { 14 | const expectedHtml = 15 | `

We got a action over here!

16 |
{
17 |   "account": "eosio.token",
18 |   "name": "transfer",
19 |   "authorization": [
20 |     {
21 |       "actor": "bobsmith",
22 |       "permission": "active",
23 |       "$index": 0
24 |     }
25 |   ],
26 |   "data": {
27 |     "from": "bobsmith",
28 |     "to": "alicejones",
29 |     "quantity": "123.0000 EOS",
30 |     "memo": "Testing.",
31 |     "$metadata": {
32 |       "summary": "Transfer from 
bobsmith
to
alicejones
" 33 | } 34 | }, 35 | "$index": 2 36 | } 37 |
38 | ` 39 | const newAbi: Abi = { 40 | ...abi, 41 | actions: [ 42 | { 43 | name: 'transfer', 44 | type: 'transfer', 45 | ricardian_contract: '---\ntitle: Token Transfer\nsummary: Transfer tokens between accounts.\nicon: https://a.com/token-transfer.png#00506E08A55BCF269FE67F202BBC08CFF55F9E3C7CD4459ECB90205BF3C3B562\n---\n\n## We got a action over here!\n{{to_json $action}}\n', 46 | }, 47 | ], 48 | } 49 | 50 | const rc = rcp.process({ 51 | abi: newAbi, 52 | transaction, 53 | actionIndex: 2, 54 | }) 55 | expect(rc.getHtml()).toEqual(expectedHtml) 56 | }) 57 | 58 | it('renders block if value defined', () => { 59 | const expectedHtml = `

We got a action over here!

\nDo we have a memo?
Testing.

\n` 60 | const newAbi: Abi = { 61 | ...abi, 62 | actions: [ 63 | { 64 | name: 'transfer', 65 | type: 'transfer', 66 | ricardian_contract: '---\ntitle: Token Transfer\nsummary: Transfer tokens between accounts.\nicon: https://a.com/token-transfer.png#00506E08A55BCF269FE67F202BBC08CFF55F9E3C7CD4459ECB90205BF3C3B562\n---\n\n## We got a action over here!\nDo we have a memo? {{#if_has_value memo}}{{memo}}{{else}}{{No memo given}}{{/if_has_value}}\n', 67 | }, 68 | ], 69 | } 70 | 71 | const rc = rcp.process({ 72 | abi: newAbi, 73 | transaction, 74 | actionIndex: 2, 75 | }) 76 | expect(rc.getHtml()).toEqual(expectedHtml) 77 | }) 78 | }) 79 | -------------------------------------------------------------------------------- /src/utils/contractUtils.ts: -------------------------------------------------------------------------------- 1 | import frontMatter from 'front-matter' 2 | 3 | import { Abi, AbiAction, ContractMetadata, 4 | RicardianContractConfig, SpecVersion, 5 | Transaction, TransactionAction } from '../interfaces' 6 | import { RicardianContractRenderError } from '../RicardianContractRenderError' 7 | 8 | /** 9 | * Retrieves a specifc action based off its index. 10 | * 11 | * @param actionIndex The index of an action to return from the transaction.actions array 12 | * 13 | * @returns An single action from a transaction 14 | */ 15 | export function getTransactionAction(transaction: Transaction, actionIndex: number): TransactionAction { 16 | const action = transaction.actions[actionIndex] 17 | return action 18 | } 19 | 20 | /** 21 | * Finds the abi for a specific action and returns the raw ricardian contract. 22 | * 23 | * @return Raw ricardian contract string 24 | */ 25 | export function getContractTextFromAbi(abi: Abi, action: TransactionAction): string { 26 | const abiAction: (AbiAction | undefined) = abi.actions.find((aa: AbiAction) => aa.name === action.name) 27 | if (!abiAction) { 28 | throw new RicardianContractRenderError('Matching ABI not provided for given action.') 29 | } 30 | return abiAction.ricardian_contract 31 | } 32 | 33 | /** 34 | * Extracts the ContractMetadata and contract body contents from the raw contract text 35 | * 36 | * @param contractText String containing the raw contract text 37 | * 38 | * @return Object containing ContractMetadata and body content 39 | */ 40 | export function getMetadataAndContent(contractText: string): 41 | { metadata: ContractMetadata, content: string } { 42 | try { 43 | const { attributes: metadata, body: content } = frontMatter(contractText) 44 | return { metadata, content } 45 | } catch (e) { 46 | throw new RicardianContractRenderError(e.message) 47 | } 48 | } 49 | 50 | export function getContractSpecVersion(config: RicardianContractConfig): SpecVersion { 51 | const versionMatcher = /^([0-9]+)\.([0-9]+)\.([0-9]+)$/ 52 | const action = getTransactionAction(config.transaction, config.actionIndex) 53 | const contractText = getContractTextFromAbi(config.abi, action) 54 | const { metadata } = getMetadataAndContent(contractText) 55 | const versionStr = metadata.spec_version 56 | if (!versionStr) { 57 | // Provide backward compatability with spec version 0.0.x 58 | // which had no version specifier 59 | return { 60 | major: 0, 61 | minor: 0, 62 | patch: 0, 63 | } 64 | } 65 | const parts = versionMatcher.exec(versionStr) 66 | if (parts) { 67 | return { 68 | major: parseInt(parts[1], 10), 69 | minor: parseInt(parts[2], 10), 70 | patch: parseInt(parts[3], 10), 71 | } 72 | } else { 73 | throw new RicardianContractRenderError('Unable to determine contract specification version') 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ricardian-template-toolkit", 3 | "version": "0.2.0", 4 | "description": "Ricardian Contract Template Toolkit for EOSIO applications.", 5 | "main": "dist/index.js", 6 | "typings": "dist/index.d.ts", 7 | "bin": { 8 | "rc": "bin/rc" 9 | }, 10 | "repository": "https://github.com/EOSIO/ricardian-template-toolkit", 11 | "author": { 12 | "name": "block.one", 13 | "url": "https://block.one" 14 | }, 15 | "contributors": [ 16 | "Eddie Sheffield", 17 | "Brandon Fancher", 18 | "Chris Allnutt", 19 | "Jeffrey Smith II", 20 | "Randy Torres", 21 | "Leo Ribeiro", 22 | "Bill Woodward", 23 | "Tara Tritt", 24 | "Jonathan Pratt", 25 | "Adam Halper" 26 | ], 27 | "license": "MIT", 28 | "devDependencies": { 29 | "@blockone/tslint-config-blockone": "^4.0.0", 30 | "@types/handlebars": "^4.1.0", 31 | "@types/he": "^1.1.0", 32 | "@types/is-url": "^1.2.28", 33 | "@types/jest": "^23.3.1", 34 | "@types/remarkable": "^1.7.1", 35 | "@types/yargs": "^12.0.5", 36 | "jest": "^24.8.0", 37 | "jest-coverage-ratchet": "^0.2.3", 38 | "shx": "^0.3.2", 39 | "ts-jest": "^24.0.2", 40 | "ts-loader": "^6.0.2", 41 | "tslint": "^5.17.0", 42 | "tslint-eslint-rules": "^5.3.1", 43 | "typedoc": "^0.14.2", 44 | "typedoc-plugin-markdown": "^1.2.1", 45 | "typescript": "^3.5.1", 46 | "webpack": "^4.17.1", 47 | "webpack-cli": "^3.1.0" 48 | }, 49 | "dependencies": { 50 | "front-matter": "^3.0.2", 51 | "handlebars": "^4.1.2", 52 | "he": "^1.2.0", 53 | "is-url": "^1.2.4", 54 | "remarkable": "^1.7.1", 55 | "xss": "^1.0.3", 56 | "yargs": "^12.0.5" 57 | }, 58 | "resolutions": { 59 | "argparse": "1.0.10", 60 | "underscore.string": "3.3.5", 61 | "merge": "1.2.1", 62 | "handlebars": "4.1.2", 63 | "lodash": "4.17.11", 64 | "js-yaml": "3.13.1", 65 | "marked": "^0.6.2" 66 | }, 67 | "scripts": { 68 | "build": "yarn clean && tsc -p tsconfig.webpack.json && yarn build-web && yarn build-jscore && yarn docs", 69 | "build-web": "webpack --config webpack.web.config.js", 70 | "build-jscore": "webpack --config webpack.jscore.config.js", 71 | "clean": "shx rm -rf _bundles dist docs", 72 | "watch": "yarn clean && tsc -w", 73 | "lint": "yarn tslint", 74 | "tslint": "tslint -c tslint.json -p tsconfig.json", 75 | "coverage": "jest --coverage", 76 | "test": "jest", 77 | "ratchet": "jest-coverage-ratchet", 78 | "example": "tsc && node index.js", 79 | "docs": "typedoc --exclude \"**/*+(index|.test|fixtures).ts\" --out ./docs --theme markdown", 80 | "prepublish": "npm run clean && tsc -p tsconfig.webpack.json && yarn docs" 81 | }, 82 | "jest": { 83 | "coverageThreshold": { 84 | "global": { 85 | "lines": 100, 86 | "statements": 100, 87 | "functions": 100, 88 | "branches": 100 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /docs/classes/_ricardiancontractfactory_.ricardiancontractfactory.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["RicardianContractFactory"](../modules/_ricardiancontractfactory_.md) > [RicardianContractFactory](../classes/_ricardiancontractfactory_.ricardiancontractfactory.md) 2 | 3 | # Class: RicardianContractFactory 4 | 5 | ## Hierarchy 6 | 7 | **RicardianContractFactory** 8 | 9 | ## Index 10 | 11 | ### Constructors 12 | 13 | * [constructor](_ricardiancontractfactory_.ricardiancontractfactory.md#constructor) 14 | 15 | ### Properties 16 | 17 | * [processors](_ricardiancontractfactory_.ricardiancontractfactory.md#processors) 18 | 19 | ### Methods 20 | 21 | * [create](_ricardiancontractfactory_.ricardiancontractfactory.md#create) 22 | * [findProcessor](_ricardiancontractfactory_.ricardiancontractfactory.md#findprocessor) 23 | 24 | --- 25 | 26 | ## Constructors 27 | 28 | 29 | 30 | ### constructor 31 | 32 | ⊕ **new RicardianContractFactory**(): [RicardianContractFactory](_ricardiancontractfactory_.ricardiancontractfactory.md) 33 | 34 | *Defined in [RicardianContractFactory.ts:11](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/RicardianContractFactory.ts#L11)* 35 | 36 | **Returns:** [RicardianContractFactory](_ricardiancontractfactory_.ricardiancontractfactory.md) 37 | 38 | ___ 39 | 40 | ## Properties 41 | 42 | 43 | 44 | ### `` processors 45 | 46 | **● processors**: *[RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md)[]* = [] 47 | 48 | *Defined in [RicardianContractFactory.ts:11](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/RicardianContractFactory.ts#L11)* 49 | 50 | ___ 51 | 52 | ## Methods 53 | 54 | 55 | 56 | ### create 57 | 58 | ▸ **create**(config: *[RicardianContractConfig](../interfaces/_interfaces_.ricardiancontractconfig.md)*): [RicardianContract](../interfaces/_interfaces_.ricardiancontract.md) 59 | 60 | *Defined in [RicardianContractFactory.ts:25](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/RicardianContractFactory.ts#L25)* 61 | 62 | **Parameters:** 63 | 64 | | Name | Type | 65 | | ------ | ------ | 66 | | config | [RicardianContractConfig](../interfaces/_interfaces_.ricardiancontractconfig.md) | 67 | 68 | **Returns:** [RicardianContract](../interfaces/_interfaces_.ricardiancontract.md) 69 | 70 | ___ 71 | 72 | 73 | ### `` findProcessor 74 | 75 | ▸ **findProcessor**(specVersion: *[SpecVersion](../interfaces/_interfaces_.specversion.md)*): [RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md) \| `null` 76 | 77 | *Defined in [RicardianContractFactory.ts:21](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/RicardianContractFactory.ts#L21)* 78 | 79 | **Parameters:** 80 | 81 | | Name | Type | 82 | | ------ | ------ | 83 | | specVersion | [SpecVersion](../interfaces/_interfaces_.specversion.md) | 84 | 85 | **Returns:** [RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md) \| `null` 86 | 87 | ___ 88 | 89 | -------------------------------------------------------------------------------- /docs/interfaces/_interfaces_.transaction.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["interfaces"](../modules/_interfaces_.md) > [Transaction](../interfaces/_interfaces_.transaction.md) 2 | 3 | # Interface: Transaction 4 | 5 | ## Hierarchy 6 | 7 | **Transaction** 8 | 9 | ## Index 10 | 11 | ### Properties 12 | 13 | * [actions](_interfaces_.transaction.md#actions) 14 | * [context_free_actions](_interfaces_.transaction.md#context_free_actions) 15 | * [delay_sec](_interfaces_.transaction.md#delay_sec) 16 | * [expiration](_interfaces_.transaction.md#expiration) 17 | * [max_cpu_usage_ms](_interfaces_.transaction.md#max_cpu_usage_ms) 18 | * [max_net_usage_words](_interfaces_.transaction.md#max_net_usage_words) 19 | * [ref_block_num](_interfaces_.transaction.md#ref_block_num) 20 | * [ref_block_prefix](_interfaces_.transaction.md#ref_block_prefix) 21 | * [transaction_extensions](_interfaces_.transaction.md#transaction_extensions) 22 | 23 | --- 24 | 25 | ## Properties 26 | 27 | 28 | 29 | ### actions 30 | 31 | **● actions**: *[TransactionAction](_interfaces_.transactionaction.md)[]* 32 | 33 | *Defined in [interfaces.ts:43](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L43)* 34 | 35 | ___ 36 | 37 | 38 | ### `` context_free_actions 39 | 40 | **● context_free_actions**: *`any`[]* 41 | 42 | *Defined in [interfaces.ts:50](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L50)* 43 | 44 | ___ 45 | 46 | 47 | ### `` delay_sec 48 | 49 | **● delay_sec**: *`undefined` \| `number`* 50 | 51 | *Defined in [interfaces.ts:49](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L49)* 52 | 53 | ___ 54 | 55 | 56 | ### `` expiration 57 | 58 | **● expiration**: *`undefined` \| `string`* 59 | 60 | *Defined in [interfaces.ts:44](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L44)* 61 | 62 | ___ 63 | 64 | 65 | ### `` max_cpu_usage_ms 66 | 67 | **● max_cpu_usage_ms**: *`undefined` \| `number`* 68 | 69 | *Defined in [interfaces.ts:48](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L48)* 70 | 71 | ___ 72 | 73 | 74 | ### `` max_net_usage_words 75 | 76 | **● max_net_usage_words**: *`undefined` \| `number`* 77 | 78 | *Defined in [interfaces.ts:47](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L47)* 79 | 80 | ___ 81 | 82 | 83 | ### `` ref_block_num 84 | 85 | **● ref_block_num**: *`undefined` \| `number`* 86 | 87 | *Defined in [interfaces.ts:45](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L45)* 88 | 89 | ___ 90 | 91 | 92 | ### `` ref_block_prefix 93 | 94 | **● ref_block_prefix**: *`undefined` \| `number`* 95 | 96 | *Defined in [interfaces.ts:46](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L46)* 97 | 98 | ___ 99 | 100 | 101 | ### `` transaction_extensions 102 | 103 | **● transaction_extensions**: *`string`[]* 104 | 105 | *Defined in [interfaces.ts:51](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/interfaces.ts#L51)* 106 | 107 | ___ 108 | 109 | -------------------------------------------------------------------------------- /docs/modules/_utils_contractutils_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["utils/contractUtils"](../modules/_utils_contractutils_.md) 2 | 3 | # External module: "utils/contractUtils" 4 | 5 | ## Index 6 | 7 | ### Functions 8 | 9 | * [getContractSpecVersion](_utils_contractutils_.md#getcontractspecversion) 10 | * [getContractTextFromAbi](_utils_contractutils_.md#getcontracttextfromabi) 11 | * [getMetadataAndContent](_utils_contractutils_.md#getmetadataandcontent) 12 | * [getTransactionAction](_utils_contractutils_.md#gettransactionaction) 13 | 14 | --- 15 | 16 | ## Functions 17 | 18 | 19 | 20 | ### getContractSpecVersion 21 | 22 | ▸ **getContractSpecVersion**(config: *[RicardianContractConfig](../interfaces/_interfaces_.ricardiancontractconfig.md)*): [SpecVersion](../interfaces/_interfaces_.specversion.md) 23 | 24 | *Defined in [utils/contractUtils.ts:50](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/utils/contractUtils.ts#L50)* 25 | 26 | **Parameters:** 27 | 28 | | Name | Type | 29 | | ------ | ------ | 30 | | config | [RicardianContractConfig](../interfaces/_interfaces_.ricardiancontractconfig.md) | 31 | 32 | **Returns:** [SpecVersion](../interfaces/_interfaces_.specversion.md) 33 | 34 | ___ 35 | 36 | 37 | ### getContractTextFromAbi 38 | 39 | ▸ **getContractTextFromAbi**(abi: *[Abi](../interfaces/_interfaces_.abi.md)*, action: *[TransactionAction](../interfaces/_interfaces_.transactionaction.md)*): `string` 40 | 41 | *Defined in [utils/contractUtils.ts:25](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/utils/contractUtils.ts#L25)* 42 | 43 | Finds the abi for a specific action and returns the raw ricardian contract. 44 | 45 | **Parameters:** 46 | 47 | | Name | Type | 48 | | ------ | ------ | 49 | | abi | [Abi](../interfaces/_interfaces_.abi.md) | 50 | | action | [TransactionAction](../interfaces/_interfaces_.transactionaction.md) | 51 | 52 | **Returns:** `string` 53 | Raw ricardian contract string 54 | 55 | ___ 56 | 57 | 58 | ### getMetadataAndContent 59 | 60 | ▸ **getMetadataAndContent**(contractText: *`string`*): `object` 61 | 62 | *Defined in [utils/contractUtils.ts:40](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/utils/contractUtils.ts#L40)* 63 | 64 | Extracts the ContractMetadata and contract body contents from the raw contract text 65 | 66 | **Parameters:** 67 | 68 | | Name | Type | Description | 69 | | ------ | ------ | ------ | 70 | | contractText | `string` | String containing the raw contract text | 71 | 72 | **Returns:** `object` 73 | Object containing ContractMetadata and body content 74 | 75 | ___ 76 | 77 | 78 | ### getTransactionAction 79 | 80 | ▸ **getTransactionAction**(transaction: *[Transaction](../interfaces/_interfaces_.transaction.md)*, actionIndex: *`number`*): [TransactionAction](../interfaces/_interfaces_.transactionaction.md) 81 | 82 | *Defined in [utils/contractUtils.ts:15](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/utils/contractUtils.ts#L15)* 83 | 84 | Retrieves a specifc action based off its index. 85 | 86 | **Parameters:** 87 | 88 | | Name | Type | Description | 89 | | ------ | ------ | ------ | 90 | | transaction | [Transaction](../interfaces/_interfaces_.transaction.md) | 91 | | actionIndex | `number` | The index of an action to return from the transaction.actions array | 92 | 93 | **Returns:** [TransactionAction](../interfaces/_interfaces_.transactionaction.md) 94 | An single action from a transaction 95 | 96 | ___ 97 | 98 | -------------------------------------------------------------------------------- /src/factoryHelpers.test.ts: -------------------------------------------------------------------------------- 1 | import { compareProcessors, findProcessorForVersion } from './factoryHelpers' 2 | import { RicardianContractProcessor } from './interfaces' 3 | 4 | function createMockProcessor(major: number, minor: number) { 5 | return jest.fn(() => ({ 6 | getSpecVersion: () => { 7 | return { major, minor } 8 | } 9 | }))() 10 | } 11 | 12 | describe('compareProcessors', () => { 13 | 14 | describe('when major versions differ', () => { 15 | it('compares correctly if a major < b major', () => { 16 | const mockA = createMockProcessor(1, 2) 17 | const mockB = createMockProcessor(2, 2) 18 | 19 | expect(compareProcessors(mockA, mockB)).toEqual(-1) 20 | }) 21 | 22 | it('compares correctly if a major > b major', () => { 23 | const mockA = createMockProcessor(2, 2) 24 | const mockB = createMockProcessor(1, 2) 25 | 26 | expect(compareProcessors(mockA, mockB)).toEqual(1) 27 | }) 28 | }) 29 | 30 | describe('when major versions are equal', () => { 31 | it('compares correctly if a minor == b minor', () => { 32 | const mockA = createMockProcessor(1, 2) 33 | const mockB = createMockProcessor(1, 2) 34 | 35 | expect(compareProcessors(mockA, mockB)).toEqual(0) 36 | }) 37 | 38 | it('compares correctly if a minor < b minor', () => { 39 | const mockA = createMockProcessor(1, 1) 40 | const mockB = createMockProcessor(1, 2) 41 | 42 | expect(compareProcessors(mockA, mockB)).toEqual(-1) 43 | }) 44 | 45 | it('compares correctly if a minor > b minor', () => { 46 | const mockA = createMockProcessor(1, 2) 47 | const mockB = createMockProcessor(1, 1) 48 | 49 | expect(compareProcessors(mockA, mockB)).toEqual(1) 50 | }) 51 | }) 52 | 53 | it('can correctly sort an array of processors', () => { 54 | const processors = [ 55 | createMockProcessor(0, 3), 56 | createMockProcessor(2, 2), 57 | createMockProcessor(3, 4), 58 | createMockProcessor(0, 1), 59 | createMockProcessor(2, 1), 60 | createMockProcessor(3, 2), 61 | ] 62 | 63 | processors.sort(compareProcessors) 64 | 65 | expect(processors[0].getSpecVersion()).toEqual({ major: 0, minor: 1}) 66 | expect(processors[5].getSpecVersion()).toEqual({ major: 3, minor: 4}) 67 | expect(processors[3].getSpecVersion()).toEqual({ major: 2, minor: 2}) 68 | }) 69 | }) 70 | 71 | describe('findProcessorForVersion', () => { 72 | const processors = [ 73 | createMockProcessor(0, 3), 74 | createMockProcessor(2, 2), 75 | createMockProcessor(3, 4), 76 | createMockProcessor(0, 1), 77 | createMockProcessor(2, 1), 78 | createMockProcessor(3, 2), 79 | ].sort(compareProcessors) 80 | 81 | it('finds a processor for an exact version match', () => { 82 | const specVersion = { major: 2, minor: 1 } 83 | 84 | const processor = findProcessorForVersion(processors, specVersion) 85 | 86 | expect(processor).not.toBeNull() 87 | if (processor) { 88 | expect(processor.getSpecVersion()).toEqual(specVersion) 89 | } 90 | }) 91 | 92 | it('finds a processor for equal major and lesser minor', () => { 93 | const specVersion = { major: 3, minor: 3 } 94 | 95 | const processor = findProcessorForVersion(processors, specVersion) 96 | 97 | expect(processor).not.toBeNull() 98 | if (processor) { 99 | expect(processor.getSpecVersion()).toEqual({ major: 3, minor: 4}) 100 | } 101 | }) 102 | 103 | it('finds nothing for equal major and greater minor', () => { 104 | const specVersion = { major: 3, minor: 5 } 105 | 106 | const processor = findProcessorForVersion(processors, specVersion) 107 | 108 | expect(processor).toBeNull() 109 | }) 110 | 111 | it('finds nothing for unknown major', () => { 112 | const specVersion = { major: 5, minor: 5 } 113 | 114 | const processor = findProcessorForVersion(processors, specVersion) 115 | 116 | expect(processor).toBeNull() 117 | }) 118 | }) 119 | -------------------------------------------------------------------------------- /docs/modules/_specversions_v0_0_helpers_.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["specVersions/v0.0/helpers"](../modules/_specversions_v0_0_helpers_.md) 2 | 3 | # External module: "specVersions/v0.0/helpers" 4 | 5 | ## Index 6 | 7 | ### Functions 8 | 9 | * [extractSymbolCode](_specversions_v0_0_helpers_.md#extractsymbolcode) 10 | * [getWhiteList](_specversions_v0_0_helpers_.md#getwhitelist) 11 | * [hasVariable](_specversions_v0_0_helpers_.md#hasvariable) 12 | * [indexTransaction](_specversions_v0_0_helpers_.md#indextransaction) 13 | * [processTag](_specversions_v0_0_helpers_.md#processtag) 14 | * [sanitizeHtml](_specversions_v0_0_helpers_.md#sanitizehtml) 15 | * [tagMetadataVariables](_specversions_v0_0_helpers_.md#tagmetadatavariables) 16 | * [tagTemplateVariables](_specversions_v0_0_helpers_.md#tagtemplatevariables) 17 | 18 | --- 19 | 20 | ## Functions 21 | 22 | 23 | 24 | ### extractSymbolCode 25 | 26 | ▸ **extractSymbolCode**(text: *`string`*): `string` 27 | 28 | *Defined in [specVersions/v0.0/helpers.ts:55](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/helpers.ts#L55)* 29 | 30 | **Parameters:** 31 | 32 | | Name | Type | 33 | | ------ | ------ | 34 | | text | `string` | 35 | 36 | **Returns:** `string` 37 | 38 | ___ 39 | 40 | 41 | ### getWhiteList 42 | 43 | ▸ **getWhiteList**(): `object` 44 | 45 | *Defined in [specVersions/v0.0/helpers.ts:125](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/helpers.ts#L125)* 46 | 47 | **Returns:** `object` 48 | 49 | ___ 50 | 51 | 52 | ### hasVariable 53 | 54 | ▸ **hasVariable**(text: *`string`*): `boolean` 55 | 56 | *Defined in [specVersions/v0.0/helpers.ts:25](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/helpers.ts#L25)* 57 | 58 | **Parameters:** 59 | 60 | | Name | Type | 61 | | ------ | ------ | 62 | | text | `string` | 63 | 64 | **Returns:** `boolean` 65 | 66 | ___ 67 | 68 | 69 | ### indexTransaction 70 | 71 | ▸ **indexTransaction**(entry: *`any`*): `any` 72 | 73 | *Defined in [specVersions/v0.0/helpers.ts:7](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/helpers.ts#L7)* 74 | 75 | **Parameters:** 76 | 77 | | Name | Type | 78 | | ------ | ------ | 79 | | entry | `any` | 80 | 81 | **Returns:** `any` 82 | 83 | ___ 84 | 85 | 86 | ### processTag 87 | 88 | ▸ **processTag**(tagStack: *`string`[]*, tag: *`string`*, options: *`any`*): `void` 89 | 90 | *Defined in [specVersions/v0.0/helpers.ts:98](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/helpers.ts#L98)* 91 | 92 | **Parameters:** 93 | 94 | | Name | Type | 95 | | ------ | ------ | 96 | | tagStack | `string`[] | 97 | | tag | `string` | 98 | | options | `any` | 99 | 100 | **Returns:** `void` 101 | 102 | ___ 103 | 104 | 105 | ### sanitizeHtml 106 | 107 | ▸ **sanitizeHtml**(html: *`string`*): `string` 108 | 109 | *Defined in [specVersions/v0.0/helpers.ts:65](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/helpers.ts#L65)* 110 | 111 | **Parameters:** 112 | 113 | | Name | Type | 114 | | ------ | ------ | 115 | | html | `string` | 116 | 117 | **Returns:** `string` 118 | 119 | ___ 120 | 121 | 122 | ### tagMetadataVariables 123 | 124 | ▸ **tagMetadataVariables**(wrappedHelpers: *`string`[]*, metadata: *`object`*): `object` 125 | 126 | *Defined in [specVersions/v0.0/helpers.ts:38](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/helpers.ts#L38)* 127 | 128 | **Parameters:** 129 | 130 | | Name | Type | 131 | | ------ | ------ | 132 | | wrappedHelpers | `string`[] | 133 | | metadata | `object` | 134 | 135 | **Returns:** `object` 136 | 137 | ___ 138 | 139 | 140 | ### tagTemplateVariables 141 | 142 | ▸ **tagTemplateVariables**(wrappedHelpers: *`string`[]*, template: *`string`*): `string` 143 | 144 | *Defined in [specVersions/v0.0/helpers.ts:30](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/helpers.ts#L30)* 145 | 146 | **Parameters:** 147 | 148 | | Name | Type | 149 | | ------ | ------ | 150 | | wrappedHelpers | `string`[] | 151 | | template | `string` | 152 | 153 | **Returns:** `string` 154 | 155 | ___ 156 | 157 | -------------------------------------------------------------------------------- /src/specVersions/v0.0/helpers.ts: -------------------------------------------------------------------------------- 1 | import xss from 'xss' 2 | import { RicardianContractRenderError } from '../../RicardianContractRenderError' 3 | import { VariableWrapper } from './VariableWrapper' 4 | import { EmptyElements, WhiteList } from './whitelist' 5 | 6 | // Recursively adds $index properties to every array in the provided transaction 7 | export function indexTransaction(entry: any): any { 8 | if (Array.isArray(entry)) { 9 | entry.forEach((item: any, index: number): any => { 10 | item.$index = index 11 | indexTransaction(item) 12 | }) 13 | return 14 | } 15 | 16 | for (const [, value] of Object.entries(entry)) { 17 | if (Array.isArray(value) && value.length) { 18 | indexTransaction(value) 19 | } 20 | } 21 | 22 | return entry 23 | } 24 | 25 | export function hasVariable(text: string): boolean { 26 | const regex: RegExp = RegExp('{{[{]?(.*?)[}]?}}') 27 | return regex.test(text) 28 | } 29 | 30 | export function tagTemplateVariables(wrappedHelpers: string[], template: string): string { 31 | const variableWrapper = new VariableWrapper(wrappedHelpers, (prefix, className, variable, suffix) => { 32 | return `${prefix}{{#wrap class="${className}"}}${variable}{{/wrap}}${suffix}` 33 | }) 34 | 35 | return variableWrapper.wrap(template) 36 | } 37 | 38 | export function tagMetadataVariables( 39 | wrappedHelpers: string[], 40 | metadata: { [index: string]: string }): { [index: string]: string } { 41 | const variableWrapper = new VariableWrapper(wrappedHelpers, (prefix, className, variable, suffix) => { 42 | return `${prefix}
${variable}
${suffix}` 43 | }) 44 | 45 | const processedMetadata: { [index: string]: string } = {} 46 | Object.keys(metadata).forEach((key) => { 47 | if (metadata[key]) { 48 | processedMetadata[key] = variableWrapper.wrap(metadata[key]) 49 | } 50 | }) 51 | 52 | return processedMetadata 53 | } 54 | 55 | export function extractSymbolCode(text: string): string { 56 | const regex: RegExp = RegExp('.+[^A-Za-z]([A-Za-z]+)$') 57 | const match = text.match(regex) 58 | if (match) { 59 | return match[1] 60 | } 61 | 62 | return '' 63 | } 64 | 65 | export function sanitizeHtml(html: string): string { 66 | const tagStack: string[] = [] 67 | const whiteList = getWhiteList() 68 | 69 | const sanitizer = new xss.FilterXSS({ 70 | whiteList, 71 | onTag: (tag: string, _1: string, options: any): string | void => { 72 | return processTag(tagStack, tag, options) 73 | }, 74 | onIgnoreTag: (tag: string, _1: string, options: any) => { 75 | throw new RicardianContractRenderError({ 76 | tag, reason: `Disallowed tag "${tag}" found at position ${options.sourcePosition}`, 77 | }) 78 | }, 79 | onIgnoreTagAttr: (tag: string, name: string, _1: string, _2: boolean) => { 80 | throw new RicardianContractRenderError({ 81 | tag, reason: `Disallowed attribute "${name}" found on tag "${tag}"`, 82 | }) 83 | }, 84 | }) 85 | 86 | const sanitized = sanitizer.process(html) 87 | 88 | if (tagStack.length !== 0) { 89 | const tag = tagStack.pop() as string 90 | throw new RicardianContractRenderError({ 91 | tag, reason: `Expected closing tag for "${tag}" not found`, 92 | }) 93 | } 94 | 95 | return sanitized 96 | } 97 | 98 | function processTag(tagStack: string[], tag: string, options: any): void { 99 | if (!options.isWhite) { 100 | return 101 | } 102 | 103 | if (options.isClosing) { 104 | if (EmptyElements.includes(tag)) { 105 | throw new RicardianContractRenderError({ 106 | tag, reason: `Unexpected closing tag for empty element "${tag}"`, 107 | }) 108 | } 109 | 110 | const openTag = tagStack.pop() 111 | if (openTag == null) { 112 | throw new RicardianContractRenderError({ 113 | tag, reason: `Unexpected closing tag "${tag}" with no open tag`, 114 | }) 115 | } else if (tag !== openTag) { 116 | throw new RicardianContractRenderError({ 117 | tag, reason: `Unexpected closing tag "${tag}"; expected closing tag for "${openTag}"`, 118 | }) 119 | } 120 | } else if (!EmptyElements.includes(tag)) { 121 | tagStack.push(tag) 122 | } 123 | } 124 | 125 | function getWhiteList(): { [index: string]: string[] } { 126 | const processedWL: { [index: string]: string[] } = {} 127 | Object.keys(WhiteList).forEach((tag) => { 128 | if (tag !== '_commonattrs_') { 129 | processedWL[tag] = [...WhiteList[tag], ...WhiteList._commonattrs_] 130 | } 131 | }) 132 | 133 | return processedWL 134 | } 135 | -------------------------------------------------------------------------------- /docs/classes/_ricardiancontractrendererror_.ricardiancontractrendererror.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["RicardianContractRenderError"](../modules/_ricardiancontractrendererror_.md) > [RicardianContractRenderError](../classes/_ricardiancontractrendererror_.ricardiancontractrendererror.md) 2 | 3 | # Class: RicardianContractRenderError 4 | 5 | ## Hierarchy 6 | 7 | `Error` 8 | 9 | **↳ RicardianContractRenderError** 10 | 11 | ## Implements 12 | 13 | * [RicardianContractRenderError](_ricardiancontractrendererror_.ricardiancontractrendererror.md) 14 | 15 | ## Implemented by 16 | 17 | * [RicardianContractRenderError](_ricardiancontractrendererror_.ricardiancontractrendererror.md) 18 | 19 | ## Index 20 | 21 | ### Constructors 22 | 23 | * [constructor](_ricardiancontractrendererror_.ricardiancontractrendererror.md#constructor) 24 | 25 | ### Properties 26 | 27 | * [message](_ricardiancontractrendererror_.ricardiancontractrendererror.md#message) 28 | * [name](_ricardiancontractrendererror_.ricardiancontractrendererror.md#name) 29 | * [reason](_ricardiancontractrendererror_.ricardiancontractrendererror.md#reason) 30 | * [stack](_ricardiancontractrendererror_.ricardiancontractrendererror.md#stack) 31 | * [tag](_ricardiancontractrendererror_.ricardiancontractrendererror.md#tag) 32 | * [Error](_ricardiancontractrendererror_.ricardiancontractrendererror.md#error) 33 | 34 | ### Methods 35 | 36 | * [buildMessage](_ricardiancontractrendererror_.ricardiancontractrendererror.md#buildmessage) 37 | 38 | --- 39 | 40 | ## Constructors 41 | 42 | 43 | 44 | ### constructor 45 | 46 | ⊕ **new RicardianContractRenderError**(message: *`string` \| [HtmlValidationErrorArgs](../interfaces/_ricardiancontractrendererror_.htmlvalidationerrorargs.md)*): [RicardianContractRenderError](_ricardiancontractrendererror_.ricardiancontractrendererror.md) 47 | 48 | *Defined in [RicardianContractRenderError.ts:16](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/RicardianContractRenderError.ts#L16)* 49 | 50 | **Parameters:** 51 | 52 | | Name | Type | 53 | | ------ | ------ | 54 | | message | `string` \| [HtmlValidationErrorArgs](../interfaces/_ricardiancontractrendererror_.htmlvalidationerrorargs.md) | 55 | 56 | **Returns:** [RicardianContractRenderError](_ricardiancontractrendererror_.ricardiancontractrendererror.md) 57 | 58 | ___ 59 | 60 | ## Properties 61 | 62 | 63 | 64 | ### message 65 | 66 | **● message**: *`string`* 67 | 68 | *Inherited from Error.message* 69 | 70 | *Defined in /Users/eddie.sheffield/projects/ricardian-template-toolkit/node_modules/typedoc/node_modules/typescript/lib/lib.es5.d.ts:964* 71 | 72 | ___ 73 | 74 | 75 | ### name 76 | 77 | **● name**: *`string`* 78 | 79 | *Inherited from Error.name* 80 | 81 | *Defined in /Users/eddie.sheffield/projects/ricardian-template-toolkit/node_modules/typedoc/node_modules/typescript/lib/lib.es5.d.ts:963* 82 | 83 | ___ 84 | 85 | 86 | ### reason 87 | 88 | **● reason**: *`string` \| `null`* = null 89 | 90 | *Defined in [RicardianContractRenderError.ts:16](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/RicardianContractRenderError.ts#L16)* 91 | 92 | ___ 93 | 94 | 95 | ### `` stack 96 | 97 | **● stack**: *`undefined` \| `string`* 98 | 99 | *Inherited from Error.stack* 100 | 101 | *Overrides Error.stack* 102 | 103 | *Defined in /Users/eddie.sheffield/projects/ricardian-template-toolkit/node_modules/typedoc/node_modules/typescript/lib/lib.es5.d.ts:965* 104 | 105 | ___ 106 | 107 | 108 | ### tag 109 | 110 | **● tag**: *`string` \| `null`* = null 111 | 112 | *Defined in [RicardianContractRenderError.ts:15](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/RicardianContractRenderError.ts#L15)* 113 | 114 | ___ 115 | 116 | 117 | ### `` Error 118 | 119 | **● Error**: *`ErrorConstructor`* 120 | 121 | *Defined in /Users/eddie.sheffield/projects/ricardian-template-toolkit/node_modules/typedoc/node_modules/typescript/lib/lib.es5.d.ts:974* 122 | 123 | ___ 124 | 125 | ## Methods 126 | 127 | 128 | 129 | ### ```` buildMessage 130 | 131 | ▸ **buildMessage**(messageArgs: *`string` \| [HtmlValidationErrorArgs](../interfaces/_ricardiancontractrendererror_.htmlvalidationerrorargs.md)*): `string` 132 | 133 | *Defined in [RicardianContractRenderError.ts:7](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/RicardianContractRenderError.ts#L7)* 134 | 135 | **Parameters:** 136 | 137 | | Name | Type | 138 | | ------ | ------ | 139 | | messageArgs | `string` \| [HtmlValidationErrorArgs](../interfaces/_ricardiancontractrendererror_.htmlvalidationerrorargs.md) | 140 | 141 | **Returns:** `string` 142 | 143 | ___ 144 | 145 | -------------------------------------------------------------------------------- /src/specVersions/v0.0/validators.test.ts: -------------------------------------------------------------------------------- 1 | import { RicardianContractRenderError } from '../../RicardianContractRenderError' 2 | import * as validators from './validators' 3 | 4 | describe('title validator', () => { 5 | it('fails empty titles', () => { 6 | expect(() => { validators.validateTitle('') }) 7 | .toThrow(RicardianContractRenderError) 8 | }) 9 | 10 | it('fails titles having only whitespace', () => { 11 | expect(() => { validators.validateTitle(' \t\n') }) 12 | .toThrow(RicardianContractRenderError) 13 | }) 14 | 15 | it('fails null titles', () => { 16 | expect(() => { validators.validateTitle(null) }) 17 | .toThrow(RicardianContractRenderError) 18 | }) 19 | 20 | it('fails undefined titles', () => { 21 | expect(() => { validators.validateTitle() }) 22 | .toThrow(RicardianContractRenderError) 23 | }) 24 | 25 | it('fails titles > 50 chars', () => { 26 | const title = 'a'.repeat(51) 27 | expect(() => { validators.validateTitle(title) }) 28 | .toThrow(RicardianContractRenderError) 29 | }) 30 | 31 | it('fails titles containing variables', () => { 32 | const title = 'Bad title with {{var}}' 33 | expect(() => { validators.validateTitle(title) }) 34 | .toThrow(RicardianContractRenderError) 35 | }) 36 | 37 | it('passes valid a title', () => { 38 | const title = 'This is a very fine title!' 39 | expect(() => { validators.validateTitle(title) }) 40 | .not.toThrow(RicardianContractRenderError) 41 | }) 42 | }) 43 | 44 | describe('summary validator', () => { 45 | it('fails empty summary', () => { 46 | expect(() => { validators.validateSummary('') }) 47 | .toThrow(RicardianContractRenderError) 48 | }) 49 | 50 | it('fails summary having only whitespace', () => { 51 | expect(() => { validators.validateSummary(' \t\n') }) 52 | .toThrow(RicardianContractRenderError) 53 | }) 54 | 55 | it('fails null summary', () => { 56 | expect(() => { validators.validateSummary(null) }) 57 | .toThrow(RicardianContractRenderError) 58 | }) 59 | 60 | it('fails undefined summary', () => { 61 | expect(() => { validators.validateSummary() }) 62 | .toThrow(RicardianContractRenderError) 63 | }) 64 | 65 | it('fails summary > 116 chars', () => { 66 | const summary = 'a'.repeat(117) 67 | expect(() => { validators.validateSummary(summary) }) 68 | .toThrow(RicardianContractRenderError) 69 | }) 70 | 71 | it('passes valid a summary', () => { 72 | const summary = 'This summary summarizes the summary quite nicely!' 73 | expect(() => { validators.validateTitle(summary) }) 74 | .not.toThrow(RicardianContractRenderError) 75 | }) 76 | 77 | it('passes a summary ignoring html tags', () => { 78 | // tslint:disable-next-line:max-line-length 79 | const summary = 'This
summary with variable
should still be ok even if too long with the tags in place because html tags are removed.' 80 | expect(() => { validators.validateSummary(summary) }) 81 | .not.toThrow(RicardianContractRenderError) 82 | }) 83 | 84 | it('fails a summary ignoring html tags that is still too long', () => { 85 | // tslint:disable-next-line:max-line-length 86 | const summary = 'This
summary with variable
should fail because even with the tags removed, it\'s still too long according to the specification. Falgercarb!' 87 | expect(() => { validators.validateSummary(summary) }) 88 | .toThrow(RicardianContractRenderError) 89 | }) 90 | }) 91 | 92 | describe('icon validator', () => { 93 | it('fails empty icon', () => { 94 | expect(() => { validators.validateIcon('') }) 95 | .toThrow(RicardianContractRenderError) 96 | }) 97 | 98 | it('fails icon having only whitespace', () => { 99 | expect(() => { validators.validateIcon(' \t\n') }) 100 | .toThrow(RicardianContractRenderError) 101 | }) 102 | 103 | it('fails null icon', () => { 104 | expect(() => { validators.validateIcon(null) }) 105 | .toThrow(RicardianContractRenderError) 106 | }) 107 | 108 | it('fails undefined icon', () => { 109 | expect(() => { validators.validateIcon() }) 110 | .toThrow(RicardianContractRenderError) 111 | }) 112 | 113 | it('fails icon containing variables', () => { 114 | const url = 'https://{{a}}.com/token-transfer.png#00506E08A55BCF269FE67F202BBC08CFF55F9E3C7CD4459ECB90205BF3C3B562' 115 | expect(() => { validators.validateIcon(url) }) 116 | .toThrow(RicardianContractRenderError) 117 | }) 118 | 119 | it('fails if icon is not url', () => { 120 | const url = 'Is this a URL?' 121 | expect(() => { validators.validateIcon(url) }) 122 | .toThrow(RicardianContractRenderError) 123 | }) 124 | 125 | it('fails if icon url does not end with a SHA256 hash', () => { 126 | const url = 'http://google.com' 127 | expect(() => { validators.validateIcon(url) }) 128 | .toThrow(RicardianContractRenderError) 129 | }) 130 | 131 | it('passes on valid icon URL', () => { 132 | const url = 'https://a.com/token-transfer.png#00506E08A55BCF269FE67F202BBC08CFF55F9E3C7CD4459ECB90205BF3C3B562' 133 | expect(() => { validators.validateIcon(url) }) 134 | .not.toThrow(RicardianContractRenderError) 135 | }) 136 | }) 137 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 5 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 6 | "lib": ["es2017", "dom"], /* Specify library files to be included in the compilation. */ 7 | // "allowJs": true, /* Allow javascript files to be compiled. */ 8 | // "checkJs": true, /* Report errors in .js files. */ 9 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 10 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 11 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 12 | "sourceMap": true, /* Generates corresponding '.map' file. */ 13 | // "outFile": "./", /* Concatenate and emit output to single file. */ 14 | "outDir": "dist", /* Redirect output structure to the directory. */ 15 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 16 | // "composite": true, /* Enable project compilation */ 17 | // "removeComments": true, /* Do not emit comments to output. */ 18 | // "noEmit": true, /* Do not emit outputs. */ 19 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 20 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 21 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 22 | /* Strict Type-Checking Options */ 23 | "strict": true, /* Enable all strict type-checking options. */ 24 | "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 25 | // "strictNullChecks": true, /* Enable strict null checks. */ 26 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 27 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 28 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 29 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 30 | /* Additional Checks */ 31 | "noUnusedLocals": true, /* Report errors on unused locals. */ 32 | "noUnusedParameters": true, /* Report errors on unused parameters. */ 33 | "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 34 | "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 35 | /* Module Resolution Options */ 36 | "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 37 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 38 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 39 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 40 | // "typeRoots": [], /* List of folders to include type definitions from. */ 41 | // "types": [], /* Type declaration files to be included in compilation. */ 42 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 43 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 44 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 45 | /* Source Map Options */ 46 | // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 47 | // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ 48 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 49 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 50 | /* Experimental Options */ 51 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 52 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 53 | } 54 | } -------------------------------------------------------------------------------- /docs/classes/_specversions_v0_0_variablewrapper_.variablewrapper.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["specVersions/v0.0/VariableWrapper"](../modules/_specversions_v0_0_variablewrapper_.md) > [VariableWrapper](../classes/_specversions_v0_0_variablewrapper_.variablewrapper.md) 2 | 3 | # Class: VariableWrapper 4 | 5 | ## Hierarchy 6 | 7 | **VariableWrapper** 8 | 9 | ## Index 10 | 11 | ### Constructors 12 | 13 | * [constructor](_specversions_v0_0_variablewrapper_.variablewrapper.md#constructor) 14 | 15 | ### Properties 16 | 17 | * [variableMatch](_specversions_v0_0_variablewrapper_.variablewrapper.md#variablematch) 18 | * [wrapVariable](_specversions_v0_0_variablewrapper_.variablewrapper.md#wrapvariable) 19 | * [wrappedHelperMatch](_specversions_v0_0_variablewrapper_.variablewrapper.md#wrappedhelpermatch) 20 | * [end](_specversions_v0_0_variablewrapper_.variablewrapper.md#end) 21 | * [space](_specversions_v0_0_variablewrapper_.variablewrapper.md#space) 22 | * [start](_specversions_v0_0_variablewrapper_.variablewrapper.md#start) 23 | 24 | ### Methods 25 | 26 | * [processVariable](_specversions_v0_0_variablewrapper_.variablewrapper.md#processvariable) 27 | * [wrap](_specversions_v0_0_variablewrapper_.variablewrapper.md#wrap) 28 | * [createVariableMatcher](_specversions_v0_0_variablewrapper_.variablewrapper.md#createvariablematcher) 29 | * [createWrappedHelperMatcher](_specversions_v0_0_variablewrapper_.variablewrapper.md#createwrappedhelpermatcher) 30 | 31 | --- 32 | 33 | ## Constructors 34 | 35 | 36 | 37 | ### constructor 38 | 39 | ⊕ **new VariableWrapper**(wrappedHelpers: *`string`[]*, wrapVariable: *[WrapVariable](../modules/_specversions_v0_0_wrapvariable_.md#wrapvariable)*): [VariableWrapper](_specversions_v0_0_variablewrapper_.variablewrapper.md) 40 | 41 | *Defined in [specVersions/v0.0/VariableWrapper.ts:31](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/VariableWrapper.ts#L31)* 42 | 43 | **Parameters:** 44 | 45 | | Name | Type | 46 | | ------ | ------ | 47 | | wrappedHelpers | `string`[] | 48 | | wrapVariable | [WrapVariable](../modules/_specversions_v0_0_wrapvariable_.md#wrapvariable) | 49 | 50 | **Returns:** [VariableWrapper](_specversions_v0_0_variablewrapper_.variablewrapper.md) 51 | 52 | ___ 53 | 54 | ## Properties 55 | 56 | 57 | 58 | ### `` variableMatch 59 | 60 | **● variableMatch**: *`RegExp`* = VariableWrapper.createVariableMatcher() 61 | 62 | *Defined in [specVersions/v0.0/VariableWrapper.ts:28](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/VariableWrapper.ts#L28)* 63 | 64 | ___ 65 | 66 | 67 | ### `` wrapVariable 68 | 69 | **● wrapVariable**: *[WrapVariable](../modules/_specversions_v0_0_wrapvariable_.md#wrapvariable)* 70 | 71 | *Defined in [specVersions/v0.0/VariableWrapper.ts:31](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/VariableWrapper.ts#L31)* 72 | 73 | ___ 74 | 75 | 76 | ### `` wrappedHelperMatch 77 | 78 | **● wrappedHelperMatch**: *`RegExp`* 79 | 80 | *Defined in [specVersions/v0.0/VariableWrapper.ts:29](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/VariableWrapper.ts#L29)* 81 | 82 | ___ 83 | 84 | 85 | ### ```` end 86 | 87 | **● end**: *`string`* = /(}}}?)([^}]|$)/.source 88 | 89 | *Defined in [specVersions/v0.0/VariableWrapper.ts:6](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/VariableWrapper.ts#L6)* 90 | 91 | ___ 92 | 93 | 94 | ### ```` space 95 | 96 | **● space**: *`string`* = /(?:[\s]*)/.source 97 | 98 | *Defined in [specVersions/v0.0/VariableWrapper.ts:7](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/VariableWrapper.ts#L7)* 99 | 100 | ___ 101 | 102 | 103 | ### ```` start 104 | 105 | **● start**: *`string`* = /(^|[^{])({{{?)/.source 106 | 107 | *Defined in [specVersions/v0.0/VariableWrapper.ts:5](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/VariableWrapper.ts#L5)* 108 | 109 | ___ 110 | 111 | ## Methods 112 | 113 | 114 | 115 | ### `` processVariable 116 | 117 | ▸ **processVariable**(...p: *`any`[]*): `string` 118 | 119 | *Defined in [specVersions/v0.0/VariableWrapper.ts:44](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/VariableWrapper.ts#L44)* 120 | 121 | **Parameters:** 122 | 123 | | Name | Type | 124 | | ------ | ------ | 125 | | `Rest` p | `any`[] | 126 | 127 | **Returns:** `string` 128 | 129 | ___ 130 | 131 | 132 | ### wrap 133 | 134 | ▸ **wrap**(template: *`string`*): `string` 135 | 136 | *Defined in [specVersions/v0.0/VariableWrapper.ts:38](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/VariableWrapper.ts#L38)* 137 | 138 | **Parameters:** 139 | 140 | | Name | Type | 141 | | ------ | ------ | 142 | | template | `string` | 143 | 144 | **Returns:** `string` 145 | 146 | ___ 147 | 148 | 149 | ### ```` createVariableMatcher 150 | 151 | ▸ **createVariableMatcher**(): `RegExp` 152 | 153 | *Defined in [specVersions/v0.0/VariableWrapper.ts:9](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/VariableWrapper.ts#L9)* 154 | 155 | **Returns:** `RegExp` 156 | 157 | ___ 158 | 159 | 160 | ### ```` createWrappedHelperMatcher 161 | 162 | ▸ **createWrappedHelperMatcher**(wrappedHelpers: *`string`[]*): `RegExp` 163 | 164 | *Defined in [specVersions/v0.0/VariableWrapper.ts:19](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/VariableWrapper.ts#L19)* 165 | 166 | **Parameters:** 167 | 168 | | Name | Type | 169 | | ------ | ------ | 170 | | wrappedHelpers | `string`[] | 171 | 172 | **Returns:** `RegExp` 173 | 174 | ___ 175 | 176 | -------------------------------------------------------------------------------- /docs/classes/_specversions_v0_2_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["specVersions/v0.2/RicardianContractProcessorImpl"](../modules/_specversions_v0_2_ricardiancontractprocessorimpl_.md) > [RicardianContractProcessorImpl](../classes/_specversions_v0_2_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md) 2 | 3 | # Class: RicardianContractProcessorImpl 4 | 5 | ## Hierarchy 6 | 7 | ↳ [RicardianContractProcessorImpl](_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md) 8 | 9 | **↳ RicardianContractProcessorImpl** 10 | 11 | ## Implements 12 | 13 | * [RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md) 14 | 15 | ## Index 16 | 17 | ### Constructors 18 | 19 | * [constructor](_specversions_v0_2_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#constructor) 20 | 21 | ### Methods 22 | 23 | * [getSpecVersion](_specversions_v0_2_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#getspecversion) 24 | * [process](_specversions_v0_2_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#process) 25 | * [processContract](_specversions_v0_2_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#processcontract) 26 | * [registerHelper](_specversions_v0_2_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#registerhelper) 27 | * [registerWrappedHelper](_specversions_v0_2_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#registerwrappedhelper) 28 | 29 | --- 30 | 31 | ## Constructors 32 | 33 | 34 | 35 | ### constructor 36 | 37 | ⊕ **new RicardianContractProcessorImpl**(): [RicardianContractProcessorImpl](_specversions_v0_2_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md) 38 | 39 | *Overrides [RicardianContractProcessorImpl](_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md).[constructor](_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#constructor)* 40 | 41 | *Defined in [specVersions/v0.2/RicardianContractProcessorImpl.ts:11](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.2/RicardianContractProcessorImpl.ts#L11)* 42 | 43 | **Returns:** [RicardianContractProcessorImpl](_specversions_v0_2_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md) 44 | 45 | ___ 46 | 47 | ## Methods 48 | 49 | 50 | 51 | ### getSpecVersion 52 | 53 | ▸ **getSpecVersion**(): `object` 54 | 55 | *Implementation of [RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md).[getSpecVersion](../interfaces/_interfaces_.ricardiancontractprocessor.md#getspecversion)* 56 | 57 | *Overrides [RicardianContractProcessorImpl](_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md).[getSpecVersion](_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#getspecversion)* 58 | 59 | *Defined in [specVersions/v0.2/RicardianContractProcessorImpl.ts:23](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.2/RicardianContractProcessorImpl.ts#L23)* 60 | 61 | **Returns:** `object` 62 | 63 | ___ 64 | 65 | 66 | ### process 67 | 68 | ▸ **process**(config: *[RicardianContractConfig](../interfaces/_interfaces_.ricardiancontractconfig.md)*): [RicardianContract](../interfaces/_interfaces_.ricardiancontract.md) 69 | 70 | *Implementation of [RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md).[process](../interfaces/_interfaces_.ricardiancontractprocessor.md#process)* 71 | 72 | *Inherited from [RicardianContractProcessorImpl](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md).[process](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#process)* 73 | 74 | *Defined in [specVersions/v0.0/RicardianContractProcessorImpl.ts:80](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/RicardianContractProcessorImpl.ts#L80)* 75 | 76 | Process the RicardianContractConfig and return a RicardianContract. 77 | 78 | **Parameters:** 79 | 80 | | Name | Type | Description | 81 | | ------ | ------ | ------ | 82 | | config | [RicardianContractConfig](../interfaces/_interfaces_.ricardiancontractconfig.md) | A \`RicardianContractConfig\` object | 83 | 84 | **Returns:** [RicardianContract](../interfaces/_interfaces_.ricardiancontract.md) 85 | 86 | ___ 87 | 88 | 89 | ### `` processContract 90 | 91 | ▸ **processContract**(config: *[RicardianContractConfig](../interfaces/_interfaces_.ricardiancontractconfig.md)*): [RicardianContract](../interfaces/_interfaces_.ricardiancontract.md) 92 | 93 | *Inherited from [RicardianContractProcessorImpl](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md).[processContract](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#processcontract)* 94 | 95 | *Defined in [specVersions/v0.0/RicardianContractProcessorImpl.ts:92](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/RicardianContractProcessorImpl.ts#L92)* 96 | 97 | **Parameters:** 98 | 99 | | Name | Type | 100 | | ------ | ------ | 101 | | config | [RicardianContractConfig](../interfaces/_interfaces_.ricardiancontractconfig.md) | 102 | 103 | **Returns:** [RicardianContract](../interfaces/_interfaces_.ricardiancontract.md) 104 | 105 | ___ 106 | 107 | 108 | ### `` registerHelper 109 | 110 | ▸ **registerHelper**(name: *`string`*, fn: *`HelperDelegate`*): `void` 111 | 112 | *Inherited from [RicardianContractProcessorImpl](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md).[registerHelper](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#registerhelper)* 113 | 114 | *Defined in [specVersions/v0.0/RicardianContractProcessorImpl.ts:67](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/RicardianContractProcessorImpl.ts#L67)* 115 | 116 | **Parameters:** 117 | 118 | | Name | Type | 119 | | ------ | ------ | 120 | | name | `string` | 121 | | fn | `HelperDelegate` | 122 | 123 | **Returns:** `void` 124 | 125 | ___ 126 | 127 | 128 | ### `` registerWrappedHelper 129 | 130 | ▸ **registerWrappedHelper**(name: *`string`*, fn: *`HelperDelegate`*): `void` 131 | 132 | *Inherited from [RicardianContractProcessorImpl](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md).[registerWrappedHelper](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#registerwrappedhelper)* 133 | 134 | *Defined in [specVersions/v0.0/RicardianContractProcessorImpl.ts:62](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/RicardianContractProcessorImpl.ts#L62)* 135 | 136 | **Parameters:** 137 | 138 | | Name | Type | 139 | | ------ | ------ | 140 | | name | `string` | 141 | | fn | `HelperDelegate` | 142 | 143 | **Returns:** `void` 144 | 145 | ___ 146 | 147 | -------------------------------------------------------------------------------- /docs/classes/_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md: -------------------------------------------------------------------------------- 1 | [ricardian-template-toolkit](../README.md) > ["specVersions/v0.1/RicardianContractProcessorImpl"](../modules/_specversions_v0_1_ricardiancontractprocessorimpl_.md) > [RicardianContractProcessorImpl](../classes/_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md) 2 | 3 | # Class: RicardianContractProcessorImpl 4 | 5 | ## Hierarchy 6 | 7 | [RicardianContractProcessorImpl](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md) 8 | 9 | **↳ RicardianContractProcessorImpl** 10 | 11 | ↳ [RicardianContractProcessorImpl](_specversions_v0_2_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md) 12 | 13 | ## Implements 14 | 15 | * [RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md) 16 | 17 | ## Index 18 | 19 | ### Constructors 20 | 21 | * [constructor](_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#constructor) 22 | 23 | ### Methods 24 | 25 | * [getSpecVersion](_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#getspecversion) 26 | * [process](_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#process) 27 | * [processContract](_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#processcontract) 28 | * [registerHelper](_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#registerhelper) 29 | * [registerWrappedHelper](_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#registerwrappedhelper) 30 | 31 | --- 32 | 33 | ## Constructors 34 | 35 | 36 | 37 | ### constructor 38 | 39 | ⊕ **new RicardianContractProcessorImpl**(): [RicardianContractProcessorImpl](_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md) 40 | 41 | *Overrides [RicardianContractProcessorImpl](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md).[constructor](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#constructor)* 42 | 43 | *Defined in [specVersions/v0.1/RicardianContractProcessorImpl.ts:9](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.1/RicardianContractProcessorImpl.ts#L9)* 44 | 45 | **Returns:** [RicardianContractProcessorImpl](_specversions_v0_1_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md) 46 | 47 | ___ 48 | 49 | ## Methods 50 | 51 | 52 | 53 | ### getSpecVersion 54 | 55 | ▸ **getSpecVersion**(): `object` 56 | 57 | *Implementation of [RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md).[getSpecVersion](../interfaces/_interfaces_.ricardiancontractprocessor.md#getspecversion)* 58 | 59 | *Overrides [RicardianContractProcessorImpl](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md).[getSpecVersion](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#getspecversion)* 60 | 61 | *Defined in [specVersions/v0.1/RicardianContractProcessorImpl.ts:18](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.1/RicardianContractProcessorImpl.ts#L18)* 62 | 63 | **Returns:** `object` 64 | 65 | ___ 66 | 67 | 68 | ### process 69 | 70 | ▸ **process**(config: *[RicardianContractConfig](../interfaces/_interfaces_.ricardiancontractconfig.md)*): [RicardianContract](../interfaces/_interfaces_.ricardiancontract.md) 71 | 72 | *Implementation of [RicardianContractProcessor](../interfaces/_interfaces_.ricardiancontractprocessor.md).[process](../interfaces/_interfaces_.ricardiancontractprocessor.md#process)* 73 | 74 | *Inherited from [RicardianContractProcessorImpl](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md).[process](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#process)* 75 | 76 | *Defined in [specVersions/v0.0/RicardianContractProcessorImpl.ts:80](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/RicardianContractProcessorImpl.ts#L80)* 77 | 78 | Process the RicardianContractConfig and return a RicardianContract. 79 | 80 | **Parameters:** 81 | 82 | | Name | Type | Description | 83 | | ------ | ------ | ------ | 84 | | config | [RicardianContractConfig](../interfaces/_interfaces_.ricardiancontractconfig.md) | A \`RicardianContractConfig\` object | 85 | 86 | **Returns:** [RicardianContract](../interfaces/_interfaces_.ricardiancontract.md) 87 | 88 | ___ 89 | 90 | 91 | ### `` processContract 92 | 93 | ▸ **processContract**(config: *[RicardianContractConfig](../interfaces/_interfaces_.ricardiancontractconfig.md)*): [RicardianContract](../interfaces/_interfaces_.ricardiancontract.md) 94 | 95 | *Inherited from [RicardianContractProcessorImpl](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md).[processContract](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#processcontract)* 96 | 97 | *Defined in [specVersions/v0.0/RicardianContractProcessorImpl.ts:92](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/RicardianContractProcessorImpl.ts#L92)* 98 | 99 | **Parameters:** 100 | 101 | | Name | Type | 102 | | ------ | ------ | 103 | | config | [RicardianContractConfig](../interfaces/_interfaces_.ricardiancontractconfig.md) | 104 | 105 | **Returns:** [RicardianContract](../interfaces/_interfaces_.ricardiancontract.md) 106 | 107 | ___ 108 | 109 | 110 | ### `` registerHelper 111 | 112 | ▸ **registerHelper**(name: *`string`*, fn: *`HelperDelegate`*): `void` 113 | 114 | *Inherited from [RicardianContractProcessorImpl](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md).[registerHelper](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#registerhelper)* 115 | 116 | *Defined in [specVersions/v0.0/RicardianContractProcessorImpl.ts:67](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/RicardianContractProcessorImpl.ts#L67)* 117 | 118 | **Parameters:** 119 | 120 | | Name | Type | 121 | | ------ | ------ | 122 | | name | `string` | 123 | | fn | `HelperDelegate` | 124 | 125 | **Returns:** `void` 126 | 127 | ___ 128 | 129 | 130 | ### `` registerWrappedHelper 131 | 132 | ▸ **registerWrappedHelper**(name: *`string`*, fn: *`HelperDelegate`*): `void` 133 | 134 | *Inherited from [RicardianContractProcessorImpl](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md).[registerWrappedHelper](_specversions_v0_0_ricardiancontractprocessorimpl_.ricardiancontractprocessorimpl.md#registerwrappedhelper)* 135 | 136 | *Defined in [specVersions/v0.0/RicardianContractProcessorImpl.ts:62](https://github.com/EOSIO/ricardian-template-toolkit/blob/ae088d5/src/specVersions/v0.0/RicardianContractProcessorImpl.ts#L62)* 137 | 138 | **Parameters:** 139 | 140 | | Name | Type | 141 | | ------ | ------ | 142 | | name | `string` | 143 | | fn | `HelperDelegate` | 144 | 145 | **Returns:** `void` 146 | 147 | ___ 148 | 149 | -------------------------------------------------------------------------------- /examples/abi.json: -------------------------------------------------------------------------------- 1 | { 2 | "abi": { 3 | "types": [ 4 | { 5 | "type": "name", 6 | "new_type_name": "account_name" 7 | } 8 | ], 9 | "tables": [ 10 | { 11 | "name": "accounts", 12 | "type": "account", 13 | "key_names": [ 14 | "currency" 15 | ], 16 | "key_types": [ 17 | "uint64" 18 | ], 19 | "index_type": "i64" 20 | }, 21 | { 22 | "name": "stat", 23 | "type": "currency_stats", 24 | "key_names": [ 25 | "currency" 26 | ], 27 | "key_types": [ 28 | "uint64" 29 | ], 30 | "index_type": "i64" 31 | } 32 | ], 33 | "actions": [ 34 | { 35 | "name": "transfer", 36 | "type": "transfer", 37 | "ricardian_contract": "---\ntitle: Token Transfer\nsummary: Transfer tokens from {{from}} to {{to}}.\nicon: http://simpleicon.com/wp-content/uploads/like.png#d0da4e5d44e4f2d325109010203fda422d3f7cd4934d874cb4ea98a62bf16cec\n---\n\n## Transfer Terms & Conditions\n\nI, {{from}}, certify the following to be true to the best of my knowledge:\n\n1. I certify that {{quantity}} is not the proceeds of fraudulent or violent activities.\n2. I certify that, to the best of my knowledge, {{to}} is not supporting initiation of violence against others.\n3. I have disclosed any contractual \"terms & conditions\" with respect to {{quantity}} to {{to}}.\n\nI understand that funds transfers are not reversible after the {{$transaction.delay_sec}} seconds or other delay as configured by {{from}}'s permissions.\n\nIf this action fails to be irreversibly confirmed after receiving goods or services from '{{to}}', I agree to either return the goods or services or resend {{quantity}} in a timely manner.\n" 38 | }, 39 | { 40 | "name": "multitransf", 41 | "type": "multitransf", 42 | "ricardian_contract": "---\ntitle: Multi Token Transfer\nsummary: Transfer multiple different tokens from {{from}} to {{to}}.\nicon: https://a.com/token-transfer.png#00506E08A55BCF269FE67F202BBC08CFF55F9E3C7CD4459ECB90205BF3C3B562\n---\n\n# Super Multi Transfer with whole ABI Meta Data\n\n![header-img](https://cdn-images-1.medium.com/max/900/1*zkkZqd1_ShN9rRqBG_Wu3A@2x.png#HA8HG03SH3R3HA8HG03SH3R3HA8HG03SH3R3)\n\n

This contract action is NOT a real one, and not related to `eosio.token` at all.
\nJust an example of testing all the contract parsings with handlebars.

\n\n## Transfer Terms & Conditions\n\nI, {{from}}, certify the following to be true to the best of my knowledge:\n\n1. I certify that the total amount of this transfer does not the proceeds of fraudulent or violent activities.\n2. I certify that, to the best of my knowledge, {{to}} is not supporting initiation of violence against others.\n3. I have disclosed any contractual terms & conditions with respect to {{to}}.\n\nThe transfered tokens are:\n\n{{#each quantities}}\n - {{@index}}: {{{lookup ../memos @index}}} {{this}}\n{{else}}\n Not transfer\n{{/each}}\n\nAnd these are the reasons:\n\n{{#each memos}}\n {{{this}}}\n{{else}}\n Not transfer\n{{/each}}\n\nI understand that funds transfers are not reversible after the {{$transaction.delay_sec}} seconds or other delay as configured by {{from}}'s permissions.\n\nIf this action fails to be irreversibly confirmed after receiving goods or services from '{{to}}', I agree to either return the goods or services or resend all over again in a timely manner.\n\n### Transaction metadata\n\n- expiration: {{$transaction.expiration}}\n- ref_block_num: {{$transaction.ref_block_num}}\n- ref_block_prefix: {{$transaction.ref_block_prefix}}\n- max_net_usage_words: {{$transaction.max_net_usage_words}}\n- max_cpu_usage_ms: {{$transaction.max_cpu_usage_ms}}\n- delay_sec: {{$transaction.delay_sec}}\n- context_free_actions: {{$transaction.context_free_actions}}\n\n### Action Metadata\n\n- account: {{$action.account}}\n- name: {{$action.name}}\n- authorization: {{$action.authorization}}\n- authorization.[0].actor: {{$action.authorization.[0].actor}}\n- authorization.[0].permission: {{$action.authorization.[0].permission}}\n\n{{#if $transaction.actions.[1]}}\n ### That's not all!!! :)\n\n I'm also sending you {{$transaction.actions.[1].data.quantity}} - because {{$transaction.actions.[1].data.memo}}\n{{else}}\n **That's it!**\n{{/if}}\n\n\n#### Transaction Contract Clauses\n\n{{$clauses.boilerplate}}\n\n{{$clauses.ricardian_contract_images}}\n\n{{$clauses.ricardian_clause_interpolations}}\n" 43 | }, 44 | { 45 | "name": "issue", 46 | "type": "issue", 47 | "ricardian_contract": "" 48 | }, 49 | { 50 | "name": "create", 51 | "type": "create", 52 | "ricardian_contract": "" 53 | } 54 | ], 55 | "structs": [ 56 | { 57 | "base": "", 58 | "name": "transfer", 59 | "fields": [ 60 | { 61 | "name": "from", 62 | "type": "account_name" 63 | }, 64 | { 65 | "name": "to", 66 | "type": "account_name" 67 | }, 68 | { 69 | "name": "quantity", 70 | "type": "asset" 71 | }, 72 | { 73 | "name": "memo", 74 | "type": "string" 75 | } 76 | ] 77 | }, 78 | { 79 | "base": "", 80 | "name": "multitransf", 81 | "fields": [ 82 | { 83 | "name": "from", 84 | "type": "account_name" 85 | }, 86 | { 87 | "name": "to", 88 | "type": "account_name" 89 | }, 90 | { 91 | "name": "quantities", 92 | "type": "asset[]" 93 | }, 94 | { 95 | "name": "memos", 96 | "type": "string[]" 97 | } 98 | ] 99 | }, 100 | { 101 | "base": "", 102 | "name": "create", 103 | "fields": [ 104 | { 105 | "name": "issuer", 106 | "type": "account_name" 107 | }, 108 | { 109 | "name": "maximum_supply", 110 | "type": "asset" 111 | } 112 | ] 113 | }, 114 | { 115 | "base": "", 116 | "name": "issue", 117 | "fields": [ 118 | { 119 | "name": "to", 120 | "type": "account_name" 121 | }, 122 | { 123 | "name": "quantity", 124 | "type": "asset" 125 | }, 126 | { 127 | "name": "memo", 128 | "type": "string" 129 | } 130 | ] 131 | }, 132 | { 133 | "base": "", 134 | "name": "account", 135 | "fields": [ 136 | { 137 | "name": "balance", 138 | "type": "asset" 139 | } 140 | ] 141 | }, 142 | { 143 | "base": "", 144 | "name": "currency_stats", 145 | "fields": [ 146 | { 147 | "name": "supply", 148 | "type": "asset" 149 | }, 150 | { 151 | "name": "max_supply", 152 | "type": "asset" 153 | }, 154 | { 155 | "name": "issuer", 156 | "type": "account_name" 157 | } 158 | ] 159 | } 160 | ], 161 | "version": "eosio::abi/1.0", 162 | "abi_extensions": [], 163 | "error_messages": [], 164 | "ricardian_clauses": [ 165 | { 166 | "id": "boilerplate", 167 | "body": "I, {{from}}, swear by the moon and the stars in the sky\nI'll be there\nI swear like a shadow that's by your side\nI'll be there\n\nFor better or worse, till death do us part\nI'll love you with every beat of my heart\nAnd I swear" 168 | }, 169 | { 170 | "id": "ricardian_contract_images", 171 | "body": "![EOS ricardian_contract_images](https://files.readme.io/aeb2530-small-logo_2x.png#HA8HG03SH3R3)" 172 | }, 173 | { 174 | "id": "ricardian_clause_interpolations", 175 | "body": "You are sending this transfer from the account: {{from}}" 176 | } 177 | ] 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/specVersions/v0.0/helpers.test.ts: -------------------------------------------------------------------------------- 1 | import { indexedTransferTransaction, transferTransaction } from '../../testfixtures/fixtures' 2 | import * as helpers from './helpers' 3 | 4 | const indexedTestTransferTransaction: any = JSON.parse(indexedTransferTransaction) 5 | // tslint:disable-next-line:max-line-length 6 | const transferRicardian: string = '---\ntitle: Token Transfer\nsummary: Transfer tokens from one account to another.\nicon: https://a.com/token-transfer.png#00506E08A55BCF269FE67F202BBC08CFF55F9E3C7CD4459ECB90205BF3C3B562\n---\n\n## Transfer Terms & Conditions\n\nI, {{from}}, certify the following to be true to the best of my knowledge:\n\n1. I certify that {{quantity}} is not the proceeds of fraudulent or violent activities.\n2. I certify that, to the best of my knowledge, {{to}} is not supporting initiation of violence against others.\n3. I have disclosed any contractual terms & conditions with respect to {{quantity}} to {{to}}.\n\nI understand that funds transfers are not reversible after the {{$transaction.delay_sec}} seconds or other delay as configured by {{from}}\'s permissions.\n\nIf this action fails to be irreversibly confirmed after receiving goods or services from \'{{to}}\', I agree to either return the goods or services or resend {{quantity}} in a timely manner.\n\n{{$clauses.ricardian_clause_interpolations}}\n\nOh, and one more thing...\n\n{{$clauses.boilerplate}}\n\n{{$clauses.ricardian_contract_images}}' 7 | 8 | describe('indexTransaction Helper', (): void => { 9 | it('adds $index properties to every array in the transaction', (): void => { 10 | const indexed: any = helpers.indexTransaction(JSON.parse(transferTransaction)) 11 | expect(indexed).toEqual(indexedTestTransferTransaction) 12 | }) 13 | }) 14 | 15 | describe('extractSymbolCode Helper', (): void => { 16 | it('extracts the symbol code from an asset', (): void => { 17 | const asset = '2.001 EOS' 18 | const code = helpers.extractSymbolCode(asset) 19 | expect(code).toEqual('EOS') 20 | }) 21 | 22 | it('extracts the symbol code from a symbol', (): void => { 23 | const symbol = '4,EOS' 24 | const code = helpers.extractSymbolCode(symbol) 25 | expect(code).toEqual('EOS') 26 | }) 27 | 28 | it('returns empty string on improperly formatted input', (): void => { 29 | const symbol = '123.456' 30 | const code = helpers.extractSymbolCode(symbol) 31 | expect(code).toEqual('') 32 | }) 33 | }) 34 | 35 | describe('hasVariable Helper', (): void => { 36 | it('detects uninterpolated variables in the Ricardian Contract', (): void => { 37 | expect(helpers.hasVariable(transferRicardian)).toBe(true) 38 | }) 39 | 40 | it('detects the various types of uninterpolated handlebars variables', (): void => { 41 | const a = helpers.hasVariable('test {{> components/templates/email/includes/email-tr-spacer }} test') 42 | const b = helpers.hasVariable('{{# deliveryAddress }} test') 43 | const c = helpers.hasVariable('test {{^ deliveryAddress }}') 44 | const d = helpers.hasVariable('{{{ deliveryAddressReadable }}}') 45 | const e = helpers.hasVariable('{{/ deliveryAddress }}') 46 | const f = helpers.hasVariable('test {{test}}') 47 | expect(a && b && c && d && e && f).toBe(true) 48 | }) 49 | 50 | it('returns false when the given string has no variables', (): void => { 51 | expect(helpers.hasVariable('This is a test.')).toBe(false) 52 | }) 53 | }) 54 | 55 | describe('tagTemplateVariables Helper', (): void => { 56 | it('wraps all valid variables', (): void => { 57 | const template = '{{from}} is sending {{ quantity }} to {{ to }} for {{{memo}}}.' 58 | // tslint:disable-next-line:max-line-length 59 | const wrapped = '{{#wrap class="data"}}{{from}}{{/wrap}} is sending {{#wrap class="data"}}{{quantity}}{{/wrap}} to {{#wrap class="data"}}{{to}}{{/wrap}} for {{#wrap class="data"}}{{{memo}}}{{/wrap}}.' 60 | expect(helpers.tagTemplateVariables([ 'lookup' ], template)).toEqual(wrapped) 61 | }) 62 | 63 | it('wraps all valid pseudo variables', (): void => { 64 | // tslint:disable-next-line:max-line-length 65 | const template: string = '{{$transaction.delay_sec}} seconds will pass before the {{ $action.account }}::{{ $action.name }} takes place. {{{$clauses.boilerplate}}}; {{$transaction.actions.[0].data.from}}' 66 | // tslint:disable-next-line:max-line-length 67 | const wrapped: string = '{{#wrap class="transaction"}}{{$transaction.delay_sec}}{{/wrap}} seconds will pass before the {{#wrap class="action"}}{{$action.account}}{{/wrap}}::{{#wrap class="action"}}{{$action.name}}{{/wrap}} takes place. {{#wrap class="clauses"}}{{{$clauses.boilerplate}}}{{/wrap}}; {{#wrap class="transaction"}}{{$transaction.actions.[0].data.from}}{{/wrap}}' 68 | expect(helpers.tagTemplateVariables([ 'lookup' ], template)).toEqual(wrapped) 69 | }) 70 | 71 | it('does not wrap non-variable handlebars tags', (): void => { 72 | // tslint:disable-next-line:max-line-length 73 | const template: string = '{{> from }} seconds will pass before the {{^$action.account}}::{{{^$action.name}}} takes place. {{{# $clauses.boilerplate }}}; {{/ $transaction.actions.[0].data.from }}. And {{valid}}.' 74 | // tslint:disable-next-line:max-line-length 75 | const wrapped: string = '{{> from }} seconds will pass before the {{^$action.account}}::{{{^$action.name}}} takes place. {{{# $clauses.boilerplate }}}; {{/ $transaction.actions.[0].data.from }}. And {{#wrap class="data"}}{{valid}}{{/wrap}}.' 76 | expect(helpers.tagTemplateVariables([ 'lookup' ], template)).toEqual(wrapped) 77 | }) 78 | 79 | it('does not wrap \'if\' clause elements', () => { 80 | const template: string = 'This {{#if animal}}{{animal}}{{else}}{{mineral}}{{/if}} is kind of weird.' 81 | // tslint:disable-next-line:max-line-length 82 | const wrapped: string = 'This {{#if animal}}{{#wrap class="data"}}{{animal}}{{/wrap}}{{else}}{{#wrap class="data"}}{{mineral}}{{/wrap}}{{/if}} is kind of weird.' 83 | expect(helpers.tagTemplateVariables([ 'lookup' ], template)).toEqual(wrapped) 84 | }) 85 | 86 | it('does not wrap variables surrounded by more than 3 brackets', (): void => { 87 | const template: string = '{{{{testing}}}} {{okay}} {{{not}}}} {{{{okay}}}' 88 | const wrapped: string = '{{{{testing}}}} {{#wrap class="data"}}{{okay}}{{/wrap}} {{{not}}}} {{{{okay}}}' 89 | expect(helpers.tagTemplateVariables([ 'lookup' ], template)).toEqual(wrapped) 90 | }) 91 | }) 92 | 93 | describe('sanitizeHtml Helper', (): void => { 94 | it('throws error on non-whitelisted tags', (): void => { 95 | const html = '
His power is over 9000
' 96 | expect(() => helpers.sanitizeHtml(html)).toThrow(/Disallowed tag "shocked" found/) 97 | }) 98 | 99 | it('throws error on non-whitelisted attributes', (): void => { 100 | const html = '
His power is over

9000

' 101 | expect(() => helpers.sanitizeHtml(html)).toThrow(/Disallowed attribute "mass" found on tag "h1"/) 102 | }) 103 | 104 | it('throws error on mismatched tags', () => { 105 | const html = '
His power is over

9000

' 106 | expect(() => helpers.sanitizeHtml(html)).toThrow(/Unexpected closing tag "div"; expected closing tag for "h1"/) 107 | }) 108 | 109 | it('throws error on improper close tag for empty element', () => { 110 | const html = '
His power is over

9000



' 111 | expect(() => helpers.sanitizeHtml(html)).toThrow(/Unexpected closing tag for empty element "br"/) 112 | }) 113 | 114 | it('throws error on unclosed tag', () => { 115 | const html = '
His power is over

9000

' 116 | expect(() => helpers.sanitizeHtml(html)).toThrow(/Expected closing tag for "div" not found/) 117 | }) 118 | 119 | it('throws error on unmatched closing tag', () => { 120 | const html = '
His power is over

9000

' 121 | expect(() => helpers.sanitizeHtml(html)).toThrow(/Unexpected closing tag "h2"; expected closing tag for "div"/) 122 | }) 123 | 124 | it('throws error on unmatched trailing closing tag', () => { 125 | const html = '
His power is over

9000

' 126 | expect(() => helpers.sanitizeHtml(html)).toThrow(/Unexpected closing tag "h2" with no open tag/) 127 | }) 128 | }) 129 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EOSIO.CDT Ricardian Template Toolkit ![EOSIO Alpha](https://img.shields.io/badge/EOSIO-Alpha-blue.svg) 2 | 3 | This library is a new tool in the suite of tools from [EOSIO.CDT (Contract Development Toolkit)](https://github.com/EOSIO/eosio.cdt/tree/develop), and should allow for a more robust and rich environment for writing **Ricardian** contracts for your **EOSIO** smart contracts. 4 | 5 | ## Overview 6 | 7 | The Ricardian Template Toolkit is an implementation of a renderer for the [Ricardian Contract Specification](https://github.com/EOSIO/ricardian-spec) that demonstrates how Ricardian Contracts built to the specification can be displayed. This toolkit can be used by Authenticator developers to consistently render Ricardian Contracts and by Smart Contract developers as an authoring and testing tool. 8 | 9 | Together, the Ricardian Template Toolkit and Ricardian Contract Specification projects enable a clear understanding of the agreements to which users are consenting in Authenticators which ask them to sign transactions. 10 | 11 | This library contains a factory that takes an ABI object, a transaction object, and an action index (along with some developer-oriented flags). It then: 12 | 13 | 1. Selects an appropriate processor based on the `spec_version` field in the contract metadata 14 | 1. Validates the Ricardian Contracts and metadata associated with the transaction actions 15 | 1. Validates all other spec requirements, including image sizes and hashes 16 | 1. Interpolates all variables with data from the transaction or ricardian_clauses 17 | 1. On success, returns an object with metadata and Contract Markup Language (CML, a subset of HTML) 18 | 1. On error or validation failure, returns a descriptive error, along with any data it was able to successfully parse and render 19 | 20 | Foundational Inspiration for Metadata: 21 | - https://hiltmon.com/blog/2012/06/18/markdown-metadata/ 22 | - https://blog.github.com/2013-09-27-viewing-yaml-metadata-in-your-documents/ 23 | - https://stackoverflow.com/questions/44215896/markdown-metadata-format#answer-44222826 24 | 25 | 26 | ## Installation 27 | 28 | `yarn add ricardian-template-toolkit` 29 | 30 | ## Command Line Tool 31 | 32 | The toolkit includes a simple command line wrapper around the library for local testing of HTML generation. If you install the package globally, the `rc` command will be available on the command line. If running locally, use (within the project root) `./bin/rc`. Given an ABI, transaction data (fully deserialized), and optionally the transaction index (default 0) the `rc` command will output the generated HTML fragment. 33 | 34 | Example: 35 | ``` 36 | rc -a myabi.json -t mytxn.json -i 1 37 | ``` 38 | 39 | The metadata is also available with the `--only-metadata` option. 40 | 41 | Example: 42 | ``` 43 | rc -a myabi.json -t mytxn.json -i 1 --only-metadata 44 | ``` 45 | 46 | Help is available with `rc --help`. 47 | 48 | ## Running Locally 49 | 50 | ``` 51 | yarn install 52 | yarn build 53 | yarn example 54 | ``` 55 | 56 | ## Other Commands 57 | 58 | * `yarn lint` 59 | * `yarn test` 60 | 61 | ## Ricardian Specification 62 | 63 | The Ricardian Specification and an example of a compliant Ricardian contract can now be found at https://github.com/EOSIO/ricardian-spec. 64 | 65 | ## Usage 66 | 67 | Usage is very straightforward: 68 | 69 | ```javascript 70 | import { RicardianContractFactory} from 'ricardian-template-toolkit' 71 | 72 | ... 73 | 74 | // Create the factory instance. 75 | const factory = new RicardianContractFactory() 76 | 77 | // Construct a RicardianContractConfig object 78 | const config = { 79 | abi: myAbi, 80 | transaction: myTransaction, 81 | actionIndex: 0, 82 | // Optional - defaults to 3 83 | maxPasses: 3, 84 | // Optional - developer flag - if true ignore errors if a variable 85 | // is specified in the contract but no value is found to substitute 86 | allowUnusedVariables: false 87 | } 88 | 89 | const ricardianContract = factory.create(config) 90 | 91 | const metadata = ricardianContract.getMetadata() 92 | const html = ricardianContract.getHtml() 93 | ``` 94 | 95 | ## Backward Compatibility Note 96 | 97 | Be aware that for backward compatibility with contract specifications prior to `0.1.0`, any contracts 98 | lacking a `spec_version` in the metadata are treated as following spec version `0.0.0`. 99 | 100 | ## Example 101 | The following is based on the [example from the Ricardian Contract Specification](https://github.com/EOSIO/ricardian-spec#example-template) 102 | 103 | Raw HTML Output 104 | ``` 105 | I,
bobsmith
, author of the blog post "
An Example Post
", certify that I am the original author of the contents of this blog post and have attributed all external sources appropriately.
106 |
WARRANTY. The invoker of the contract action shall uphold its Obligations under this Contract in a timely and workmanlike manner, using knowledge and recommendations for performing the services which meet generally acceptable standards set forth by EOS.IO Blockchain Block Producers.

107 | ``` 108 | 109 | Styled HTML 110 | ``` 111 | 112 | 113 | 127 | 128 | 129 | 130 | I,
bobsmith
, author of the blog post "
An Example Post
", certify that I am the original author of the contents of this blog post and have attributed all external sources appropriately.
131 |
WARRANTY. The invoker of the contract action shall uphold its Obligations under this Contract in a timely and workmanlike manner, using knowledge and recommendations for performing the services which meet generally acceptable standards set forth by EOS.IO Blockchain Block Producers.

132 | 133 | 134 | ``` 135 | Rendered Styled HTML 136 | Styled HTML Example 137 | 138 | ## Contributing 139 | 140 | [Contributing Guide](./CONTRIBUTING.md) 141 | 142 | [Code of Conduct](./CONTRIBUTING.md#conduct) 143 | 144 | ## License 145 | 146 | [MIT](./LICENSE) 147 | 148 | ## Important 149 | 150 | See LICENSE for copyright and license terms. Block.one makes its contribution on a voluntary basis as a member of the EOSIO community and is not responsible for ensuring the overall performance of the software or any related applications. We make no representation, warranty, guarantee or undertaking in respect of the software or any related documentation, whether expressed or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall we be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or documentation or the use or other dealings in the software or documentation. Any test results or performance figures are indicative and will not reflect performance under all conditions. Any reference to any third party or third-party product, service or other resource is not an endorsement or recommendation by Block.one. We are not responsible, and disclaim any and all responsibility and liability, for your use of or reliance on any of these resources. Third-party resources may be updated, changed or terminated at any time, so the information here may be out of date or inaccurate. Any person using or offering this software in connection with providing software, goods or services to third parties shall advise such third parties of these license terms, disclaimers and exclusions of liability. Block.one, EOSIO, EOSIO Labs, EOS, the heptahedron and associated logos are trademarks of Block.one. 151 | 152 | Wallets and related components are complex software that require the highest levels of security. If incorrectly built or used, they may compromise users’ private keys and digital assets. Wallet applications and related components should undergo thorough security evaluations before being used. Only experienced developers should work with this software. 153 | -------------------------------------------------------------------------------- /src/testfixtures/fixtures.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:max-line-length */ 2 | export const transferTransaction: string = `{ 3 | "expiration": "2018-08-14T20:38:58", 4 | "ref_block_num": 63462, 5 | "ref_block_prefix": 4279361130, 6 | "max_net_usage_words": 0, 7 | "max_cpu_usage_ms": 0, 8 | "delay_sec": 0, 9 | "context_free_actions": [], 10 | "actions": [ 11 | { 12 | "account": "eosio.token", 13 | "name": "transfer", 14 | "authorization": [ 15 | { 16 | "actor": "alicejones", 17 | "permission": "active" 18 | } 19 | ], 20 | "data": { 21 | "from": "alicejones", 22 | "to": "bobsmith", 23 | "quantity": "1500.0000 EOS", 24 | "memo": "This is a test of the emergency broadcasting system." 25 | } 26 | }, 27 | { 28 | "account": "eosio.token", 29 | "name": "transfer", 30 | "authorization": [ 31 | { 32 | "actor": "bobsmith", 33 | "permission": "active" 34 | } 35 | ], 36 | "data": { 37 | "from": "bobsmith", 38 | "to": "alicejones", 39 | "quantity": "123.0000 EOS", 40 | "memo": "Testing." 41 | } 42 | }, 43 | { 44 | "account": "eosio.token", 45 | "name": "transfer", 46 | "authorization": [ 47 | { 48 | "actor": "bobsmith", 49 | "permission": "active" 50 | } 51 | ], 52 | "data": { 53 | "from": "bobsmith", 54 | "to": "alicejones", 55 | "quantity": "123.0000 EOS", 56 | "memo": "Testing.", 57 | "$metadata": { 58 | "summary": "Transfer from {{from}} to {{to}}" 59 | } 60 | } 61 | } 62 | ], 63 | "transaction_extensions": [] 64 | }` 65 | 66 | export const indexedTransferTransaction: string = `{ 67 | "expiration": "2018-08-14T20:38:58", 68 | "ref_block_num": 63462, 69 | "ref_block_prefix": 4279361130, 70 | "max_net_usage_words": 0, 71 | "max_cpu_usage_ms": 0, 72 | "delay_sec": 0, 73 | "context_free_actions": [], 74 | "actions": [ 75 | { 76 | "account": "eosio.token", 77 | "name": "transfer", 78 | "authorization": [ 79 | { 80 | "actor": "alicejones", 81 | "permission": "active", 82 | "$index": 0 83 | } 84 | ], 85 | "data": { 86 | "from": "alicejones", 87 | "to": "bobsmith", 88 | "quantity": "1500.0000 EOS", 89 | "memo": "This is a test of the emergency broadcasting system." 90 | }, 91 | "$index": 0 92 | }, 93 | { 94 | "account": "eosio.token", 95 | "name": "transfer", 96 | "authorization": [ 97 | { 98 | "actor": "bobsmith", 99 | "permission": "active", 100 | "$index": 0 101 | } 102 | ], 103 | "data": { 104 | "from": "bobsmith", 105 | "to": "alicejones", 106 | "quantity": "123.0000 EOS", 107 | "memo": "Testing." 108 | }, 109 | "$index": 1 110 | }, 111 | { 112 | "account": "eosio.token", 113 | "name": "transfer", 114 | "authorization": [ 115 | { 116 | "actor": "bobsmith", 117 | "permission": "active", 118 | "$index": 0 119 | } 120 | ], 121 | "data": { 122 | "from": "bobsmith", 123 | "to": "alicejones", 124 | "quantity": "123.0000 EOS", 125 | "memo": "Testing.", 126 | "$metadata": { 127 | "summary": "Transfer from {{from}} to {{to}}" 128 | } 129 | }, 130 | "$index": 2 131 | } 132 | ], 133 | "transaction_extensions": [] 134 | }` 135 | 136 | export const eosioTokenAbi: string = `{ 137 | "types": [ 138 | { 139 | "type": "name", 140 | "new_type_name": "account_name" 141 | } 142 | ], 143 | "tables": [ 144 | { 145 | "name": "accounts", 146 | "type": "account", 147 | "key_names": [ 148 | "currency" 149 | ], 150 | "key_types": [ 151 | "uint64" 152 | ], 153 | "index_type": "i64" 154 | }, 155 | { 156 | "name": "stat", 157 | "type": "currency_stats", 158 | "key_names": [ 159 | "currency" 160 | ], 161 | "key_types": [ 162 | "uint64" 163 | ], 164 | "index_type": "i64" 165 | } 166 | ], 167 | "actions": [ 168 | { 169 | "name": "transfer", 170 | "type": "transfer", 171 | "ricardian_contract": "---\\ntitle: Token Transfer\\nsummary: Transfer tokens from one account to another.\\nicon: https://a.com/token-transfer.png#00506E08A55BCF269FE67F202BBC08CFF55F9E3C7CD4459ECB90205BF3C3B562\\n---\\n\\n## Transfer Terms & Conditions\\n\\nI, {{from}}, certify the following to be true to the best of my knowledge:\\n\\n1. I certify that {{quantity}} is not the proceeds of fraudulent or violent activities.\\n2. I certify that, to the best of my knowledge, {{to}} is not supporting initiation of violence against others.\\n3. I have disclosed any contractual terms & conditions with respect to {{quantity}} to {{to}}.\\n\\nI understand that funds transfers are not reversible after the {{$transaction.delay_sec}} seconds or other delay as configured by {{from}}'s permissions.\\n\\nIf this action fails to be irreversibly confirmed after receiving goods or services from '{{to}}', I agree to either return the goods or services or resend {{quantity}} in a timely manner.\\n\\n{{$clauses.ricardian_clause_interpolations}}\\n\\nOh, and one more thing...\\n\\n{{$clauses.boilerplate}}\\n\\n{{$clauses.ricardian_contract_images}}" 172 | }, 173 | { 174 | "name": "issue", 175 | "type": "issue", 176 | "ricardian_contract": "" 177 | }, 178 | { 179 | "name": "create", 180 | "type": "create", 181 | "ricardian_contract": "" 182 | } 183 | ], 184 | "structs": [ 185 | { 186 | "base": "", 187 | "name": "transfer", 188 | "fields": [ 189 | { 190 | "name": "from", 191 | "type": "account_name" 192 | }, 193 | { 194 | "name": "to", 195 | "type": "account_name" 196 | }, 197 | { 198 | "name": "quantity", 199 | "type": "asset" 200 | }, 201 | { 202 | "name": "memo", 203 | "type": "string" 204 | } 205 | ] 206 | }, 207 | { 208 | "base": "", 209 | "name": "create", 210 | "fields": [ 211 | { 212 | "name": "issuer", 213 | "type": "account_name" 214 | }, 215 | { 216 | "name": "maximum_supply", 217 | "type": "asset" 218 | } 219 | ] 220 | }, 221 | { 222 | "base": "", 223 | "name": "issue", 224 | "fields": [ 225 | { 226 | "name": "to", 227 | "type": "account_name" 228 | }, 229 | { 230 | "name": "quantity", 231 | "type": "asset" 232 | }, 233 | { 234 | "name": "memo", 235 | "type": "string" 236 | } 237 | ] 238 | }, 239 | { 240 | "base": "", 241 | "name": "account", 242 | "fields": [ 243 | { 244 | "name": "balance", 245 | "type": "asset" 246 | } 247 | ] 248 | }, 249 | { 250 | "base": "", 251 | "name": "currency_stats", 252 | "fields": [ 253 | { 254 | "name": "supply", 255 | "type": "asset" 256 | }, 257 | { 258 | "name": "max_supply", 259 | "type": "asset" 260 | }, 261 | { 262 | "name": "issuer", 263 | "type": "account_name" 264 | } 265 | ] 266 | } 267 | ], 268 | "version": "eosio::abi/1.0", 269 | "abi_extensions": [], 270 | "error_messages": [], 271 | "ricardian_clauses": [ 272 | { 273 | "id": "boilerplate", 274 | "body": "I, {{from}}, swear by the moon and the stars in the sky\\nI'll be there\\nI swear like a shadow that's by your side\\nI'll be there\\n\\nFor better or worse, till death do us part\\nI'll love you with every beat of my heart\\nAnd I swear" 275 | }, 276 | { 277 | "id": "ricardian_contract_images", 278 | "body": "![EOS ricardian_contract_images](https://files.readme.io/aeb2530-small-logo_2x.png#HA8HG03SH3R3)" 279 | }, 280 | { 281 | "id": "ricardian_clause_interpolations", 282 | "body": "You are sending this transfer with the following memo: {{memo}}" 283 | } 284 | ] 285 | }` 286 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to EOSIO Ricardian Template Toolkit 2 | 3 | Interested in contributing? That's awesome! Here are some guidelines to get started quickly and easily: 4 | 5 | - [Reporting An Issue](#reporting-an-issue) 6 | - [Bug Reports](#bug-reports) 7 | - [Feature Requests](#feature-requests) 8 | - [Change Requests](#change-requests) 9 | - [Working on Ricardian Template Toolkit](#working-on-friendlyname) 10 | - [Feature Branches](#feature-branches) 11 | - [Submitting Pull Requests](#submitting-pull-requests) 12 | - [Testing and Quality Assurance](#testing-and-quality-assurance) 13 | - [Conduct](#conduct) 14 | - [Contributor License & Acknowledgments](#contributor-license--acknowledgments) 15 | - [References](#references) 16 | 17 | ## Reporting An Issue 18 | 19 | If you're about to raise an issue because you think you've found a problem with Ricardian Template Toolkit, or you'd like to make a request for a new feature in the codebase, or any other reason… please read this first. 20 | 21 | The GitHub issue tracker is the preferred channel for [bug reports](#bug-reports), [feature requests](#feature-requests), and [submitting pull requests](#submitting-pull-requests), but please respect the following restrictions: 22 | 23 | * Please **search for existing issues**. Help us keep duplicate issues to a minimum by checking to see if someone has already reported your problem or requested your idea. 24 | 25 | * Please **be civil**. Keep the discussion on topic and respect the opinions of others. See also our [Contributor Code of Conduct](#conduct). 26 | 27 | ### Bug Reports 28 | 29 | A bug is a _demonstrable problem_ that is caused by the code in the repository. Good bug reports are extremely helpful - thank you! 30 | 31 | Guidelines for bug reports: 32 | 33 | 1. **Use the GitHub issue search** — check if the issue has already been 34 | reported. 35 | 36 | 1. **Check if the issue has been fixed** — look for [closed issues in the 37 | current milestone](https://github.com/EOSIO/ricardian-template-toolkit/issues?q=is%3Aissue+is%3Aclosed) or try to reproduce it 38 | using the latest `develop` branch. 39 | 40 | A good bug report shouldn't leave others needing to chase you up for more information. Be sure to include the details of your environment and relevant tests that demonstrate the failure. 41 | 42 | [Report a bug](https://github.com/EOSIO/ricardian-template-toolkit/issues/new?title=Bug%3A) 43 | 44 | ### Feature Requests 45 | 46 | Feature requests are welcome. Before you submit one be sure to have: 47 | 48 | 1. **Use the GitHub search** and check the feature hasn't already been requested. 49 | 1. Take a moment to think about whether your idea fits with the scope and aims of the project. 50 | 1. Remember, it's up to *you* to make a strong case to convince the project's leaders of the merits of this feature. Please provide as much detail and context as possible, this means explaining the use case and why it is likely to be common. 51 | 52 | ### Change Requests 53 | 54 | Change requests cover both architectural and functional changes to how Ricardian Template Toolkit works. If you have an idea for a new or different dependency, a refactor, or an improvement to a feature, etc - please be sure to: 55 | 56 | 1. **Use the GitHub search** and check someone else didn't get there first 57 | 1. Take a moment to think about the best way to make a case for, and explain what you're thinking. Are you sure this shouldn't really be 58 | a [bug report](#bug-reports) or a [feature request](#feature-requests)? Is it really one idea or is it many? What's the context? What problem are you solving? Why is what you are suggesting better than what's already there? 59 | 60 | ## Working on Ricardian Template Toolkit 61 | 62 | Code contributions are welcome and encouraged! If you are looking for a good place to start, check out the [good first issue](https://github.com/EOSIO/ricardian-template-toolkit/labels/good%20first%20issue) label in GitHub issues. 63 | 64 | Also, please follow these guidelines when submitting code: 65 | 66 | ### Feature Branches 67 | 68 | To get it out of the way: 69 | 70 | - **[develop](https://github.com/EOSIO/ricardian-template-toolkit/tree/develop)** is the development branch. All work on the next release happens here so you should generally branch off `develop`. Do **NOT** use this branch for a production site. 71 | - **[master](https://github.com/EOSIO/ricardian-template-toolkit/tree/master)** contains the latest release of Ricardian Template Toolkit. This branch may be used in production. Do **NOT** use this branch to work on Ricardian Template Toolkit's source. 72 | 73 | ### Submitting Pull Requests 74 | 75 | Pull requests are awesome. If you're looking to raise a PR for something which doesn't have an open issue, please think carefully about [raising an issue](#reporting-an-issue) which your PR can close, especially if you're fixing a bug. This makes it more likely that there will be enough information available for your PR to be properly tested and merged. 76 | 77 | ### Testing and Quality Assurance 78 | 79 | Never underestimate just how useful quality assurance is. If you're looking to get involved with the code base and don't know where to start, checking out and testing a pull request is one of the most useful things you could do. 80 | 81 | Essentially, [check out the latest develop branch](#working-on-Ricardian Template Toolkit), take it for a spin, and if you find anything odd, please follow the [bug report guidelines](#bug-reports) and let us know! 82 | 83 | ## Conduct 84 | 85 | While contributing, please be respectful and constructive, so that participation in our project is a positive experience for everyone. 86 | 87 | Examples of behavior that contributes to creating a positive environment include: 88 | - Using welcoming and inclusive language 89 | - Being respectful of differing viewpoints and experiences 90 | - Gracefully accepting constructive criticism 91 | - Focusing on what is best for the community 92 | - Showing empathy towards other community members 93 | 94 | Examples of unacceptable behavior include: 95 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 96 | - Trolling, insulting/derogatory comments, and personal or political attacks 97 | - Public or private harassment 98 | - Publishing others’ private information, such as a physical or electronic address, without explicit permission 99 | - Other conduct which could reasonably be considered inappropriate in a professional setting 100 | 101 | 102 | 103 | ## Contributor License & Acknowledgments 104 | 105 | Whenever you make a contribution to this project, you license your contribution under the same terms as set out in LICENSE, and you represent and warrant that you have the right to license your contribution under those terms. Whenever you make a contribution to this project, you also certify in the terms of the Developer’s Certificate of Origin set out below: 106 | 107 | ``` 108 | Developer Certificate of Origin 109 | Version 1.1 110 | 111 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 112 | 1 Letterman Drive 113 | Suite D4700 114 | San Francisco, CA, 94129 115 | 116 | Everyone is permitted to copy and distribute verbatim copies of this 117 | license document, but changing it is not allowed. 118 | 119 | 120 | Developer's Certificate of Origin 1.1 121 | 122 | By making a contribution to this project, I certify that: 123 | 124 | (a) The contribution was created in whole or in part by me and I 125 | have the right to submit it under the open source license 126 | indicated in the file; or 127 | 128 | (b) The contribution is based upon previous work that, to the best 129 | of my knowledge, is covered under an appropriate open source 130 | license and I have the right under that license to submit that 131 | work with modifications, whether created in whole or in part 132 | by me, under the same open source license (unless I am 133 | permitted to submit under a different license), as indicated 134 | in the file; or 135 | 136 | (c) The contribution was provided directly to me by some other 137 | person who certified (a), (b) or (c) and I have not modified 138 | it. 139 | 140 | (d) I understand and agree that this project and the contribution 141 | are public and that a record of the contribution (including all 142 | personal information I submit with it, including my sign-off) is 143 | maintained indefinitely and may be redistributed consistent with 144 | this project or the open source license(s) involved. 145 | ``` 146 | 147 | ## References 148 | 149 | * Overall CONTRIB adapted from https://github.com/mathjax/MathJax/blob/master/CONTRIBUTING.md 150 | * Conduct section adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 151 | -------------------------------------------------------------------------------- /src/specVersions/v0.0/testfixtures/jscore-fixtures.ts: -------------------------------------------------------------------------------- 1 | // Extra smoke test file using some common shared data 2 | 3 | // tslint:disable:max-line-length 4 | 5 | const simpleRicardian = `--- 6 | title: Token Transfer 7 | summary: Transfer tokens from {{from}} to {{to}}. 8 | icon: http://simpleicon.com/wp-content/uploads/like.png#d0da4e5d44e4f2d325109010203fda422d3f7cd4934d874cb4ea98a62bf16cec 9 | --- 10 | 11 | ## Transfer Terms & Conditions 12 | 13 | I, {{from}}, certify the following to be true to the best of my knowledge: 14 | 15 | 1. I certify that {{quantity}} is not the proceeds of fraudulent or violent activities. 16 | 2. I certify that, to the best of my knowledge, {{to}} is not supporting initiation of violence against others. 17 | 3. I have disclosed any contractual terms & conditions with respect to {{quantity}} to {{to}}. 18 | 19 | I understand that funds transfers are not reversible after the {{$transaction.delay_sec}} seconds or other delay as configured by {{from}}'s permissions. 20 | 21 | If this action fails to be irreversibly confirmed after receiving goods or services from '{{to}}', I agree to either return the goods or services or resend {{quantity}} in a timely manner. 22 | ` 23 | 24 | const complexRicardian = `--- 25 | title: Multi Token Transfer 26 | summary: Transfer multiple different tokens from {{from}} to {{to}}. 27 | icon: https://www.wlu.edu/images/advancement/icons/stock-transfer.png#e4289f04df9c6cf89e1bfecf1dbaa4357a9e7099c25aa2d158d6894065e4773a 28 | --- 29 | 30 | # Super Multi Transfer with whole ABI Meta Data 31 | 32 |

This contract action is NOT a real one, and not related to \`eosio.token\` at all.
33 | Just an example of testing all the contract parsings with handlebars.

34 | 35 | ## Transfer Terms & Conditions 36 | 37 | I, {{from}}, certify the following to be true to the best of my knowledge: 38 | 39 | 1. I certify that the total amount of this transfer does not the proceeds of fraudulent or violent activities. 40 | 2. I certify that, to the best of my knowledge, {{to}} is not supporting initiation of violence against others. 41 | 3. I have disclosed any contractual terms & conditions with respect to {{to}}. 42 | 43 | ` 44 | 45 | export default { 46 | chainId: process.env.REACT_APP_CHAIN_ID, 47 | 48 | pubKeys: ['5JmqocoeJ1ury2SdjVNVgNL1n4qR2sse5cxN4upvspU2R5PEnxP'], 49 | 50 | transaction: { 51 | expiration: '2018-08-14T20:38:58', 52 | ref_block_num: 63462, 53 | ref_block_prefix: 4279361130, 54 | max_net_usage_words: 0, 55 | max_cpu_usage_ms: 0, 56 | delay_sec: 0, 57 | context_free_actions: [], 58 | actions: [ 59 | { 60 | account: 'eosio.token', 61 | name: 'multitransf', 62 | authorization: [ 63 | { 64 | actor: 'alicejones', 65 | permission: 'active', 66 | }, 67 | ], 68 | data: { 69 | from: 'alicejones', 70 | to: 'bobsmith', 71 | quantities: ['123.0000 EOS', '456.0000 ABC', '789.0000 DEF'], 72 | memos: ['Super EOS', 'I know you like ABC tokens'], 73 | }, 74 | }, 75 | { 76 | account: 'eosio.token', 77 | name: 'transfer', 78 | authorization: [ 79 | { 80 | actor: 'bobsmith', 81 | permission: 'active', 82 | }, 83 | ], 84 | data: { 85 | from: 'bobsmith', 86 | to: 'alicejones', 87 | quantity: '123.0000 EOS', 88 | memo: 'Testing.', 89 | }, 90 | }, 91 | ], 92 | transaction_extensions: [], 93 | }, 94 | 95 | abis: [ 96 | { 97 | account_name: 'eosio.token', 98 | abi: { 99 | types: [ 100 | { 101 | type: 'name', 102 | new_type_name: 'account_name', 103 | }, 104 | ], 105 | tables: [ 106 | { 107 | name: 'accounts', 108 | type: 'account', 109 | key_names: [ 110 | 'currency', 111 | ], 112 | key_types: [ 113 | 'uint64', 114 | ], 115 | index_type: 'i64', 116 | }, 117 | { 118 | name: 'stat', 119 | type: 'currency_stats', 120 | key_names: [ 121 | 'currency', 122 | ], 123 | key_types: [ 124 | 'uint64', 125 | ], 126 | index_type: 'i64', 127 | }, 128 | ], 129 | actions: [ 130 | { 131 | name: 'transfer', 132 | type: 'transfer', 133 | ricardian_contract: simpleRicardian, 134 | }, 135 | { 136 | name: 'multitransf', 137 | type: 'multitransf', 138 | ricardian_contract: complexRicardian, 139 | }, 140 | { 141 | name: 'issue', 142 | type: 'issue', 143 | ricardian_contract: '', 144 | }, 145 | { 146 | name: 'create', 147 | type: 'create', 148 | ricardian_contract: '', 149 | }, 150 | ], 151 | structs: [ 152 | { 153 | base: '', 154 | name: 'transfer', 155 | fields: [ 156 | { 157 | name: 'from', 158 | type: 'account_name', 159 | }, 160 | { 161 | name: 'to', 162 | type: 'account_name', 163 | }, 164 | { 165 | name: 'quantity', 166 | type: 'asset', 167 | }, 168 | { 169 | name: 'memo', 170 | type: 'string', 171 | }, 172 | ], 173 | }, 174 | { 175 | base: '', 176 | name: 'multitransf', 177 | fields: [ 178 | { 179 | name: 'from', 180 | type: 'account_name', 181 | }, 182 | { 183 | name: 'to', 184 | type: 'account_name', 185 | }, 186 | { 187 | name: 'quantities', 188 | type: 'asset[]', 189 | }, 190 | { 191 | name: 'memos', 192 | type: 'string[]', 193 | }, 194 | ], 195 | }, 196 | { 197 | base: '', 198 | name: 'create', 199 | fields: [ 200 | { 201 | name: 'issuer', 202 | type: 'account_name', 203 | }, 204 | { 205 | name: 'maximum_supply', 206 | type: 'asset', 207 | }, 208 | ], 209 | }, 210 | { 211 | base: '', 212 | name: 'issue', 213 | fields: [ 214 | { 215 | name: 'to', 216 | type: 'account_name', 217 | }, 218 | { 219 | name: 'quantity', 220 | type: 'asset', 221 | }, 222 | { 223 | name: 'memo', 224 | type: 'string', 225 | }, 226 | ], 227 | }, 228 | { 229 | base: '', 230 | name: 'account', 231 | fields: [ 232 | { 233 | name: 'balance', 234 | type: 'asset', 235 | }, 236 | ], 237 | }, 238 | { 239 | base: '', 240 | name: 'currency_stats', 241 | fields: [ 242 | { 243 | name: 'supply', 244 | type: 'asset', 245 | }, 246 | { 247 | name: 'max_supply', 248 | type: 'asset', 249 | }, 250 | { 251 | name: 'issuer', 252 | type: 'account_name', 253 | }, 254 | ], 255 | }, 256 | ], 257 | version: 'eosio::abi/1.0', 258 | abi_extensions: [], 259 | error_messages: [], 260 | ricardian_clauses: [ 261 | { 262 | id: 'boilerplate', 263 | body: 'I, {{from}}, swear by the moon and the stars in the sky\nI\'ll be there\nI swear like a shadow that\'s by your side\nI\'ll be there\n\nFor better or worse, till death do us part\nI\'ll love you with every beat of my heart\nAnd I swear', 264 | }, 265 | { 266 | id: 'ricardian_contract_images', 267 | body: '![EOS ricardian_contract_images](https://files.readme.io/aeb2530-small-logo_2x.png#HA8HG03SH3R3)', 268 | }, 269 | { 270 | id: 'ricardian_clause_interpolations', 271 | body: 'You are sending this transfer from the account: {{from}}', 272 | }, 273 | ], 274 | }, 275 | }, 276 | ], 277 | } 278 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | 2 | EOSIO.CDT Ricardian Template Toolkit ![EOSIO Alpha](https://img.shields.io/badge/EOSIO-Alpha-blue.svg) 3 | ====================================================================================================== 4 | 5 | This library is a new tool in the suite of tools from [EOSIO.CDT (Contract Development Toolkit)](https://github.com/EOSIO/eosio.cdt/tree/develop), and should allow for a more robust and rich environment for writing **Ricardian** contracts for your **EOSIO** smart contracts. 6 | 7 | Overview 8 | -------- 9 | 10 | The Ricardian Template Toolkit is an implementation of a renderer for the [Ricardian Contract Specification](https://github.com/EOSIO/ricardian-spec) that demonstrates how Ricardian Contracts built to the specification can be displayed. This toolkit can be used by Authenticator developers to consistently render Ricardian Contracts and by Smart Contract developers as an authoring and testing tool. 11 | 12 | Together, the Ricardian Template Toolkit and Ricardian Contract Specification projects enable a clear understanding of the agreements to which users are consenting in Authenticators which ask them to sign transactions. 13 | 14 | This library contains a factory that takes an ABI object, a transaction object, and an action index (along with some developer-oriented flags). It then: 15 | 16 | 1. Selects an appropriate processor based on the `spec_version` field in the contract metadata 17 | 2. Validates the Ricardian Contracts and metadata associated with the transaction actions 18 | 3. Validates all other spec requirements, including image sizes and hashes 19 | 4. Interpolates all variables with data from the transaction or ricardian\_clauses 20 | 5. On success, returns an object with metadata and Contract Markup Language (CML, a subset of HTML) 21 | 6. On error or validation failure, returns a descriptive error, along with any data it was able to successfully parse and render 22 | 23 | Foundational Inspiration for Metadata: 24 | 25 | * [https://hiltmon.com/blog/2012/06/18/markdown-metadata/](https://hiltmon.com/blog/2012/06/18/markdown-metadata/) 26 | * [https://blog.github.com/2013-09-27-viewing-yaml-metadata-in-your-documents/](https://blog.github.com/2013-09-27-viewing-yaml-metadata-in-your-documents/) 27 | * [https://stackoverflow.com/questions/44215896/markdown-metadata-format#answer-44222826](https://stackoverflow.com/questions/44215896/markdown-metadata-format#answer-44222826) 28 | 29 | Installation 30 | ------------ 31 | 32 | `yarn add ricardian-template-toolkit` 33 | 34 | Running Locally 35 | --------------- 36 | 37 | ``` 38 | yarn install 39 | yarn build 40 | yarn example 41 | ``` 42 | 43 | Other Commands 44 | -------------- 45 | 46 | * `yarn lint` 47 | * `yarn test` 48 | 49 | Ricardian Specification 50 | ----------------------- 51 | 52 | The Ricardian Specification and an example of a compliant Ricardian contract can now be found at [https://github.com/EOSIO/ricardian-spec](https://github.com/EOSIO/ricardian-spec). 53 | 54 | Usage 55 | ----- 56 | 57 | Usage is very straightforward: 58 | 59 | ```javascript 60 | import { RicardianContractFactory} from 'ricardian-template-toolkit' 61 | 62 | ... 63 | 64 | // Create the factory instance. 65 | const factory = new RicardianContractFactory() 66 | 67 | // Construct a RicardianContractConfig object 68 | const config = { 69 | abi: myAbi, 70 | transaction: myTransaction, 71 | actionIndex: 0, 72 | // Optional - defaults to 3 73 | maxPasses: 3, 74 | // Optional - developer flag - if true ignore errors if a variable 75 | // is specified in the contract but no value is found to substitute 76 | allowUnusedVariables: false 77 | } 78 | 79 | const ricardianContract = factory.create(config) 80 | 81 | const metadata = ricardianContract.getMetadata() 82 | const html = ricardianContract.getHtml() 83 | ``` 84 | 85 | Backward Compatibility Note 86 | --------------------------- 87 | 88 | Be aware that for backward compatibility with contract specifications prior to `0.1.0`, any contracts lacking a `spec_version` in the metadata are treated as following spec version `0.0.0`. 89 | 90 | Example 91 | ------- 92 | 93 | The following is based on the [example from the Ricardian Contract Specification](https://github.com/EOSIO/ricardian-spec#example-template) 94 | 95 | Raw HTML Output 96 | 97 | ``` 98 | I,
bobsmith
, author of the blog post "
An Example Post
", certify that I am the original author of the contents of this blog post and have attributed all external sources appropriately.
99 |
WARRANTY. The invoker of the contract action shall uphold its Obligations under this Contract in a timely and workmanlike manner, using knowledge and recommendations for performing the services which meet generally acceptable standards set forth by EOS.IO Blockchain Block Producers.

100 | ``` 101 | 102 | Styled HTML 103 | 104 | ``` 105 | 106 | 107 | 121 | 122 | 123 | 124 | I,
bobsmith
, author of the blog post "
An Example Post
", certify that I am the original author of the contents of this blog post and have attributed all external sources appropriately.
125 |
WARRANTY. The invoker of the contract action shall uphold its Obligations under this Contract in a timely and workmanlike manner, using knowledge and recommendations for performing the services which meet generally acceptable standards set forth by EOS.IO Blockchain Block Producers.

126 | 127 | 128 | ``` 129 | 130 | Rendered Styled HTML ![Styled HTML Example](.images/styled-example.png) 131 | 132 | Contributing 133 | ------------ 134 | 135 | [Contributing Guide](./CONTRIBUTING.md) 136 | 137 | [Code of Conduct](./CONTRIBUTING.md#conduct) 138 | 139 | License 140 | ------- 141 | 142 | [MIT](./LICENSE) 143 | 144 | Important 145 | --------- 146 | 147 | See LICENSE for copyright and license terms. Block.one makes its contribution on a voluntary basis as a member of the EOSIO community and is not responsible for ensuring the overall performance of the software or any related applications. We make no representation, warranty, guarantee or undertaking in respect of the software or any related documentation, whether expressed or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall we be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or documentation or the use or other dealings in the software or documentation. Any test results or performance figures are indicative and will not reflect performance under all conditions. Any reference to any third party or third-party product, service or other resource is not an endorsement or recommendation by Block.one. We are not responsible, and disclaim any and all responsibility and liability, for your use of or reliance on any of these resources. Third-party resources may be updated, changed or terminated at any time, so the information here may be out of date or inaccurate. Any person using or offering this software in connection with providing software, goods or services to third parties shall advise such third parties of these license terms, disclaimers and exclusions of liability. Block.one, EOSIO, EOSIO Labs, EOS, the heptahedron and associated logos are trademarks of Block.one. 148 | 149 | Wallets and related components are complex software that require the highest levels of security. If incorrectly built or used, they may compromise users’ private keys and digital assets. Wallet applications and related components should undergo thorough security evaluations before being used. Only experienced developers should work with this software. 150 | 151 | ## Index 152 | 153 | ### External modules 154 | 155 | * ["RicardianContractFactory"](modules/_ricardiancontractfactory_.md) 156 | * ["RicardianContractRenderError"](modules/_ricardiancontractrendererror_.md) 157 | * ["bin/rc"](modules/_bin_rc_.md) 158 | * ["config"](modules/_config_.md) 159 | * ["factoryHelpers"](modules/_factoryhelpers_.md) 160 | * ["interfaces"](modules/_interfaces_.md) 161 | * ["specVersions/v0.0/RicardianContext"](modules/_specversions_v0_0_ricardiancontext_.md) 162 | * ["specVersions/v0.0/RicardianContractProcessorImpl"](modules/_specversions_v0_0_ricardiancontractprocessorimpl_.md) 163 | * ["specVersions/v0.0/VariableWrapper"](modules/_specversions_v0_0_variablewrapper_.md) 164 | * ["specVersions/v0.0/WrapVariable"](modules/_specversions_v0_0_wrapvariable_.md) 165 | * ["specVersions/v0.0/helpers"](modules/_specversions_v0_0_helpers_.md) 166 | * ["specVersions/v0.0/validators"](modules/_specversions_v0_0_validators_.md) 167 | * ["specVersions/v0.0/whitelist"](modules/_specversions_v0_0_whitelist_.md) 168 | * ["specVersions/v0.1/RicardianContractProcessorImpl"](modules/_specversions_v0_1_ricardiancontractprocessorimpl_.md) 169 | * ["specVersions/v0.1/helpers"](modules/_specversions_v0_1_helpers_.md) 170 | * ["specVersions/v0.2/RicardianContractProcessorImpl"](modules/_specversions_v0_2_ricardiancontractprocessorimpl_.md) 171 | * ["specVersions/v0.2/helpers"](modules/_specversions_v0_2_helpers_.md) 172 | * ["utils/contractUtils"](modules/_utils_contractutils_.md) 173 | 174 | --- 175 | 176 | -------------------------------------------------------------------------------- /src/specVersions/v0.0/RicardianContractProcessorImpl.ts: -------------------------------------------------------------------------------- 1 | import * as Handlebars from 'handlebars' 2 | import he from 'he' 3 | import Remarkable from 'remarkable' 4 | import { MAX_PASSES } from '../../config' 5 | import { 6 | Abi, ContractMetadata, 7 | RicardianClause, RicardianContract, RicardianContractConfig, RicardianContractProcessor, 8 | Transaction, TransactionAction, 9 | } from '../../interfaces' 10 | import { RicardianContractRenderError } from '../../RicardianContractRenderError' 11 | import { 12 | extractSymbolCode, hasVariable, indexTransaction, 13 | sanitizeHtml, tagMetadataVariables, tagTemplateVariables, 14 | } from './helpers' 15 | import { RicardianContext } from './RicardianContext' 16 | import { validateIcon, validateSummary, validateTitle } from './validators' 17 | 18 | import * as utils from '../../utils/contractUtils' 19 | import { getContractSpecVersion } from '../../utils/contractUtils' 20 | 21 | const implVersion = { 22 | major: 0, 23 | minor: 0, 24 | } 25 | 26 | /** 27 | * Processes a Ricardian contract, interpolating transaction variables and clauses, and 28 | * extracting metadata and html. 29 | */ 30 | export class RicardianContractProcessorImpl implements RicardianContractProcessor { 31 | // private transaction: any 32 | private allowUnusedVariables = false 33 | private disableMetadataValidation = false 34 | 35 | private wrappedHelpers: string[] = ['lookup'] 36 | 37 | /** 38 | * Constructs the RicardianContractProcessorImpl. 39 | */ 40 | constructor() { 41 | Handlebars.registerHelper('wrap', function(options: any): string { 42 | return `
` 43 | // @ts-ignore 44 | + options.fn(this) 45 | + '
' 46 | }) 47 | 48 | this.registerWrappedHelper('symbol_to_symbol_code', (symbol: string) => { 49 | return new Handlebars.SafeString(extractSymbolCode(symbol)) 50 | }) 51 | 52 | this.registerWrappedHelper('asset_to_symbol_code', (asset: string) => { 53 | return new Handlebars.SafeString(extractSymbolCode(asset)) 54 | }) 55 | 56 | Handlebars.registerHelper('nowrap', (text: string) => { 57 | return new Handlebars.SafeString(text) 58 | }) 59 | } 60 | 61 | // Register a helper whose output should be wrapped as a variable 62 | protected registerWrappedHelper(name: string, fn: Handlebars.HelperDelegate) { 63 | Handlebars.registerHelper(name, fn) 64 | this.wrappedHelpers.push(name) 65 | } 66 | 67 | protected registerHelper(name: string, fn: Handlebars.HelperDelegate) { 68 | Handlebars.registerHelper(name, fn) 69 | } 70 | 71 | public getSpecVersion() { 72 | return implVersion 73 | } 74 | 75 | /** 76 | * Process the RicardianContractConfig and return a RicardianContract. 77 | * 78 | * @param config A `RicardianContractConfig` object 79 | */ 80 | public process(config: RicardianContractConfig): RicardianContract { 81 | const version = getContractSpecVersion(config) 82 | const specVersion = this.getSpecVersion() 83 | 84 | if (version.major === specVersion.major && version.minor <= specVersion.minor) { 85 | return this.processContract(config) 86 | } else { 87 | throw new RicardianContractRenderError(`Unexpected version encountered. ` + 88 | `Found ${version}`) 89 | } 90 | } 91 | 92 | protected processContract(config: RicardianContractConfig): RicardianContract { 93 | this.allowUnusedVariables = !!config.allowUnusedVariables 94 | this.disableMetadataValidation = !!config.allowUnusedVariables 95 | 96 | const maxPasses = config.maxPasses || MAX_PASSES 97 | 98 | const action = utils.getTransactionAction(config.transaction, config.actionIndex) 99 | const rawTemplate = utils.getContractTextFromAbi(config.abi, action) 100 | const context = this.createContext(config.abi, config.transaction, action) 101 | const { metadata, interpolatedRicardian } = this.interpolateContract(rawTemplate, context, maxPasses) 102 | if (!metadata.spec_version) { 103 | metadata.spec_version = '0.0.0' 104 | } 105 | const html = this.convertToHtml(interpolatedRicardian) 106 | 107 | return { 108 | getMetadata: () => metadata, 109 | getHtml: () => html 110 | } 111 | } 112 | 113 | /** 114 | * Parses a transaction and returns an object with formatted transaction data 115 | * 116 | * @return An RicardianContext with formatted transaction data 117 | */ 118 | private createContext(abi: Abi, transaction: Transaction, action: TransactionAction): RicardianContext { 119 | const indexedTransaction: any = indexTransaction(transaction) 120 | const ricardianClauses = abi.ricardian_clauses 121 | return { 122 | ...action.data, 123 | $transaction: indexedTransaction, 124 | $action: action, 125 | $clauses: ricardianClauses.reduce( 126 | (clauses: any, current: RicardianClause): any => ({ 127 | ...clauses, 128 | [current.id]: current.body, 129 | } 130 | ), {}, 131 | ), 132 | } as RicardianContext 133 | } 134 | 135 | /** 136 | * Interpolate variables referenced in the contract metadata and body. 137 | * 138 | * @param context The RicardianContext contain the source data for interpolation 139 | * @param maxPasses The number of variable interpolation passes to make. Defaults to config.MAX_PASSES 140 | * 141 | * @return An object with parsed ContractMetadata and interpolated body 142 | */ 143 | private interpolateContract(rawTemplate: string, context: RicardianContext, maxPasses: number): 144 | { metadata: ContractMetadata, interpolatedRicardian: string } { 145 | const { metadata: rawMetadata, content: rawContent } = utils.getMetadataAndContent(rawTemplate) 146 | return { 147 | metadata: this.interpolateMetadata(rawMetadata, context, maxPasses), 148 | interpolatedRicardian: this.interpolateRicardian(rawContent, context, maxPasses), 149 | } 150 | } 151 | 152 | /** 153 | * Interpolate the variables referenced in contractContent, making the specified number 154 | * of passes. 155 | * @param contractContent String containing the contract body 156 | * @param context The RicardianContext contain the source data for interpolation 157 | * @param maxPasses Maximum number of interpolation passes to make 158 | * 159 | * @return String containing the interpolated content 160 | */ 161 | private interpolateRicardian(contractContent: string, context: RicardianContext, maxPasses: number): string { 162 | let interpolatedRicardian: string = contractContent 163 | let passes: number = 0 164 | const allowUnusedVariables = this.allowUnusedVariables 165 | do { 166 | try { 167 | interpolatedRicardian = tagTemplateVariables(this.wrappedHelpers, interpolatedRicardian) 168 | const handlebarsTemplate: Handlebars.Template = Handlebars.compile( 169 | interpolatedRicardian, 170 | { strict: !allowUnusedVariables }, 171 | ) 172 | interpolatedRicardian = handlebarsTemplate(context) 173 | } catch (e) { 174 | throw new RicardianContractRenderError(`Handlebars error: ${e.message}`) 175 | } 176 | 177 | passes++ 178 | } while (passes < maxPasses && hasVariable(interpolatedRicardian)) 179 | 180 | if (!this.allowUnusedVariables && passes === maxPasses && hasVariable(interpolatedRicardian)) { 181 | throw new RicardianContractRenderError( 182 | 'Contract has uninterpolated variables after maximum number of variable interpolation passes.') 183 | } 184 | 185 | return interpolatedRicardian 186 | } 187 | 188 | /** 189 | * Interpolate the variables referenced in the given ContractMetadata, performing maxPasses 190 | * of intererpolation. 191 | * Note that the "title" and "icon" metadata fields are NOT subject to interpolation and are 192 | * returned as-is. 193 | * 194 | * @param metadata The ContractMetadata to interpolate 195 | * @param context The RicardianContext contain the source data for interpolation 196 | * @param maxPasses Maximum number of interpolation passes to make 197 | * 198 | * @return A new ContractMetadata containing the interpolated fields 199 | */ 200 | private interpolateMetadata(metadata: ContractMetadata, context: RicardianContext, 201 | maxPasses: number): ContractMetadata { 202 | const { title, icon, ...metadataTemplate } = metadata 203 | let interpolatedMetadata: { [index: string]: string } = metadataTemplate 204 | let passes: number = 0 205 | const allowUnusedVariables = this.allowUnusedVariables 206 | let hasUninterpolatedVars = false 207 | 208 | if (!this.disableMetadataValidation) { 209 | validateTitle(title) 210 | validateIcon(icon) 211 | } 212 | 213 | do { 214 | try { 215 | hasUninterpolatedVars = false 216 | interpolatedMetadata = tagMetadataVariables(this.wrappedHelpers, interpolatedMetadata) 217 | 218 | Object.keys(interpolatedMetadata) 219 | .forEach((key) => { 220 | const value = interpolatedMetadata[key] 221 | if (!!value) { 222 | const hbMetaTplt: Handlebars.Template = Handlebars.compile(value, { strict: !allowUnusedVariables }) 223 | interpolatedMetadata[key] = hbMetaTplt(context) 224 | hasUninterpolatedVars = hasUninterpolatedVars || hasVariable(interpolatedMetadata[key]) 225 | } 226 | }) 227 | } catch (e) { 228 | throw new RicardianContractRenderError(`Handlebars error: ${e.message}`) 229 | } 230 | 231 | passes++ 232 | } while (passes < maxPasses && hasUninterpolatedVars) 233 | 234 | if (!this.allowUnusedVariables && passes === maxPasses && hasUninterpolatedVars) { 235 | throw new RicardianContractRenderError( 236 | 'Contract has uninterpolated metadata variables after maximum number of variable interpolation passes.') 237 | } 238 | 239 | // Summary may have variables, so validating post-interpolation 240 | if (!this.disableMetadataValidation) { 241 | validateSummary(interpolatedMetadata.summary) 242 | } 243 | 244 | return { title, icon, ...interpolatedMetadata } as ContractMetadata 245 | } 246 | 247 | /** 248 | * Given a Github flavored markdown formatted string, generate HTML. 249 | * Also replaces [variable] tags with
s. 250 | * 251 | * @param content Markdown formatted string 252 | * 253 | * @return The generated HTML 254 | */ 255 | private convertToHtml(content: string): string { 256 | const md = new Remarkable('commonmark', { 257 | breaks: true, 258 | html: false, 259 | }) 260 | 261 | let html = md.render(content) 262 | 263 | // Remove the somewhat funky

tags Remarkable adds since they 264 | // can break the

wrappings if the wrapped var contained newlines. 265 | html = html.replace(/

/g, '') 266 | html = html.replace(/<\/p>/g, '
') 267 | 268 | html = he.decode(html) 269 | 270 | html = sanitizeHtml(html) 271 | 272 | return html 273 | } 274 | } 275 | 276 | export default RicardianContract 277 | --------------------------------------------------------------------------------