
Security News
/Research
Wallet-Draining npm Package Impersonates Nodemailer to Hijack Crypto Transactions
Malicious npm package impersonates Nodemailer and drains wallets by hijacking crypto transactions across multiple blockchains.
A library that simplifies the process of parsing and validating command-line arguments using the Zod validation library
npm install zod-opts # npm
yarn add zod-opts # yarn
File: simple.ts
import { z } from "zod";
import { parser } from "zod-opts";
const parsed = parser()
.options({
option1: {
type: z.boolean().default(false),
alias: "a",
},
option2: {
type: z.string(),
},
})
.parse(); // same with .parse(process.argv.slice(2))
// parsed is inferred as { option1: boolean, option2: string }
console.log(parsed);
# Valid options
$ node simple.js --option1 --option2=str # or `node simple.js -a --option2 str`
{ option1: true, option2: 'str' }
# Help
$ node simple.js --help
Usage: simple.js [options]
Options:
-h, --help Show help
-a, --option1 (default: false)
--option2 <string> [required]
# Invalid options show help and make exit(1)
$ node simple.js
Required option is missing: option2
Usage: simple.js [options]
Options:
-h, --help Show help
-a, --option1 (default: false)
--option2 <string> [required]
File: complex.ts
import { z } from "zod";
// import { parser } from "zod-opts";
import { parser } from "../src/index";
const parsed = parser()
.name("scriptA") // script name on Usage
.version("1.0.0") // version on Usage
.options({
option1: {
// if default() is specified, it will be optional option.
type: z.string().describe("description of option").default("default"),
argumentName: "NameA", // used in Usage.
},
option2: {
type: z
.string()
.regex(/[a-z]+/) // you can use zod's various methods.
.optional(), // if optional() is specified, it will be optional option.
},
option3: {
type: z.number().min(5), // accepts only number and greater than 5.
},
option4: {
type: z.enum(["a", "b", "c"]).default("b"), // accepts only "a", "b", "c" and default is "b".
},
})
.args([
{
// And required arguments.
name: "arg1",
type: z.string(),
},
])
.parse();
// parsed is inferred as below.
// const parsed: {
// option1: string;
// option2?: string | undefined;
// option3: number;
// option4: "a" | "b" | "c";
// arg1: string;
// }
console.log(parsed);
# Valid options
$ node complex.js --option3=10 arg_str
{
option1: 'default',
option2: undefined,
option3: 10,
option4: 'b',
arg1: 'arg_str'
}
# Help
$ node complex.js --help
Usage: scriptA [options] <arg1>
Arguments:
arg1 [required]
Options:
-h, --help Show help
-V, --version Show version
--option1 <NameA> description of option (default: "default")
--option2 <string>
--option3 <number> [required]
--option4 <string> (choices: "a", "b", "c") (default: "b")
# Version
$ node complex.js --version
1.0.0
File: boolean.ts
const parsed = parser()
.options({
option1: {
type: z.boolean(), // required option. type is boolean
},
option2: {
type: z.boolean().default(false), // optional option. type is boolean
},
option3: {
type: z.boolean().optional(), // optional option. type is boolean|undefined
},
option4: {
type: z.boolean().default(false).optional(), // optional option. type is boolean|undefined
},
})
.parse();
// parsed is inferred as below:
// const parsed: {
// option1: boolean;
// option2: boolean;
// option3?: boolean;
// option4?: boolean;
// }
You can use '--no-' prefix to set false(ex. --no-option1
).
const parsed = parser()
.options({
option1: {
type: z.boolean().default(true),
},
})
.parse();
console.log(parsed);
$ node script.js --no-option1
{ option1: false }
File: enum.ts
const parsed = parser()
.options({
option1: {
type: z.enum(["a", "b"]), // required option. type is "a"|"b"
},
option2: {
type: z.enum(["a", "b"]).default("b"), // optional option. type is "a"|"b"
},
option3: {
type: z.enum(["a", "b"]).optional(), // optional option. type is "a"|"b"|undefined
},
option4: {
type: z.enum(["a", "b"]).default("b").optional(), // optional option. type is "a"|"b"|undefined
},
})
.args([
{
name: "position1",
type: z.enum(["a", "b"]), // required arg. type is "a"|"b"
},
])
.parse();
// parsed is inferred as below:
// const parsed: {
// option1: "a" | "b";
// option2: "a" | "b";
// option3?: "a" | "b";
// option4?: "a" | "b";
// position1: "a" | "b";
// };
console.log(parsed);
CAUTION: program --opt opt_arg1 opt_arg2 pos_arg
will be treated as opt=['opt_arg1' 'opt_arg2' 'pos_arg']
.
In this case, the user should use program --opt opt_arg1 opt_arg2 -- pos_arg
.
File: array_option.ts
const parsed = parser()
.options({
opt: {
type: z.array(z.string()), // required option. type is string[]
// type: z.array(z.string()).default([]), // optional arg. type is string[] and default is []
},
})
.parse();
// parsed is inferred as below:
// const parsed: {
// opt: string[];
// };
console.log(parsed);
# Valid options
$ node array_option.js --opt str1 str2
{ opt: [ 'str1', 'str2' ] }
# Invalid options (empty array is not permitted. use `.default([])` instead).
$ node array_option.js --opt
Option 'opt' needs value: opt
Usage: array_option.js [options]
Options:
-h, --help Show help
--opt <string ...> [required]
File: array_argument.ts
const parsed = parser()
.args([
{
name: "pos",
type: z.array(z.string()), // required arg. type is string[]
// type: z.array(z.string()).default([]), // optional arg. type is string[] and default is []
},
])
.parse();
// parsed is inferred as below:
// const parsed: {
// pos: string[];
// };
console.log(parsed);
# Valid options
$ node array_argument.js str1 str2
{ pos: [ 'str1', 'str2' ] }
# Invalid options (empty array is not permitted. use `.default([])` instead).
$ node array_argument.js
Required argument is missing: pos
Usage: array_argument.js [options] <pos ...>
Arguments:
pos [required]
Options:
-h, --help Show help
You can use Zod's .refine()
method to validate each option(e.g. z.string().refine((v) => v === "foo" || v === "bar", {message: "option1 must be foo or bar"}
).
If you want to check combinations of options, you can use .validation()
method. .validation()
registers the custom validation function. And the function is called after default validation.
File: custom_validation.ts
const parsed = parser()
.options({
option1: {
type: z.number(),
},
option2: {
type: z.number(),
},
})
.validation((parsed) => {
if (parsed.option1 === parsed.option2) {
throw Error("option1 and option2 must be different"); // or return "option1 and option2 must be different"
}
return true;
})
.parse();
console.log(parsed);
# Valid options
$ node custom_validation.js --option1=10 --option2=11
{ option1: 10, option2: 11 }
# Invalid options
$ node custom_validation.js --option1=10 --option2=10
option1 and option2 must be different
Usage: custom_validation.js [options]
Options:
-h, --help Show help
--option1 <number> [required]
--option2 <number> [required]
Please refer array types.
File command.ts
import { z } from "zod";
import { parser } from "zod-opts";
const command1 = command("command1")
.options({
option1: {
type: z.boolean().default(false),
},
})
.action((parsed) => {
// parsed is inferred as { option1: boolean }
console.log("command2", parsed);
});
const command2 = command("command2")
.options({
option1: {
type: z.string(),
},
})
.action((parsed) => {
// parsed is inferred as { option1: string }
console.log("command2", parsed);
});
parser().subcommand(command1).subcommand(command2).parse();
# Valid options
$ node command.js command1 --option1
command1 { option1: true }
# Invalid options
$ node command.js command2 a
Too many positional arguments
Usage: command.js command2 [options]
Options:
-h, --help Show help
--option1 <string> [required]
# Global help
$ node command.js --help
Usage: command.js [options] <command>
Commands:
command1
command2
Options:
-h, --help Show help
# Command help
$ node command.js command1 --help
Usage: command.js command1 [options]
Options:
-h, --help Show help
--option1 (default: false)
You can .showHelp()
to show help message. And .getHelp()
returns the help message.
If the parser has called with .version()
method, The user can show the version with --version
or -V
option.
$ node complex.js --version
1.0.0
If you want to reuse Zod object type, you can define the type and use it in .options()
and .args()
.
File: map_zod_object.ts
import { z } from "zod";
import { parser } from "zod-opts";
const OptionsSchema = z.object({
opt1: z.string(),
opt2: z.number().optional(),
pos1: z.enum(["a", "b"]),
});
type Options = z.infer<typeof OptionsSchema>;
function parseOptions(): Options {
return parser()
.name("scriptA")
.version("1.0.0")
.description("desc")
.options({
opt1: { type: OptionsSchema.shape.opt1 },
opt2: { type: OptionsSchema.shape.opt2 },
})
.args([
{
name: "pos1",
type: OptionsSchema.shape.pos1,
},
])
.parse();
}
const options = parseOptions();
console.log(options);
z.array()
type in options()
.asyncParse()
FAQs
node.js CLI option parser / validator using Zod
The npm package zod-opts receives a total of 1,013 weekly downloads. As such, zod-opts popularity was classified as popular.
We found that zod-opts demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
/Research
Malicious npm package impersonates Nodemailer and drains wallets by hijacking crypto transactions across multiple blockchains.
Security News
This episode explores the hard problem of reachability analysis, from static analysis limits to handling dynamic languages and massive dependency trees.
Security News
/Research
Malicious Nx npm versions stole secrets and wallet info using AI CLI tools; Socket’s AI scanner detected the supply chain attack and flagged the malware.