gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: taler-util: fix CLI parsing f


From: gnunet
Subject: [taler-wallet-core] branch master updated: taler-util: fix CLI parsing for numberic options
Date: Mon, 19 Sep 2022 17:46:36 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new a5525eab1 taler-util: fix CLI parsing for numberic options
a5525eab1 is described below

commit a5525eab1e96d5b08fbb6442275b1e92f7f8d806
Author: Florian Dold <florian@dold.me>
AuthorDate: Mon Sep 19 17:46:30 2022 +0200

    taler-util: fix CLI parsing for numberic options
---
 packages/taler-util/src/clk.test.ts    |  46 +++
 packages/taler-util/src/clk.ts         |  46 ++-
 packages/taler-wallet-cli/src/clk.ts   | 614 ---------------------------------
 packages/taler-wallet-cli/src/index.ts |  78 ++---
 4 files changed, 112 insertions(+), 672 deletions(-)

diff --git a/packages/taler-util/src/clk.test.ts 
b/packages/taler-util/src/clk.test.ts
new file mode 100644
index 000000000..bec93947b
--- /dev/null
+++ b/packages/taler-util/src/clk.test.ts
@@ -0,0 +1,46 @@
+/*
+ This file is part of GNU Taler
+ (C) 2018-2019 GNUnet e.V.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Type-safe codecs for converting from/to JSON.
+ */
+
+import test from "ava";
+import { clk } from "./clk.js";
+import {
+  Codec,
+  buildCodecForObject,
+  codecForConstString,
+  codecForString,
+  buildCodecForUnion,
+} from "./codec.js";
+
+test("bla", (t) => {
+  const prog = clk.program("foo", {
+    help: "Hello",
+  });
+
+  let success = false;
+
+  prog.maybeOption("opt1", ["-o", "--opt1"], clk.INT).action((args) => {
+    success = true;
+    t.deepEqual(args.foo.opt1, 42);
+  });
+
+  prog.run(["bla", "-o", "42"]);
+
+  t.true(success);
+});
diff --git a/packages/taler-util/src/clk.ts b/packages/taler-util/src/clk.ts
index d172eed48..e99ebf733 100644
--- a/packages/taler-util/src/clk.ts
+++ b/packages/taler-util/src/clk.ts
@@ -20,6 +20,7 @@
 import process from "process";
 import path from "path";
 import readline from "readline";
