-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add .dryrun Command Support #191
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
import { dryrun } from "@permaweb/aoconnect"; | ||
import chalk from "chalk"; | ||
|
||
export async function performDryRun(input, pid, data, owner, id, anchor) { | ||
await processInput(input, pid, data, owner, id, anchor); | ||
} | ||
|
||
async function extractTags(input, pid) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This code needs to be simplified. I suggest you reduce complexity by:
This should give an indication:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P.S if target can be appended you can get rid of else al in all
|
||
let tags = []; | ||
|
||
// Check if the input contains curly braces | ||
if (!input.includes("{")) { | ||
throw new Error("Tags not specified"); | ||
} | ||
|
||
// Check if the input contains curly braces | ||
if (input.includes("{")) { | ||
try { | ||
// Extracting content within curly braces | ||
const content = input.match(/\{(.*?)\}/)[1]; | ||
|
||
const pairs = content.split(","); | ||
|
||
// Iterating through each key-value pair | ||
pairs.forEach((pair) => { | ||
// Check if the pair contains an equal sign | ||
if (pair.includes("=")) { | ||
// Splitting each pair by "=" to get key and value | ||
const [key, value] = pair.split("=").map((item) => item.trim()); | ||
// Normalize the value | ||
let normalizedValue = value; | ||
normalizedValue = normalizedValue.replace(/^['"](.*)['"]$/, "$1"); | ||
|
||
console.log("normalizedValue", normalizedValue); | ||
|
||
// Replace "ao.id" with `pid` | ||
if (normalizedValue === "ao.id") { | ||
normalizedValue = pid; | ||
} | ||
|
||
//use extra quotes to use the "ao.id" word itself | ||
if (normalizedValue === "'ao.id'" || normalizedValue === `ao.id"`) { | ||
normalizedValue = "ao.id"; | ||
} | ||
|
||
// Pushing key-value pair to tags array | ||
tags.push({ name: key, value: normalizedValue }); | ||
} else { | ||
const action = pair.trim().replace(/^'|'$/g, ""); | ||
tags.push({ name: "Action", value: action }); | ||
} | ||
}); | ||
} catch (error) { | ||
throw new Error("Invalid Syntax Usage"); | ||
} | ||
} else { | ||
// If no curly braces, assume single word input, set it as Action | ||
const action = input.trim().replace(/^'|'$/g, ""); | ||
let normalizedAction = action; | ||
normalizedAction = normalizedAction.replace(/^['"](.*)['"]$/, "$1"); | ||
console.log(normalizedAction); | ||
tags.push({ name: "Action", value: normalizedAction }); | ||
} | ||
|
||
// Adding default Target if not already present | ||
let targetIncluded = tags.some((tag) => tag.name === "Target"); | ||
if (!targetIncluded) { | ||
tags.unshift({ name: "Target", value: pid }); | ||
} | ||
|
||
return tags; | ||
} | ||
|
||
async function callDryRun(input, pid, data, owner, id, anchor) { | ||
try { | ||
const tags = await extractTags(input, pid); | ||
// check for Pid and data in params | ||
const customProcessId = getCustomProcessId(input, pid) || pid; | ||
const customData = getCustomData(input, pid) || data; | ||
|
||
const dryrunParams = { | ||
process: customProcessId, | ||
tags, | ||
...(customData && { data: customData }), | ||
...(owner && { Owner: owner }), | ||
...(id && { Id: id }), | ||
...(anchor && { anchor: anchor }), | ||
}; | ||
|
||
checkForVerboseFlag(input, dryrunParams); | ||
|
||
const result = await dryrun(dryrunParams); | ||
return result; | ||
} catch (error) { | ||
console.error(chalk.red("Error Performing DryRun:", error.message)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it not be right to propagate the error up in context? Why swallow it here. |
||
} | ||
} | ||
|
||
function checkForVerboseFlag(input, dryrunParams) { | ||
const regex = /(^|\s)-v($|\s)/; // Regular expression to match -v preceded and followed by whitespace or string boundary | ||
|
||
if (regex.test(input)) { | ||
console.log("dryrunParams:", dryrunParams); | ||
} | ||
} | ||
|
||
|
||
const getCustomProcessId = (input, pid) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Slightly cleaner.
|
||
const match = input.match(/-p=(["'])(.*?)\1/); | ||
if (match) { | ||
let customProcessParam = match[2]; | ||
|
||
// Replace "ao.id" with `pid` | ||
if (customProcessParam === "ao.id") { | ||
customProcessParam = pid; | ||
} | ||
|
||
if (customProcessParam.length !== 43) { | ||
throw new Error("Invalid Process Id"); | ||
} | ||
return customProcessParam; | ||
} | ||
return null; | ||
}; | ||
|
||
const getCustomData = (input, pid) => { | ||
try { | ||
let match = input.match(/-d=(["'])(.*?)\1/); | ||
if (match) { | ||
if (match[2] === "ao.id") { | ||
return pid; | ||
} | ||
|
||
if (match[2] === "'ao.id'" || match[2] === `"ao.id"`) { | ||
return "ao.id"; | ||
} | ||
|
||
return match[2]; | ||
} | ||
} catch (error) { | ||
throw new Error("Invalid Data Format"); | ||
} | ||
return null; | ||
}; | ||
|
||
const getSpecificResult = (obj, path, defaultValue = undefined) => { | ||
const travel = (regexp) => | ||
String.prototype.split | ||
.call(path, regexp) | ||
.filter(Boolean) | ||
.reduce( | ||
(res, key) => (res !== null && res !== undefined ? res[key] : res), | ||
obj, | ||
); | ||
|
||
const result = travel(/[,[\]]+?/) || travel(/[,[\].]+?/); | ||
return result === undefined || result === obj ? defaultValue : result; | ||
}; | ||
|
||
async function processInput(input, pid, data, owner, id, anchor) { | ||
try { | ||
const flagIndex = input.indexOf("-r"); | ||
const flag = flagIndex !== -1 ? getFlag(input, flagIndex) : null; | ||
const result = await callDryRun(input, pid, data, owner, id, anchor); | ||
console.log(chalk.green("result:")); | ||
flag ? console.log(getSpecificResult(result, flag)) : console.log(result); | ||
} catch (error) { | ||
console.error(chalk.red("Error Processing Input:", error.message)); | ||
} | ||
} | ||
|
||
const getFlag = (input, flagIndex) => { | ||
const flagStart = flagIndex + 3; | ||
const flagEnd = input.indexOf(" ", flagStart); | ||
return input.slice(flagStart, flagEnd !== -1 ? flagEnd : undefined).trim(); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
# README for Command: .dryrun | ||
|
||
### Syntax | ||
|
||
.dryrun <flags> <{Tags}> | ||
|
||
### Quick Examples | ||
|
||
- Replacing the Send command with `.dryrun`: | ||
|
||
.dryrun ({ Target = 'FgU-RiEaLuC__SHZnI9pSIa_ZI8o-8hUVG9nPJvs92k', Action = 'Balance' }) | ||
|
||
or | ||
|
||
- Using single word Action: | ||
|
||
.dryrun ({Balance}). | ||
|
||
**Note:** | ||
- While using single words, the word inside the braces will be considered as Action ('Action'='Word'), and it takes your Process ID `ao.id` as both the Target and Process ID by default. | ||
- Tags must be enclosed with curly braces `{}` surrounding the circle brackets with parentheses `()` is optional. | ||
|
||
|
||
|
||
## Flags: | ||
These flags determine the output you get on your terminal. | ||
|
||
### TheFlags List: | ||
- `-p` for specifying Process ID. | ||
- `-d` for specifying data. | ||
- `-r` for accessing the Result Object. | ||
- `-v` for viewing the DryRun Parameterss | ||
|
||
### Usage: | ||
- Flags can be used in combinations, and the order of flags can be interchangeable. | ||
- If you don't specify any flags, it will default to the `result object` (`-r`). | ||
- If you don't specify a `-p` Process ID, your Process ID will be used. | ||
- If you don't specify any `-d`, no data will be passed. | ||
|
||
|
||
|
||
|
||
## Tags: | ||
The tags that will be passed to perform DryRun. | ||
|
||
### Usage: | ||
- Tags must be enclosed with curly braces `{}`. Surrounding the circle brackets with parentheses `()` is optional. | ||
- Single word tags must also be enclosed within curly braces `{}`. | ||
- By default, the single word will be considered as Action. It takes your Process ID `ao.id` as both the Target and Process ID by default. | ||
|
||
### Using 'ao.id' | ||
Using "ao.id" to mention Process ID will work fine. By default Process ID and Target ID will be 'ao.id' (your process id). so its better to leave eit without mentioning it. If you want to specify the "ao.id" word itself, then give it enclosed with a single quote enclosed with a double quote. | ||
|
||
Samples : | ||
|
||
# to get ao.id | ||
|
||
.dryrun {'Balance'} | ||
|
||
.dryrun ({ Target = ao.id, Action = 'Balance' }) | ||
|
||
.dryrun ({ Target = 'ao.id', Action = 'Balance' }) | ||
|
||
# to get 'ao.id' | ||
|
||
.dryrun ({ Target = "'ao.id'", Action = 'Balance' }) | ||
|
||
|
||
## Examples: | ||
|
||
- Replacing the Send command with `.dryrun` will give you the Result Object: | ||
|
||
.dryrun ({ Target = 'FgU-RiEaLuC__SHZnI9pSIa_ZI8o-8hUVG9nPJvs92k', Action = 'Balance' }) | ||
|
||
- Using Single word Action: | ||
|
||
.dryrun ({Balance}) | ||
|
||
This will use "Balance" as Action and your Process ID as Target & Process ID: | ||
|
||
# .dryrun ({ Target = ao.id, Action = 'Balance' }) | ||
|
||
**Sample Result Object Output:** | ||
|
||
{ | ||
Messages: [ | ||
{ | ||
Target: '1234', | ||
Anchor: '00000000000000000000000000000917', | ||
Tags: [Array] | ||
} | ||
], | ||
Spawns: [], | ||
Output: [], | ||
GasUsed: 466333831 | ||
} | ||
|
||
This will give you the Result Overview. (More details will be available in the Message property.) | ||
|
||
|
||
- Accessing the keys of the Result Object: | ||
|
||
.dryrun -r.Messages[0] ({Balance}) | ||
|
||
This will give the Message Object of index=0 in Messages Array in the result object. | ||
|
||
Example Output: | ||
|
||
{ | ||
Target: '1234', | ||
Anchor: '00000000000000000000000000000917', | ||
Tags: [ | ||
{ value: 'ao', name: 'Data-Protocol' }, | ||
{ value: 'ao.TN.1', name: 'Variant' }, | ||
{ value: 'Message', name: 'Type' }, | ||
{ | ||
value: 'FgU-RiEaLuC__SHZnI9pSIa_ZI8o-8hUVG9nPJvs92k', | ||
name: 'From-Process' | ||
}, | ||
{ | ||
value: '9afQ1PLf2mrshqCTZEzzJTR2gWaC9zNPnYgYEqg1Pt4', | ||
name: 'From-Module' | ||
}, | ||
{ value: '917', name: 'Ref_' }, | ||
{ value: '1e+14', name: 'Data' }, | ||
{ value: '1234', name: 'Target' }, | ||
{ value: 'PNTS', name: 'Ticker' }, | ||
{ value: '100000000000000', name: 'Balance' } | ||
] | ||
} | ||
|
||
|
||
- Sending data to the DryRun: | ||
|
||
.dryrun -d="test" ({Balance}) | ||
|
||
or | ||
|
||
.dryrun -d="test" ({ Target = 'FgU-RiEaLuC__SHZnI9pSIa_ZI8o-8hUVG9nPJvs92k', Action = 'Balance' }) | ||
|
||
or sending as Tag **(recommended method)**: | ||
|
||
.dryrun -d="test" ({ Target = 'FgU-RiEaLuC__SHZnI9pSIa_ZI8o-8hUVG9nPJvs92k', Action = 'Balance' , Data = 'test'}) | ||
|
||
|
||
- Passing Process ID: | ||
|
||
.dryrun -p="FgU-RiEaLuC__SHZnI9pSIa_ZI8o-8hUVG9nPJvs92k" ({Balance}) | ||
|
||
|
||
- Viewing DryRun Params : | ||
|
||
.dryrun -v {Message} | ||
|
||
Example Output : | ||
|
||
dryrunParams: { | ||
process: 'FXYu2-c66N90yG2yqL0myafDgRTGONn0xn7xmZxEq7g', | ||
tags: [ | ||
{ | ||
name: 'Target', | ||
value: 'FXYu2-c66N90yG2yqL0myafDgRTGONn0xn7xmZxEq7g' | ||
}, | ||
{ name: 'Action', value: 'Message' } | ||
] | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This
s
seem to be a typo?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, that's a typo.