Compare commits

...

19 Commits

Author SHA1 Message Date
mariopil
d2033c8035 Hooks docs update (#279)
* Added hooks-guard-call-non-const checker doc, updated hooks-guard-in-for doc.
2023-01-09 13:43:32 +01:00
muzamil
48daf1c5c8 Merge pull request #278 from XRPLF/feat/compile-wat
Increase wat file priority in sorting.
2022-12-07 15:03:40 +05:30
muzam1l
a3365e4beb Increase wat file priority in sorting. 2022-12-07 15:02:09 +05:30
muzamil
45d813cdad Merge pull request #277 from XRPLF/feat/compile-wat
Compile raw wat files.
2022-12-07 14:46:05 +05:30
muzam1l
911416aa2f Compile wat files. 2022-12-07 13:31:59 +05:30
muzamil
2d836af9ed Merge pull request #276 from XRPLF/feat/flags-ui
Transaction flags UI.
2022-11-01 17:14:44 +05:30
muzam1l
4f0fc838be Minor css fix. 2022-11-01 11:20:09 +05:30
muzam1l
fa93912c38 Remove reductant comment. 2022-10-28 14:58:11 +05:30
muzam1l
f5cb76c302 Merge branch 'main' into feat/flags-ui 2022-10-28 14:48:41 +05:30
muzamil
df1d65dcab Merge pull request #275 from XRPLF/dependabot/npm_and_yarn/jose-4.10.0
Bump jose from 4.6.0 to 4.10.0
2022-10-28 14:48:02 +05:30
muzam1l
1513f78991 Add tx specific flags. 2022-10-28 14:43:37 +05:30
muzam1l
3a064f307b Add global flags. 2022-10-28 14:21:22 +05:30
muzam1l
6fca05f310 Add flags UI to Payment transaction. 2022-10-28 12:29:57 +05:30
muzamil
31e67d382f Merge pull request #273 from XRPLF/fix/renaming-ext
Update file language on renaming.
2022-10-26 18:10:43 +05:30
dependabot[bot]
27475301e4 Bump jose from 4.6.0 to 4.10.0
Bumps [jose](https://github.com/panva/jose) from 4.6.0 to 4.10.0.
- [Release notes](https://github.com/panva/jose/releases)
- [Changelog](https://github.com/panva/jose/blob/main/CHANGELOG.md)
- [Commits](https://github.com/panva/jose/compare/v4.6.0...v4.10.0)

---
updated-dependencies:
- dependency-name: jose
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-14 08:29:14 +00:00
muzam1l
934283976a Add plain text language to monaco. 2022-09-09 14:07:13 +05:30
muzamil
2d9ca2674e Merge pull request #266 from XRPLF/feat/engine-code-links
Linkify engine error codes and some refactor.
2022-08-19 20:00:22 +05:30
muzam1l
0d9e9e7b45 Merge branch 'main' into fix/renaming-ext 2022-08-19 15:14:52 +05:30
muzam1l
2c2bf59bcd Update file language on renaming. 2022-08-17 12:46:17 +05:30
17 changed files with 316 additions and 92 deletions

View File

@@ -200,15 +200,15 @@ const HooksEditor = () => {
defaultValue={file?.content}
// onChange={val => (state.files[snap.active].content = val)} // Auto save?
beforeMount={monaco => {
if (!snap.editorCtx) {
snap.files.forEach(file =>
monaco.editor.createModel(
file.content,
file.language,
monaco.Uri.parse(`file:///work/c/${file.name}`)
)
)
}
// if (!snap.editorCtx) {
// snap.files.forEach(file =>
// monaco.editor.createModel(
// file.content,
// file.language,
// monaco.Uri.parse(`file:///work/c/${file.name}`)
// )
// )
// }
// create the web socket
if (!subscriptionRef.current) {
@@ -218,6 +218,11 @@ const HooksEditor = () => {
aliases: ['C', 'c', 'H', 'h'],
mimetypes: ['text/plain']
})
monaco.languages.register({
id: 'text',
extensions: ['.txt'],
mimetypes: ['text/plain'],
})
MonacoServices.install(monaco)
const webSocket = createWebSocket(
process.env.NEXT_PUBLIC_LANGUAGE_SERVER_API_ENDPOINT || ''

View File

@@ -11,7 +11,7 @@ import {
} from './Dialog'
import { Plus, X } from 'phosphor-react'
import { styled } from '../stitches.config'
import { capitalize } from '../utils/helpers'
import { capitalize, getFileExtention } from '../utils/helpers'
import ContextMenu, { ContentMenuOption } from './ContextMenu'
const ErrorText = styled(Text, {
@@ -97,7 +97,7 @@ export const Tabs = ({
if (!tabname) {
return { error: `Please enter ${label.toLocaleLowerCase()} name.` }
}
let ext = (tabname.includes('.') && tabname.split('.').pop()) || ''
let ext = getFileExtention(tabname)
if (!ext && defaultExtension) {
ext = defaultExtension
@@ -109,7 +109,7 @@ export const Tabs = ({
if (extensionRequired && !ext) {
return { error: 'File extension is required!' }
}
if (allowedExtensions && !allowedExtensions.includes(ext)) {
if (allowedExtensions && ext && !allowedExtensions.includes(ext)) {
return { error: 'This file extension is not allowed!' }
}
if (headerExtraValidation && !tabname.match(headerExtraValidation.regex)) {

View File

@@ -19,6 +19,7 @@ import { TxJson } from './json'
import { TxUI } from './ui'
import { default as _estimateFee } from '../../utils/estimateFee'
import toast from 'react-hot-toast'
import { combineFlags, extractFlags, transactionFlags } from '../../state/constants/flags'
export interface TransactionProps {
header: string
@@ -39,14 +40,17 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
const prepareOptions = useCallback(
(state: Partial<TransactionState> = txState) => {
const { selectedTransaction, selectedDestAccount, selectedAccount, txFields } = state
const { selectedTransaction, selectedDestAccount, selectedAccount, txFields, selectedFlags } =
state
const TransactionType = selectedTransaction?.value || null
const Destination = selectedDestAccount?.value || txFields?.Destination
const Account = selectedAccount?.value || null
const Flags = combineFlags(selectedFlags?.map(flag => flag.value)) || txFields?.Flags
return prepareTransaction({
...txFields,
Flags,
TransactionType,
Destination,
Account
@@ -136,8 +140,13 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
} else {
fields.Destination = undefined
}
nwState.txFields = fields
if (transactionType?.value && transactionFlags[transactionType?.value] && fields.Flags) {
nwState.selectedFlags = extractFlags(transactionType.value, fields.Flags)
fields.Flags = undefined
}
nwState.txFields = fields
const state = modifyTxState(header, nwState, { replaceState: true })
const editorValue = getJsonString(state)
return setState({ editorValue })
@@ -179,7 +188,12 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
estimateFee={estimateFee}
/>
) : (
<TxUI state={txState} setState={setState} estimateFee={estimateFee} />
<TxUI
state={txState}
resetState={resetState}
setState={setState}
estimateFee={estimateFee}
/>
)}
<Flex
row

View File

@@ -17,16 +17,19 @@ import state from '../../state'
import { streamState } from '../DebugStream'
import { Button } from '..'
import Textarea from '../Textarea'
import { getFlags } from '../../state/constants/flags'
interface UIProps {
setState: (pTx?: Partial<TransactionState> | undefined) => TransactionState | undefined
resetState: (tt?: SelectOption) => TransactionState | undefined
state: TransactionState
estimateFee?: (...arg: any) => Promise<string | undefined>
}
export const TxUI: FC<UIProps> = ({ state: txState, setState, estimateFee }) => {
export const TxUI: FC<UIProps> = ({ state: txState, setState, resetState, estimateFee }) => {
const { accounts } = useSnapshot(state)
const { selectedAccount, selectedDestAccount, selectedTransaction, txFields } = txState
const { selectedAccount, selectedDestAccount, selectedTransaction, txFields, selectedFlags } =
txState
const accountOptions: SelectOption[] = accounts.map(acc => ({
label: acc.name,
@@ -40,23 +43,15 @@ export const TxUI: FC<UIProps> = ({ state: txState, setState, estimateFee }) =>
}))
.filter(acc => acc.value !== selectedAccount?.value)
const flagsOptions: SelectOption[] = Object.entries(
getFlags(selectedTransaction?.value) || {}
).map(([label, value]) => ({
label,
value
}))
const [feeLoading, setFeeLoading] = useState(false)
const resetFields = useCallback(
(tt: string) => {
const fields = getTxFields(tt)
if (fields.Destination !== undefined) {
setState({ selectedDestAccount: null })
fields.Destination = ''
} else {
fields.Destination = undefined
}
return setState({ txFields: fields })
},
[setState]
)
const handleSetAccount = (acc: SelectOption) => {
setState({ selectedAccount: acc })
streamState.selectedAccount = acc
@@ -92,11 +87,11 @@ export const TxUI: FC<UIProps> = ({ state: txState, setState, estimateFee }) =>
(tt: SelectOption) => {
setState({ selectedTransaction: tt })
const newState = resetFields(tt.value)
const newState = resetState(tt)
handleEstimateFee(newState, true)
},
[handleEstimateFee, resetFields, setState]
[handleEstimateFee, resetState, setState]
)
const switchToJson = () => setState({ viewType: 'json' })
@@ -115,14 +110,16 @@ export const TxUI: FC<UIProps> = ({ state: txState, setState, estimateFee }) =>
[selectedTransaction?.value]
)
const specialFields = ['TransactionType', 'Account']
const richFields = ['TransactionType', 'Account']
if (fields.Destination !== undefined) {
specialFields.push('Destination')
richFields.push('Destination')
}
const otherFields = Object.keys(txFields).filter(k => !specialFields.includes(k)) as [
keyof TxFields
]
if (flagsOptions.length) {
richFields.push('Flags')
}
const otherFields = Object.keys(txFields).filter(k => !richFields.includes(k)) as [keyof TxFields]
return (
<Container
@@ -179,7 +176,32 @@ export const TxUI: FC<UIProps> = ({ state: txState, setState, estimateFee }) =>
onChange={(acc: any) => handleSetAccount(acc)} // TODO make react-select have correct types for acc
/>
</Flex>
{fields.Destination !== undefined && (
{richFields.includes('Destination') && (
<Flex
row
fluid
css={{
justifyContent: 'flex-end',
alignItems: 'center',
mb: '$3',
pr: '1px'
}}
>
<Text muted css={{ mr: '$3', textAlign: 'end' }}>
Destination account:{' '}
</Text>
<Select
instanceId="to-account"
placeholder="Select the destination account"
css={{ width: '70%' }}
options={destAccountOptions}
value={selectedDestAccount}
isClearable
onChange={(acc: any) => setState({ selectedDestAccount: acc })}
/>
</Flex>
)}
{richFields.includes('Flags') && (
<Flex
row
fluid
@@ -191,16 +213,21 @@ export const TxUI: FC<UIProps> = ({ state: txState, setState, estimateFee }) =>
}}
>
<Text muted css={{ mr: '$3' }}>
Destination account:{' '}
Flags:{' '}
</Text>
<Select
instanceId="to-account"
placeholder="Select the destination account"
css={{ width: '70%' }}
options={destAccountOptions}
value={selectedDestAccount}
isClearable
onChange={(acc: any) => setState({ selectedDestAccount: acc })}
css={{ width: '70%' }}
instanceId="flags"
placeholder="Select flags to apply"
menuPosition="fixed"
value={selectedFlags}
isMulti
options={flagsOptions}
onChange={flags => setState({ selectedFlags: flags as any })}
closeMenuOnSelect={
selectedFlags ? selectedFlags.length >= flagsOptions.length - 1 : false
}
/>
</Flex>
)}

View File

@@ -6,7 +6,7 @@
"DestinationTag": 13,
"Fee": "2000000",
"Sequence": 2470665,
"Flags": 2147483648
"Flags": "2147483648"
},
{
"TransactionType": "AccountSet",
@@ -48,7 +48,7 @@
"Account": "rsUiUMpnrgxQp24dJYZDhmV4bE3aBtQyt8",
"Authorize": "rEhxGqkqPPSxQ3P25J66ft5TwpzV14k2de",
"Fee": "10",
"Flags": 2147483648,
"Flags": "2147483648",
"Sequence": 2
},
{
@@ -109,7 +109,9 @@
"Fee": "10",
"NFTokenOffers": {
"$type": "json",
"$value": ["4AAAEEA76E3C8148473CB3840CE637676E561FB02BD4CA22CA59729EA815B862"]
"$value": [
"4AAAEEA76E3C8148473CB3840CE637676E561FB02BD4CA22CA59729EA815B862"
]
}
},
{
@@ -120,7 +122,7 @@
"$value": "100",
"$type": "xrp"
},
"Flags": 1,
"Flags": "1",
"Destination": "",
"Fee": "10"
},
@@ -128,7 +130,7 @@
"TransactionType": "OfferCancel",
"Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"Fee": "12",
"Flags": 0,
"Flags": "0",
"LastLedgerSequence": 7108629,
"OfferSequence": 6,
"Sequence": 7
@@ -137,7 +139,7 @@
"TransactionType": "OfferCreate",
"Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"Fee": "12",
"Flags": 0,
"Flags": "0",
"LastLedgerSequence": 7108682,
"Sequence": 8,
"TakerGets": "6000000",
@@ -155,7 +157,7 @@
"$type": "xrp"
},
"Fee": "12",
"Flags": 2147483648,
"Flags": "2147483648",
"Sequence": 2
},
{
@@ -185,14 +187,14 @@
"Fee": "10"
},
{
"Flags": 0,
"Flags": "0",
"TransactionType": "SetRegularKey",
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Fee": "12",
"RegularKey": "rAR8rR8sUkBoCZFawhkWzY4Y5YoyuznwD"
},
{
"Flags": 0,
"Flags": "0",
"TransactionType": "SignerListSet",
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"Fee": "12",
@@ -232,7 +234,7 @@
"TransactionType": "TrustSet",
"Account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"Fee": "12",
"Flags": 262144,
"Flags": "262144",
"LastLedgerSequence": 8007750,
"LimitAmount": {
"$type": "json",
@@ -244,4 +246,4 @@
},
"Sequence": 12
}
]
]

View File

@@ -64,7 +64,7 @@
"valtio": "^1.2.5",
"vscode-languageserver": "^7.0.0",
"vscode-uri": "^3.0.2",
"wabt": "1.0.16",
"wabt": "^1.0.30",
"xrpl-accountlib": "^1.5.2",
"xrpl-client": "^1.9.4"
},

View File

@@ -10,10 +10,11 @@ import Box from '../../components/Box'
import Button from '../../components/Button'
import Popover from '../../components/Popover'
import RunScript from '../../components/RunScript'
import state from '../../state'
import state, { IFile } from '../../state'
import { compileCode } from '../../state/actions'
import { getSplit, saveSplit } from '../../state/actions/persistSplits'
import { styled } from '../../stitches.config'
import { getFileExtention } from '../../utils/helpers'
const HooksEditor = dynamic(() => import('../../components/HooksEditor'), {
ssr: false
@@ -147,6 +148,9 @@ const CompilerSettings = () => {
const Home: NextPage = () => {
const snap = useSnapshot(state)
const activeFile = snap.files[snap.active] as IFile | undefined
const activeFileExt = getFileExtention(activeFile?.name)
const canCompile = activeFileExt === 'c' || activeFileExt === 'wat'
return (
<Split
direction="vertical"
@@ -159,7 +163,7 @@ const Home: NextPage = () => {
>
<main style={{ display: 'flex', flex: 1, position: 'relative' }}>
<HooksEditor />
{snap.files[snap.active]?.name?.split('.')?.[1]?.toLowerCase() === 'c' && (
{canCompile && (
<Hotkeys
keyName="command+b,ctrl+b"
onKeyDown={() => !snap.compiling && snap.files.length && compileCode(snap.active)}
@@ -193,7 +197,7 @@ const Home: NextPage = () => {
</Flex>
</Hotkeys>
)}
{snap.files[snap.active]?.name?.split('.')?.[1]?.toLowerCase() === 'js' && (
{activeFileExt === 'js' && (
<Hotkeys
keyName="command+b,ctrl+b"
onKeyDown={() => !snap.compiling && snap.files.length && compileCode(snap.active)}
@@ -209,7 +213,7 @@ const Home: NextPage = () => {
gap: '$2'
}}
>
<RunScript file={snap.files[snap.active]} />
<RunScript file={activeFile as IFile} />
</Flex>
</Hotkeys>
)}
@@ -225,7 +229,7 @@ const Home: NextPage = () => {
>
<LogBox title="Development Log" clearLog={() => (state.logs = [])} logs={snap.logs} />
</Flex>
{snap.files[snap.active]?.name?.split('.')?.[1]?.toLowerCase() === 'js' && (
{activeFileExt === 'js' && (
<Flex
css={{
flex: 1

View File

@@ -15,6 +15,11 @@ import { ref } from 'valtio'
export const compileCode = async (activeId: number) => {
// Save the file to global state
saveFile(false, activeId)
const file = state.files[activeId]
if (file.name.endsWith('.wat')) {
return compileWat(activeId)
}
if (!process.env.NEXT_PUBLIC_COMPILE_API_ENDPOINT) {
throw Error('Missing env!')
}
@@ -26,7 +31,6 @@ export const compileCode = async (activeId: number) => {
// Set loading state to true
state.compiling = true
state.logs = []
const file = state.files[activeId]
try {
file.containsErrors = false
let res: Response
@@ -72,7 +76,7 @@ export const compileCode = async (activeId: number) => {
// Import wabt from and create human readable version of wasm file and
// put it into state
const ww = (await import('wabt')).default()
const ww = await (await import('wabt')).default()
const myModule = ww.readWasm(new Uint8Array(bufferData), {
readDebugNames: true
})
@@ -122,3 +126,46 @@ export const compileCode = async (activeId: number) => {
file.containsErrors = true
}
}
export const compileWat = async (activeId: number) => {
if (state.compiling) return;
const file = state.files[activeId]
state.compiling = true
state.logs = []
try {
const wabt = await (await import('wabt')).default()
const module = wabt.parseWat(file.name, file.content);
module.resolveNames();
module.validate();
const { buffer } = module.toBinary({
log: false,
write_debug_names: true,
});
file.compiledContent = ref(buffer)
file.lastCompiled = new Date()
file.compiledValueSnapshot = file.content
file.compiledWatContent = file.content
toast.success('Compiled successfully!', { position: 'bottom-center' })
state.logs.push({
type: 'success',
message: `File ${state.files?.[activeId]?.name} compiled successfully. Ready to deploy.`,
link: Router.asPath.replace('develop', 'deploy'),
linkText: 'Go to deploy'
})
} catch (err) {
console.log(err)
let message = "Error compiling WAT file!"
if (err instanceof Error) {
message = err.message
}
state.logs.push({
type: 'error',
message
})
toast.error(`Error occurred while compiling!`, { position: 'bottom-center' })
file.containsErrors = true
}
state.compiling = false
}

View File

@@ -1,21 +1,19 @@
import { getFileExtention } from '../../utils/helpers'
import state, { IFile } from '../index'
const languageMapping = {
const languageMapping: Record<string, string | undefined> = {
ts: 'typescript',
js: 'javascript',
md: 'markdown',
c: 'c',
h: 'c',
other: ''
} /* Initializes empty file to global state */
txt: 'text'
}
export const createNewFile = (name: string) => {
const tempName = name.split('.')
const fileExt = tempName[tempName.length - 1] || 'other'
const emptyFile: IFile = {
name,
language: languageMapping[fileExt as 'ts' | 'js' | 'md' | 'c' | 'h' | 'other'],
content: ''
}
const ext = getFileExtention(name) || ''
const emptyFile: IFile = { name, language: languageMapping[ext] || 'text', content: '' }
state.files.push(emptyFile)
state.active = state.files.length - 1
}
@@ -24,5 +22,8 @@ export const renameFile = (oldName: string, nwName: string) => {
const file = state.files.find(file => file.name === oldName)
if (!file) throw Error(`No file exists with name ${oldName}`)
const ext = getFileExtention(nwName) || ''
const language = languageMapping[ext] || 'text'
file.name = nwName
file.language = language
}

View File

@@ -61,6 +61,7 @@ export const fetchFiles = async (gistId: string) => {
// default priority is undefined == 0
const extPriority: Record<string, number> = {
c: 3,
wat: 3,
md: 2,
h: -1
}

79
state/constants/flags.ts Normal file
View File

@@ -0,0 +1,79 @@
import { SelectOption } from '../transactions';
interface Flags {
[key: string]: string;
}
export const transactionFlags: { [key: /* TransactionType */ string]: Flags } = {
"*": {
tfFullyCanonicalSig: '0x80000000'
},
Payment: {
tfNoDirectRipple: '0x00010000',
tfPartialPayment: '0x00020000',
tfLimitQuality: '0x00040000',
},
AccountSet: {
tfRequireDestTag: '0x00010000',
tfOptionalDestTag: '0x00020000',
tfRequireAuth: '0x00040000',
tfOptionalAuth: '0x00080000',
tfDisallowXRP: '0x00100000',
tfAllowXRP: '0x00200000',
},
NFTokenCreateOffer: {
tfSellNFToken: '0x00000001',
},
NFTokenMint: {
tfBurnable: '0x00000001',
tfOnlyXRP: '0x00000002',
tfTrustLine: '0x00000004',
tfTransferable: '0x00000008',
},
OfferCreate: {
tfPassive: '0x00010000',
tfImmediateOrCancel: '0x00020000',
tfFillOrKill: '0x00040000',
tfSell: '0x00080000',
},
PaymentChannelClaim: {
tfRenew: '0x00010000',
tfClose: '0x00020000',
},
TrustSet: {
tfSetfAuth: '0x00010000',
tfSetNoRipple: '0x00020000',
tfClearNoRipple: '0x00040000',
tfSetFreeze: '0x00100000',
tfClearFreeze: '0x00200000',
},
}
export const getFlags = (tt?: string) => {
if (!tt) return
const flags = {
...transactionFlags['*'],
...transactionFlags[tt]
}
return flags
}
export function combineFlags(flags?: string[]): string | undefined {
if (!flags) return
const num = flags.reduce((cumm, curr) => cumm | BigInt(curr), BigInt(0))
return num.toString()
}
export function extractFlags(transactionType: string, flags?: string | number,): SelectOption[] {
const flagsObj = getFlags(transactionType)
if (!flags || !flagsObj) return []
const extracted = Object.entries(flagsObj).reduce((cumm, [label, value]) => {
return (BigInt(flags) & BigInt(value)) ? cumm.concat({ label, value }) : cumm
}, [] as SelectOption[])
return extracted
}

View File

@@ -4,6 +4,7 @@ import transactionsData from '../content/transactions.json'
import state from '.'
import { showAlert } from '../state/actions/showAlert'
import { parseJSON } from '../utils/json'
import { extractFlags, getFlags } from './constants/flags'
export type SelectOption = {
value: string
@@ -14,6 +15,7 @@ export interface TransactionState {
selectedTransaction: SelectOption | null
selectedAccount: SelectOption | null
selectedDestAccount: SelectOption | null
selectedFlags: SelectOption[] | null
txIsLoading: boolean
txIsDisabled: boolean
txFields: TxFields
@@ -31,6 +33,7 @@ export const defaultTransaction: TransactionState = {
selectedTransaction: null,
selectedAccount: null,
selectedDestAccount: null,
selectedFlags: null,
txIsLoading: false,
txIsDisabled: false,
txFields: {},
@@ -128,9 +131,8 @@ export const prepareTransaction = (data: any) => {
try {
options[field] = JSON.parse(_value.$value)
} catch (error) {
const message = `Input error for json field '${field}': ${
error instanceof Error ? error.message : ''
}`
const message = `Input error for json field '${field}': ${error instanceof Error ? error.message : ''
}`
console.error(message)
options[field] = _value.$value
}
@@ -205,6 +207,13 @@ export const prepareState = (value: string, transactionType?: string) => {
rest.Destination = Destination
}
if (getFlags(TransactionType) && rest.Flags) {
const flags = extractFlags(TransactionType, rest.Flags)
rest.Flags = undefined
tx.selectedFlags = flags
}
Object.keys(rest).forEach(field => {
const value = rest[field]
const schemaVal = schema[field as keyof TxFields]

View File

@@ -13,3 +13,9 @@ export const capitalize = (value?: string) => {
return value[0].toLocaleUpperCase() + value.slice(1)
}
export const getFileExtention = (filename?: string): string | undefined => {
if (!filename) return
const ext = (filename.includes('.') && filename.split('.').pop()) || undefined
return ext
}

View File

@@ -22,6 +22,7 @@ import hooksFloatManipPure from './md/hooks-float-manip-pure.md'
import hooksFloatOnePure from './md/hooks-float-one-pure.md'
import hooksFloatPure from './md/hooks-float-pure.md'
import hooksGuardCalled from './md/hooks-guard-called.md'
import hooksGuardCallNonConst from './md/hooks-guard-call-non-const.md'
import hooksGuardInFor from './md/hooks-guard-in-for.md'
import hooksGuardInWhile from './md/hooks-guard-in-while.md'
import hooksHashBufLen from './md/hooks-hash-buf-len.md'
@@ -70,6 +71,7 @@ const docs: { [key: string]: string } = {
'hooks-float-one-pure': hooksFloatOnePure,
'hooks-float-pure': hooksFloatPure,
'hooks-guard-called': hooksGuardCalled,
'hooks-guard-call-non-const': hooksGuardCallNonConst,
'hooks-guard-in-for': hooksGuardInFor,
'hooks-guard-in-while': hooksGuardInWhile,
'hooks-hash-buf-len': hooksHashBufLen,

View File

@@ -0,0 +1,6 @@
# hooks-guard-call-non-const
Only compile-time constants can be used as an argument in loop GUARD call. This check warns if a non compile-time constant is used.
It also checks whether a compile-time constant is used as a first argument of `_g()` call and whether it is a unique value. If not - it warns.
[Read more](https://xrpl-hooks.readme.io/v2.0/docs/loops-and-guarding)

View File

@@ -1,14 +1,35 @@
# hooks-guard-in-for
A guard is a marker that must be placed in your code at the top of each loop. Consider the following for-loop in C:
Consider the following for-loop in C:
```c
#define GUARD(maxiter) _g(__LINE__, (maxiter)+1)
for (int i = 0; GUARD(3), i < 3; ++i)
#define GUARD(maxiter) _g(__LINE__, (maxiter)+1)
for (int i = 0; GUARD(3), i < 3; ++i)
```
<BR/>
This is the only way to satisfy the guard rule when using a for-loop in C.
To satisfy the guard rule when using a for-loop in C guard should be
placed either in the condition part of the loop, or as a first call in loop body, e.g.
```c
for(int i = 0; i < 3; ++i) {
GUARD(3);
}
```
In case of nested loops, the guard limit value should be
multiplied by a number of iterations in each loop, e.g.
```c
for(int i = 0; GUARD(3), i < 3; ++i) {
for (int j = 0; GUARD(17), j < 5; ++j)
}
```
```
(most descendant loop iterations + 1) * (each parent loops iterations) - 1
```
This check will warn if the GUARD call is missing and also it will propose a GUARD value based on the for loop initial value,
the increment and loop condition.
[Read more](https://xrpl-hooks.readme.io/v2.0/docs/loops-and-guarding)

View File

@@ -2725,9 +2725,9 @@ javascript-time-ago@^2.3.11:
relative-time-format "^1.0.7"
jose@^4.1.4, jose@^4.3.7:
version "4.6.0"
resolved "https://registry.npmjs.org/jose/-/jose-4.6.0.tgz"
integrity sha512-0hNAkhMBNi4soKSAX4zYOFV+aqJlEz/4j4fregvasJzEVtjDChvWqRjPvHwLqr5hx28Ayr6bsOs1Kuj87V0O8w==
version "4.10.0"
resolved "https://registry.yarnpkg.com/jose/-/jose-4.10.0.tgz#2e0b7bcc80dd0775f8a4588e55beb9460c37d60a"
integrity sha512-KEhB/eLGLomWGPTb+/RNbYsTjIyx03JmbqAyIyiXBuNSa7CmNrJd5ysFhblayzs/e/vbOPMUaLnjHUMhGp4yLw==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
@@ -4765,10 +4765,10 @@ vscode-uri@^3.0.2:
resolved "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.3.tgz"
integrity sha512-EcswR2S8bpR7fD0YPeS7r2xXExrScVMxg4MedACaWHEtx9ftCF/qHG1xGkolzTPcEmjTavCQgbVzHUIdTMzFGA==
wabt@1.0.16:
version "1.0.16"
resolved "https://registry.npmjs.org/wabt/-/wabt-1.0.16.tgz"
integrity sha512-aSQEAJfYkoZRY9Qt2/6hTM8yRX/Nc2R1bScET/4lppRqfUyzynB5HI+lK0u/hp8NbCVTAXg0iETviSS3zoufJw==
wabt@^1.0.30:
version "1.0.30"
resolved "https://registry.yarnpkg.com/wabt/-/wabt-1.0.30.tgz#23cff6d38a05d0718e298fda371a70f0dff38ad7"
integrity sha512-qM1QnttJhjZ4vTSuXvder43yxgGhVffT/0wMc0SwYpboEW0/ENISpei/2kIDEMPrnNfTQ4GdvD7JIFV0IJPYog==
webidl-conversions@^3.0.0:
version "3.0.1"