+import { devNull } from "os";
 
 export namespace clk {
   class Converter<T> {}
@@ -329,6 +330,20 @@ export namespace clk {
       const myArgs: any = (parsedArgs[this.argKey] = {});
       const foundOptions: { [name: string]: boolean } = {};
       const currentName = this.name ?? progname;
+      const storeOption = (def: OptionDef, value: string) => {
+        foundOptions[def.name] = true;
+        if (def.conv === INT) {
+          myArgs[def.name] = Number.parseInt(value);
+        } else if (def.conv == null || def.conv === STRING) {
+          myArgs[def.name] = value;
+        } else {
+          throw Error("unknown converter");
+        }
+      };
+      const storeFlag = (def: OptionDef, value: boolean) => {
+        foundOptions[def.name] = true;
+        myArgs[def.name] = value;
+      };
       for (i = 0; i < unparsedArgs.length; i++) {
         const argVal = unparsedArgs[i];
         if (argsTerminated == false) {
@@ -353,8 +368,7 @@ export namespace clk {
                 process.exit(-1);
                 throw Error("not reached");
               }
-              foundOptions[d.name] = true;
-              myArgs[d.name] = true;
+              storeFlag(d, true);
             } else {
               if (r.value === undefined) {
                 if (i === unparsedArgs.length - 1) {
@@ -362,12 +376,11 @@ export namespace clk {
                   process.exit(-1);
                   throw Error("not reached");
                 }
-                myArgs[d.name] = unparsedArgs[i + 1];
+                storeOption(d, unparsedArgs[i + 1]);
                 i++;
               } else {
-                myArgs[d.name] = r.value;
+                storeOption(d, r.value);
               }
-              foundOptions[d.name] = true;
             }
             continue;
           }
@@ -381,8 +394,7 @@ export namespace clk {
                 process.exit(-1);
               }
               if (opt.isFlag) {
-                myArgs[opt.name] = true;
-                foundOptions[opt.name] = true;
+                storeFlag(opt, true);
               } else {
                 if (si == optShort.length - 1) {
                   if (i === unparsedArgs.length - 1) {
@@ -390,13 +402,12 @@ export namespace clk {
                     process.exit(-1);
                     throw Error("not reached");
                   } else {
-                    myArgs[opt.name] = unparsedArgs[i + 1];
+                    storeOption(opt, unparsedArgs[i + 1]);
                     i++;
                   }
                 } else {
-                  myArgs[opt.name] = optShort.substring(si + 1);
+                  storeOption(opt, optShort.substring(si + 1));
                 }
-                foundOptions[opt.name] = true;
                 break;
               }
             }
@@ -508,16 +519,21 @@ export namespace clk {
       });
     }
 
-    run(): void {
-      const args = process.argv;
-      if (args.length < 2) {
+    run(cmdlineArgs?: string[]): void {
+      let args: string[];
+      if (cmdlineArgs) {
+        args = cmdlineArgs;
+      } else {
+        args = process.argv.slice(1);
+      }
+      if (args.length < 1) {
         console.error(
           "Error while parsing command line arguments: not enough arguments",
         );
         process.exit(-1);
       }
-      const progname = path.basename(args[1]);
-      const rest = args.slice(2);
+      const progname = path.basename(args[0]);
+      const rest = args.slice(1);
 
       this.mainCommand.run(progname, [], rest, {});
     }
diff --git a/packages/taler-wallet-cli/src/clk.ts 
b/packages/taler-wallet-cli/src/clk.ts
deleted file mode 100644
index ca6dcc1a4..000000000
--- a/packages/taler-wallet-cli/src/clk.ts
+++ /dev/null
@@ -1,614 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 GNUnet e.V.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * Imports.
- */
-import process from "process";
-import path from "path";
-import readline from "readline";
-
-class Converter<T> {}
-
-export const INT = new Converter<number>();
-export const STRING: Converter<string> = new Converter<string>();
-
-export interface OptionArgs<T> {
-  help?: string;
-  default?: T;
-  onPresentHandler?: (v: T) => void;
-}
-
-export interface ArgumentArgs<T> {
-  metavar?: string;
-  help?: string;
-  default?: T;
-}
-
-export interface SubcommandArgs {
-  help?: string;
-}
-
-export interface FlagArgs {
-  help?: string;
-}
-
-export interface ProgramArgs {
-  help?: string;
-}
-
-interface ArgumentDef {
-  name: string;
-  conv: Converter<any>;
-  args: ArgumentArgs<any>;
-  required: boolean;
-}
-
-interface SubcommandDef {
-  commandGroup: CommandGroup<any, any>;
-  name: string;
-  args: SubcommandArgs;
-}
-
-type ActionFn<TG> = (x: TG) => void;
-
-type SubRecord<S extends keyof any, N extends keyof any, V> = {
-  [Y in S]: { [X in N]: V };
-};
-
-interface OptionDef {
-  name: string;
-  flagspec: string[];
-  /**
-   * Converter, only present for options, not for flags.
-   */
-  conv?: Converter<any>;
-  args: OptionArgs<any>;
-  isFlag: boolean;
-  required: boolean;
-}
-
-function splitOpt(opt: string): { key: string; value?: string } {
-  const idx = opt.indexOf("=");
-  if (idx == -1) {
-    return { key: opt };
-  }
-  return { key: opt.substring(0, idx), value: opt.substring(idx + 1) };
-}
-
-function formatListing(key: string, value?: string): string {
-  const res = "  " + key;
-  if (!value) {
-    return res;
-  }
-  if (res.length >= 25) {
-    return res + "\n" + "    " + value;
-  } else {
-    return res.padEnd(24) + " " + value;
-  }
-}
-
-export class CommandGroup<GN extends keyof any, TG> {
-  private shortOptions: { [name: string]: OptionDef } = {};
-  private longOptions: { [name: string]: OptionDef } = {};
-  private subcommandMap: { [name: string]: SubcommandDef } = {};
-  private subcommands: SubcommandDef[] = [];
-  private options: OptionDef[] = [];
-  private arguments: ArgumentDef[] = [];
-
-  private myAction?: ActionFn<TG>;
-
-  constructor(
-    private argKey: string,
-    private name: string | null,
-    private scArgs: SubcommandArgs,
-  ) {}
-
-  action(f: ActionFn<TG>): void {
-    if (this.myAction) {
-      throw Error("only one action supported per command");
-    }
-    this.myAction = f;
-  }
-
-  requiredOption<N extends keyof any, V>(
-    name: N,
-    flagspec: string[],
-    conv: Converter<V>,
-    args: OptionArgs<V> = {},
-  ): CommandGroup<GN, TG & SubRecord<GN, N, V>> {
-    const def: OptionDef = {
-      args: args,
-      conv: conv,
-      flagspec: flagspec,
-      isFlag: false,
-      required: true,
-      name: name as string,
-    };
-    this.options.push(def);
-    for (const flag of flagspec) {
-      if (flag.startsWith("--")) {
-        const flagname = flag.substring(2);
-        this.longOptions[flagname] = def;
-      } else if (flag.startsWith("-")) {
-        const flagname = flag.substring(1);
-        this.shortOptions[flagname] = def;
-      } else {
-        throw Error("option must start with '-' or '--'");
-      }
-    }
-    return this as any;
-  }
-
-  maybeOption<N extends keyof any, V>(
-    name: N,
-    flagspec: string[],
-    conv: Converter<V>,
-    args: OptionArgs<V> = {},
-  ): CommandGroup<GN, TG & SubRecord<GN, N, V | undefined>> {
-    const def: OptionDef = {
-      args: args,
-      conv: conv,
-      flagspec: flagspec,
-      isFlag: false,
-      required: false,
-      name: name as string,
-    };
-    this.options.push(def);
-    for (const flag of flagspec) {
-      if (flag.startsWith("--")) {
-        const flagname = flag.substring(2);
-        this.longOptions[flagname] = def;
-      } else if (flag.startsWith("-")) {
-        const flagname = flag.substring(1);
-        this.shortOptions[flagname] = def;
-      } else {
-        throw Error("option must start with '-' or '--'");
-      }
-    }
-    return this as any;
-  }
-
-  requiredArgument<N extends keyof any, V>(
-    name: N,
-    conv: Converter<V>,
-    args: ArgumentArgs<V> = {},
-  ): CommandGroup<GN, TG & SubRecord<GN, N, V>> {
-    const argDef: ArgumentDef = {
-      args: args,
-      conv: conv,
-      name: name as string,
-      required: true,
-    };
-    this.arguments.push(argDef);
-    return this as any;
-  }
-
-  maybeArgument<N extends keyof any, V>(
-    name: N,
-    conv: Converter<V>,
-    args: ArgumentArgs<V> = {},
-  ): CommandGroup<GN, TG & SubRecord<GN, N, V | undefined>> {
-    const argDef: ArgumentDef = {
-      args: args,
-      conv: conv,
-      name: name as string,
-      required: false,
-    };
-    this.arguments.push(argDef);
-    return this as any;
-  }
-
-  flag<N extends string, V>(
-    name: N,
-    flagspec: string[],
-    args: OptionArgs<V> = {},
-  ): CommandGroup<GN, TG & SubRecord<GN, N, boolean>> {
-    const def: OptionDef = {
-      args: args,
-      flagspec: flagspec,
-      isFlag: true,
-      required: false,
-      name: name as string,
-    };
-    this.options.push(def);
-    for (const flag of flagspec) {
-      if (flag.startsWith("--")) {
-        const flagname = flag.substring(2);
-        this.longOptions[flagname] = def;
-      } else if (flag.startsWith("-")) {
-        const flagname = flag.substring(1);
-        this.shortOptions[flagname] = def;
-      } else {
-        throw Error("option must start with '-' or '--'");
-      }
-    }
-    return this as any;
-  }
-
-  subcommand<GN extends keyof any>(
-    argKey: GN,
-    name: string,
-    args: SubcommandArgs = {},
-  ): CommandGroup<GN, TG> {
-    const cg = new CommandGroup<GN, {}>(argKey as string, name, args);
-    const def: SubcommandDef = {
-      commandGroup: cg,
-      name: name as string,
-      args: args,
-    };
-    cg.flag("help", ["-h", "--help"], {
-      help: "Show this message and exit.",
-    });
-    this.subcommandMap[name as string] = def;
-    this.subcommands.push(def);
-    this.subcommands = this.subcommands.sort((x1, x2) => {
-      const a = x1.name;
-      const b = x2.name;
-      if (a === b) {
-        return 0;
-      } else if (a < b) {
-        return -1;
-      } else {
-        return 1;
-      }
-    });
-    return cg as any;
-  }
-
-  printHelp(progName: string, parents: CommandGroup<any, any>[]): void {
-    let usageSpec = "";
-    for (const p of parents) {
-      usageSpec += (p.name ?? progName) + " ";
-      if (p.arguments.length >= 1) {
-        usageSpec += "<ARGS...> ";
-      }
-    }
-    usageSpec += (this.name ?? progName) + " ";
-    if (this.subcommands.length != 0) {
-      usageSpec += "COMMAND ";
-    }
-    for (const a of this.arguments) {
-      const argName = a.args.metavar ?? a.name;
-      usageSpec += `<${argName}> `;
-    }
-    usageSpec = usageSpec.trimRight();
-    console.log(`Usage: ${usageSpec}`);
-    if (this.scArgs.help) {
-      console.log();
-      console.log(this.scArgs.help);
-    }
-    if (this.options.length != 0) {
-      console.log();
-      console.log("Options:");
-      for (const opt of this.options) {
-        let optSpec = opt.flagspec.join(", ");
-        if (!opt.isFlag) {
-          optSpec = optSpec + "=VALUE";
-        }
-        console.log(formatListing(optSpec, opt.args.help));
-      }
-    }
-
-    if (this.subcommands.length != 0) {
-      console.log();
-      console.log("Commands:");
-      for (const subcmd of this.subcommands) {
-        console.log(formatListing(subcmd.name, subcmd.args.help));
-      }
-    }
-  }
-
-  /**
-   * Run the (sub-)command with the given command line parameters.
-   */
-  run(
-    progname: string,
-    parents: CommandGroup<any, any>[],
-    unparsedArgs: string[],
-    parsedArgs: any,
-  ): void {
-    let posArgIndex = 0;
-    let argsTerminated = false;
-    let i;
-    let foundSubcommand: CommandGroup<any, any> | undefined = undefined;
-    const myArgs: any = (parsedArgs[this.argKey] = {});
-    const foundOptions: { [name: string]: boolean } = {};
-    const currentName = this.name ?? progname;
-    for (i = 0; i < unparsedArgs.length; i++) {
-      const argVal = unparsedArgs[i];
-      if (argsTerminated == false) {
-        if (argVal === "--") {
-          argsTerminated = true;
-          continue;
-        }
-        if (argVal.startsWith("--")) {
-          const opt = argVal.substring(2);
-          const r = splitOpt(opt);
-          const d = this.longOptions[r.key];
-          if (!d) {
-            console.error(
-              `error: unknown option '--${r.key}' for ${currentName}`,
-            );
-            process.exit(-1);
-            throw Error("not reached");
-          }
-          if (d.isFlag) {
-            if (r.value !== undefined) {
-              console.error(`error: flag '--${r.key}' does not take a value`);
-              process.exit(-1);
-              throw Error("not reached");
-            }
-            foundOptions[d.name] = true;
-            myArgs[d.name] = true;
-          } else {
-            if (r.value === undefined) {
-              if (i === unparsedArgs.length - 1) {
-                console.error(`error: option '--${r.key}' needs an argument`);
-                process.exit(-1);
-                throw Error("not reached");
-              }
-              myArgs[d.name] = unparsedArgs[i + 1];
-              i++;
-            } else {
-              myArgs[d.name] = r.value;
-            }
-            foundOptions[d.name] = true;
-          }
-          continue;
-        }
-        if (argVal.startsWith("-") && argVal != "-") {
-          const optShort = argVal.substring(1);
-          for (let si = 0; si < optShort.length; si++) {
-            const chr = optShort[si];
-            const opt = this.shortOptions[chr];
-            if (!opt) {
-              console.error(`error: option '-${chr}' not known`);
-              process.exit(-1);
-            }
-            if (opt.isFlag) {
-              myArgs[opt.name] = true;
-              foundOptions[opt.name] = true;
-            } else {
-              if (si == optShort.length - 1) {
-                if (i === unparsedArgs.length - 1) {
-                  console.error(`error: option '-${chr}' needs an argument`);
-                  process.exit(-1);
-                  throw Error("not reached");
-                } else {
-                  myArgs[opt.name] = unparsedArgs[i + 1];
-                  i++;
-                }
-              } else {
-                myArgs[opt.name] = optShort.substring(si + 1);
-              }
-              foundOptions[opt.name] = true;
-              break;
-            }
-          }
-          continue;
-        }
-      }
-      if (this.subcommands.length != 0) {
-        const subcmd = this.subcommandMap[argVal];
-        if (!subcmd) {
-          console.error(`error: unknown command '${argVal}'`);
-          process.exit(-1);
-          throw Error("not reached");
-        }
-        foundSubcommand = subcmd.commandGroup;
-        break;
-      } else {
-        const d = this.arguments[posArgIndex];
-        if (!d) {
-          console.error(`error: too many arguments for ${currentName}`);
-          process.exit(-1);
-          throw Error("not reached");
-        }
-        myArgs[d.name] = unparsedArgs[i];
-        posArgIndex++;
-      }
-    }
-
-    if (parsedArgs[this.argKey].help) {
-      this.printHelp(progname, parents);
-      process.exit(0);
-      throw Error("not reached");
-    }
-
-    for (let i = posArgIndex; i < this.arguments.length; i++) {
-      const d = this.arguments[i];
-      if (d.required) {
-        if (d.args.default !== undefined) {
-          myArgs[d.name] = d.args.default;
-        } else {
-          console.error(
-            `error: missing positional argument '${d.name}' for 
${currentName}`,
-          );
-          process.exit(-1);
-          throw Error("not reached");
-        }
-      }
-    }
-
-    for (const option of this.options) {
-      if (option.isFlag == false && option.required == true) {
-        if (!foundOptions[option.name]) {
-          if (option.args.default !== undefined) {
-            myArgs[option.name] = option.args.default;
-          } else {
-            const name = option.flagspec.join(",");
-            console.error(`error: missing option '${name}'`);
-            process.exit(-1);
-            throw Error("not reached");
-          }
-        }
-      }
-    }
-
-    for (const option of this.options) {
-      const ph = option.args.onPresentHandler;
-      if (ph && foundOptions[option.name]) {
-        ph(myArgs[option.name]);
-      }
-    }
-
-    if (foundSubcommand) {
-      foundSubcommand.run(
-        progname,
-        Array.prototype.concat(parents, [this]),
-        unparsedArgs.slice(i + 1),
-        parsedArgs,
-      );
-    } else if (this.myAction) {
-      let r;
-      try {
-        r = this.myAction(parsedArgs);
-      } catch (e) {
-        console.error(`An error occurred while running ${currentName}`);
-        console.error(e);
-        process.exit(1);
-      }
-      Promise.resolve(r).catch((e) => {
-        console.error(`An error occurred while running ${currentName}`);
-        console.error(e);
-        process.exit(1);
-      });
-    } else {
-      this.printHelp(progname, parents);
-      process.exit(-1);
-      throw Error("not reached");
-    }
-  }
-}
-
-export class Program<PN extends keyof any, T> {
-  private mainCommand: CommandGroup<any, any>;
-
-  constructor(argKey: string, args: ProgramArgs = {}) {
-    this.mainCommand = new CommandGroup<any, any>(argKey, null, {
-      help: args.help,
-    });
-    this.mainCommand.flag("help", ["-h", "--help"], {
-      help: "Show this message and exit.",
-    });
-  }
-
-  run(): void {
-    const args = process.argv;
-    if (args.length < 2) {
-      console.error(
-        "Error while parsing command line arguments: not enough arguments",
-      );
-      process.exit(-1);
-    }
-    const progname = path.basename(args[1]);
-    const rest = args.slice(2);
-
-    this.mainCommand.run(progname, [], rest, {});
-  }
-
-  subcommand<GN extends keyof any>(
-    argKey: GN,
-    name: string,
-    args: SubcommandArgs = {},
-  ): CommandGroup<GN, T> {
-    const cmd = this.mainCommand.subcommand(argKey, name as string, args);
-    return cmd as any;
-  }
-
-  requiredOption<N extends keyof any, V>(
-    name: N,
-    flagspec: string[],
-    conv: Converter<V>,
-    args: OptionArgs<V> = {},
-  ): Program<PN, T & SubRecord<PN, N, V>> {
-    this.mainCommand.requiredOption(name, flagspec, conv, args);
-    return this as any;
-  }
-
-  maybeOption<N extends keyof any, V>(
-    name: N,
-    flagspec: string[],
-    conv: Converter<V>,
-    args: OptionArgs<V> = {},
-  ): Program<PN, T & SubRecord<PN, N, V | undefined>> {
-    this.mainCommand.maybeOption(name, flagspec, conv, args);
-    return this as any;
-  }
-
-  /**
-   * Add a flag (option without value) to the program.
-   */
-  flag<N extends string>(
-    name: N,
-    flagspec: string[],
-    args: OptionArgs<boolean> = {},
-  ): Program<PN, T & SubRecord<PN, N, boolean>> {
-    this.mainCommand.flag(name, flagspec, args);
-    return this as any;
-  }
-
-  /**
-   * Add a required positional argument to the program.
-   */
-  requiredArgument<N extends keyof any, V>(
-    name: N,
-    conv: Converter<V>,
-    args: ArgumentArgs<V> = {},
-  ): Program<N, T & SubRecord<PN, N, V>> {
-    this.mainCommand.requiredArgument(name, conv, args);
-    return this as any;
-  }
-
-  /**
-   * Add an optional argument to the program.
-   */
-  maybeArgument<N extends keyof any, V>(
-    name: N,
-    conv: Converter<V>,
-    args: ArgumentArgs<V> = {},
-  ): Program<N, T & SubRecord<PN, N, V | undefined>> {
-    this.mainCommand.maybeArgument(name, conv, args);
-    return this as any;
-  }
-}
-
-export type GetArgType<T> = T extends Program<any, infer AT>
-  ? AT
-  : T extends CommandGroup<any, infer AT>
-  ? AT
-  : any;
-
-export function program<PN extends keyof any>(
-  argKey: PN,
-  args: ProgramArgs = {},
-): Program<PN, {}> {
-  return new Program(argKey as string, args);
-}
-
-export function prompt(question: string): Promise<string> {
-  const stdinReadline = readline.createInterface({
-    input: process.stdin,
-    output: process.stdout,
-  });
-  return new Promise<string>((resolve, reject) => {
-    stdinReadline.question(question, (res) => {
-      resolve(res);
-      stdinReadline.close();
-    });
-  });
-}
diff --git a/packages/taler-wallet-cli/src/index.ts 
b/packages/taler-wallet-cli/src/index.ts
index 5fd608f77..31e0b0f65 100644
--- a/packages/taler-wallet-cli/src/index.ts
+++ b/packages/taler-wallet-cli/src/index.ts
@@ -17,65 +17,60 @@
 /**
  * Imports.
  */
-import os from "os";
+import { deepStrictEqual } from "assert";
 import fs from "fs";
+import os from "os";
 import path from "path";
-import { deepStrictEqual } from "assert";
 // Polyfill for encoding which isn't present globally in older nodejs versions
-import { TextEncoder, TextDecoder } from "util";
-// @ts-ignore
-global.TextEncoder = TextEncoder;
-// @ts-ignore
-global.TextDecoder = TextDecoder;
-import * as clk from "./clk.js";
-import { getTestInfo, runTests } from "./integrationtests/testrunner.js";
 import {
-  PreparePayResultType,
-  setDangerousTimetravel,
-  classifyTalerUri,
-  TalerUriType,
-  RecoveryMergeStrategy,
-  Amounts,
   addPaytoQueryParams,
+  AgeRestriction,
+  Amounts,
+  classifyTalerUri,
+  clk,
   codecForList,
   codecForString,
-  Logger,
   Configuration,
   decodeCrock,
-  rsaBlind,
-  LogLevel,
-  setGlobalLogLevelFromString,
-  parsePaytoUri,
-  AgeRestriction,
-  getRandomBytes,
   encodeCrock,
+  getRandomBytes,
   j2s,
+  Logger,
+  parsePaytoUri,
+  PreparePayResultType,
+  RecoveryMergeStrategy,
+  rsaBlind,
+  setDangerousTimetravel,
+  setGlobalLogLevelFromString,
+  TalerUriType,
 } from "@gnu-taler/taler-util";
 import {
-  NodeHttpLib,
+  CryptoDispatcher,
   getDefaultNodeWallet,
-  NodeThreadCryptoWorkerFactory,
-  walletCoreDebugFlags,
-  WalletApiOperation,
-  WalletCoreApiClient,
-  Wallet,
   getErrorDetailFromException,
-  CryptoDispatcher,
-  SynchronousCryptoWorkerFactory,
   nativeCrypto,
-  performanceNow,
+  NodeHttpLib,
+  NodeThreadCryptoWorkerFactory,
   summarizeTalerErrorDetail,
+  SynchronousCryptoWorkerFactory,
+  Wallet,
+  WalletApiOperation,
+  WalletCoreApiClient,
+  walletCoreDebugFlags,
 } from "@gnu-taler/taler-wallet-core";
-import { lintExchangeDeployment } from "./lint.js";
+import type { TalerCryptoInterface } from 
"@gnu-taler/taler-wallet-core/src/crypto/cryptoImplementation";
+import { TextDecoder, TextEncoder } from "util";
 import { runBench1 } from "./bench1.js";
-import { runEnv1 } from "./env1.js";
-import { GlobalTestState, runTestWithState } from "./harness/harness.js";
 import { runBench2 } from "./bench2.js";
 import { runBench3 } from "./bench3.js";
-import {
-  TalerCryptoInterface,
-  TalerCryptoInterfaceR,
-} from "@gnu-taler/taler-wallet-core/src/crypto/cryptoImplementation";
+import { runEnv1 } from "./env1.js";
+import { GlobalTestState, runTestWithState } from "./harness/harness.js";
+import { getTestInfo, runTests } from "./integrationtests/testrunner.js";
+import { lintExchangeDeployment } from "./lint.js";
+// @ts-ignore
+global.TextEncoder = TextEncoder;
+// @ts-ignore
+global.TextDecoder = TextDecoder;
 
 // This module also serves as the entry point for the crypto
 // thread worker, and thus must expose these two handlers.
@@ -390,13 +385,10 @@ walletCli
     help: "Withdraw with a taler://withdraw/ URI",
   })
   .requiredArgument("uri", clk.STRING)
-  .maybeOption("restrictAge", ["--restrict-age"], clk.STRING)
+  .maybeOption("restrictAge", ["--restrict-age"], clk.INT)
   .action(async (args) => {
     const uri = args.withdraw.uri;
-    const restrictAge =
-      args.withdraw.restrictAge == null
-        ? undefined
-        : Number.parseInt(args.withdraw.restrictAge);
+    const restrictAge = args.withdraw.restrictAge;
     console.log(`age restriction requested (${restrictAge})`);
     await withWallet(args, async (wallet) => {
       const withdrawInfo = await wallet.client.call(

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]