Files

libs/thor.src
  • Thor = {}
  • Thor.init = function(class, root = true)
  • self.class = null
  • self.main = null
  • self.__commands = {}
  • self.commands = {}
  • self.root = root
  • if class.hasIndex("name") then self.name = class.name
  • self.class = class
  • if self.class.hasIndex("main") then self.main = self.to_command("main")
  • for obj in self.class
  • if typeof(obj["value"]) == "function" then
  • if obj["key"][:2] == "__" then
  • self.__commands[obj["key"]] = self.to_command(obj["key"])
  • else if obj["key"] != "main" then
  • self.commands[obj["key"]] = self.to_command(obj["key"])
  • end if
  • end if
  • end for
  • ThorCommand = {}
  • //print(self.main)
  • //print(self.__commands)
  • //print(self.commands)
  • ThorCommand.init = function(func, sig, name)
  • self.name = name
  • self.func = @func
  • if self.root == true then self.eval_command(self.main, params)
  • if sig.hasIndex("description") then self.description = sig["description"]
  • if sig.hasIndex("args") then
  • self.args = sig["args"]
  • end if
  • if sig.hasIndex("options") then
  • f = function(obj)
  • param = {}
  • param["name"] = obj.indexes[0]
  • param["description"] = obj[obj.indexes[0]]
  • return param
  • end function
  • self.options = Lst.map(sig["options"], @f)
  • end if
  • end function
  • ThorCommand.required_args = function()
  • f = function(obj)
  • return obj[-1:] == "*"
  • end function
  • // it takes a function name then returns an object with name, func key by default
  • // the description, options, [[required_args, optional args], [required_commands, optinal_commands]](if args is set) key is optional,
  • Thor.to_command = function(name)
  • command = {}
  • command["name"] = name
  • command["func"] = self.class[name]
  • if self.class.hasIndex(name + "_sig") then
  • sig = self.class[name + "_sig"]
  • else
  • return command
  • end if
  • if sig.hasIndex("description") then command["description"] = sig["description"]
  • arg_to_map = function(obj)
  • param = {}
  • if typeof(obj) == "list" then param["name"] = obj[0]
  • param["name"] = obj
  • //param["name"] = obj.indexes[0]
  • //param["description"] = obj[obj.indexes[0]]
  • return param
  • return Lst.select(self.args, @f)
  • end function
  • ThorCommand.optional_args = function()
  • f = function(obj)
  • return self.required_args.indexOf(obj) == null
  • end function
  • option_to_map = function(obj)
  • param = {}
  • param["name"] = obj.indexes[0]
  • param["description"] = obj[obj.indexes[0]]
  • return param
  • return Lst.select(self.args, @f)
  • end function
  • ThorCommand.options_list = function()
  • f = function(o)
  • return o.name
  • end function
  • return Lst.map(self.options, @f)
  • end function
  • // class divider ---------------------------------------
  • ThorManager = {}
  • ThorManager.init = function(thor)
  • self.thor = thor
  • end function
  • ThorManager.eval_command = function(command)
  • used_args = self.thor.global_args[:command.args.len]
  • self.thor.global_args = self.thor.global_args[command.args.len:]
  • if sig.hasIndex("args") then
  • sig["args"] = Lst.map(sig["args"], @arg_to_map)
  • required = function(obj)
  • return obj.name[-1:] == "*"
  • end function
  • command["args"] = sig["args"]
  • command["required_args"] = Lst.select(sig["args"], @required)
  • command["optional_args"] = Lst.reject(sig["args"], @required)
  • f = function(obj)
  • return typeof(obj.name) == "list" and obj.name.len == 2 and typeof(obj.name[1]) == "map"
  • end function
  • commands = Lst.select(sig["args"], @f)
  • required = function(obj)
  • return obj.name[0][-1:] == "*"
  • end function
  • command["required_commands"] = Lst.select(commands, @required)
  • command["optional_commands"] = Lst.reject(commands, @required)
  • f = function(obj)
  • sub_cli = new Thor
  • sub_cli.init(obj["name"][1], false)
  • obj["commands"] = sub_cli
  • obj["name"] = obj["name"][0]
  • return obj
  • end function
  • command["required_commands"] = Lst.map(command["required_commands"], @f)
  • command["optional_commands"] = Lst.map(command["optional_commands"], @f)
  • end if
  • self.thor.used_options = self.thor.used_options + Lst.flat(command.options_list)
  • if sig.hasIndex("options") then
  • sig["options"] = Lst.map(sig["options"], @option_to_map)
  • command["options"] = sig["options"]
  • end if
  • command["passed_options"] = self.options_by_key(command)
  • return command
  • end function
  • Thor.arg_allowed_commands = function(arg)
  • r = []
  • for i in arg["commands"].commands
  • r.push(i["key"])
  • end for
  • return r
  • self.thor.global_execution_queue.push(command)
  • end function
  • Thor.command_help = function(command)
  • out = char(10)
  • if self.root == true then
  • out = out + self.name
  • else
  • out = out + command["name"]
  • end if
  • out = out + " "
  • ThorManager.options_by_key = function(command)
  • r = {}
  • it_has_commands = false
  • get_value = function(o)
  • if o.indexOf("=") then
  • striped_options = self.thor.striped_global_options
  • if striped_options.indexOf(o) then
  • value = self.thor.global_options[striped_options.indexOf(o)]
  • return value[value.indexOf("=")+1:]
  • else
  • return null
  • end if
  • else
  • if self.thor.global_options.indexOf(i) != null then return true
  • return null
  • end if
  • end function
  • for arg in command["args"]
  • if arg.hasIndex("commands") then
  • out = out + "[" + arg["name"] + "] "
  • it_has_commands = true
  • for o in command.options_list
  • if typeof(o) == "list" then
  • v = null
  • for i in o
  • if get_value(i) != null then v = get_value(i)
  • end for
  • for i in o
  • r[i] = v
  • end for
  • else
  • out = out + "<" + arg["name"] + "> "
  • r[o] = get_value(o)
  • end if
  • end for
  • if command.hasIndex("options") then
  • out = out + char(10) + char(10)
  • out = out + "list of flags" + char(10)
  • for option in command.options
  • n = option.name
  • if typeof(option.name) == "list" then n = option.name.join(" ")
  • out = out + "<b>" + n + "</b> : " + option.description
  • if command.options.indexOf(option) < command.options.len - 1 then out = out + char(10)
  • end for
  • end if
  • return r
  • end function
  • if it_has_commands then
  • out = out + char(10)
  • for arg in command["args"]
  • if arg.hasIndex("commands") then
  • out = out + char(10)
  • out = out + "list of valid commands for [" + arg["name"] + "]" + char(10)
  • for command in arg["commands"].commands
  • out = out + "<b>" + command.value.name + "</b> : " + command.value.description + char(10)
  • end for
  • end if
  • end for
  • end if
  • // class divider ---------------------------------------
  • Thor = {}
  • Thor.init = function(class, main_func_name)
  • self.class = null
  • self.global_args = []
  • self.passed_args_count = 0
  • self.global_options = []
  • self.used_options = []
  • self.global_execution_queue = []
  • self.manager = new ThorManager
  • self.manager.init(self)
  • main_command = new ThorCommand
  • main_command.init(class[main_func_name], class[main_func_name+"_sig"], main_func_name)
  • self.params_to_args_options(params)
  • self.manager.eval_command(main_command)
  • self.catch_errors
  • end function
  • print(out)
  • Thor.striped_global_options = function()
  • f = function(ob)
  • if ob.indexOf("=") then
  • return ob[:ob.indexOf("=")+1]
  • end if
  • end function
  • return Lst.map(self.global_options, @f)
  • end function
  • // returns a list with [args, options] with args beign a list and options a map
  • // if -h or --help is passed it will ignore all the -- and - options and return options with -h and --help set
  • // if a options is passed and it is not defined on the command options sig then it will exit
  • // if a value options is passed with no value like -f= then it will exit
  • Thor.parse_params = function(command, params)
  • Thor.params_to_args_options = function(params)
  • // filter for args
  • f = function(p)
  • return p[0] == "-"
  • end function
  • args = Lst.reject(params, @f)
  • options = {}
  • if command.hasIndex("options") then
  • //command map
  • c_all_options = null
  • c_options = []
  • c_value_options = []
  • f = function(obj)
  • return obj["name"]
  • end function
  • c_all_options = Lst.map(command["options"], @f)
  • has_value = function(obj)
  • if typeof(obj) == "list" then
  • return obj[0].indexOf("=") != null
  • else
  • return obj.indexOf("=") != null
  • end if
  • end function
  • c_options = Lst.reject(c_all_options, @has_value)
  • c_value_options = Lst.select(c_all_options, @has_value)
  • // param map
  • f = function(param)
  • return param[:1] == "-" and param.indexOf("=") == null
  • end function
  • params_options = Lst.select(params, @f)
  • f = function(param)
  • if param[:2] != "--" and param.len > 2 then
  • r = []
  • for i in param[1:].values
  • r.push("-" + i)
  • end for
  • return r
  • else
  • return param
  • end if
  • end function
  • params_options = Lst.uniq(Lst.flat(Lst.map(params_options, @f)))
  • f = function(param)
  • return param[:1] == "-" and param.indexOf("=") != null
  • end function
  • params_value_options = Lst.select(params, @f)
  • //print(c_all_options)
  • //print(c_options)
  • //print(c_value_options)
  • //print(params_options)
  • //print(params_value_options)
  • // check for errors
  • // check if undefined options was passed
  • f = function(p)
  • return p[:p.indexOf("=") + 1]
  • end function
  • vo_without_value = Lst.map(params_value_options, @f)
  • all_options = vo_without_value + params_options
  • for i in all_options
  • if Lst.flat(c_all_options).indexOf(i) == null then
  • if i == "-h" or i == "--help" then
  • return [args, {"-h": true, "--help": true}]
  • else
  • exit("option " + i + " is not defined, check the manual")
  • end if
  • end if
  • end for
  • f = function(param)
  • return param[:1] == "-" and param.indexOf("=") == null
  • end function
  • params_options = Lst.select(params, @f)
  • // check if value options was passed without values
  • for i in params_value_options
  • if i[i.indexOf("=")+1:] == null then
  • exit("option " + i + " requires a value")
  • end if
  • end for
  • // set options to be passed for the command
  • c_options_by_key = {}
  • f = function(obj)
  • if typeof(obj) == "list" then
  • for i in obj
  • c_options_by_key[i] = obj
  • end for
  • else
  • c_options_by_key[obj] = [obj]
  • end if
  • end function
  • Lst.each(c_all_options, @f)
  • for i in params_options
  • for j in c_options_by_key[i]
  • options[j] = true
  • end for
  • end for
  • for i in params_value_options
  • value = i[i.indexOf("=")+1:]
  • key = i[:i.indexOf("=")+1]
  • for j in c_options_by_key[key]
  • options[j[:-1]] = value
  • f = function(param)
  • if param[:2] != "--" and param.len > 2 then
  • r = []
  • for i in param[1:].values
  • r.push("-" + i)
  • end for
  • end for
  • for i in Lst.flat(c_all_options)
  • if i.indexOf("=") then
  • key = i[:-1]
  • else
  • key = i
  • end if
  • if options.hasIndex(key) == false then
  • options[key] = null
  • end if
  • end for
  • end if
  • return [args, options]
  • return r
  • else
  • return param
  • end if
  • end function
  • params_options = Lst.uniq(Lst.flat(Lst.map(params_options, @f)))
  • f = function(param)
  • return param[:1] == "-" and param.indexOf("=") != null
  • end function
  • params_value_options = Lst.select(params, @f)
  • options = params_options + params_value_options
  • self.global_args = args
  • self.passed_args_count = args.len
  • self.global_options = options
  • end function
  • Thor.eval_command = function(command, params)
  • p = self.parse_params(command, params)
  • args = p[0]
  • options = p[1]
  • Thor.catch_errors = function()
  • f = function(c)
  • return c.required_args.len
  • end function
  • required_args = Lst.map(self.global_execution_queue, @f)
  • if options.hasIndex("--help") or options.hasIndex("-h") then
  • self.command_help(command)
  • return
  • if self.passed_args_count < required_args.sum then
  • print("error: required params not passed"+char(10))
  • end if
  • if command.hasIndex("required_args") and command.hasIndex("required_commands") then
  • required_args_size = command["required_commands"].len + command["required_args"].len
  • if args.len < required_args_size then
  • self.command_help(command)
  • return
  • end if
  • end if
  • f = function(obj)
  • if obj.hasIndex("commands") then
  • return Thor.arg_allowed_commands(obj)
  • else
  • return "*"
  • end if
  • end function
  • accepted_args = Lst.map(command["args"], @f)
  • for i in args.indexes
  • if accepted_args.hasIndex(i) == false then break
  • if typeof(accepted_args[i]) == "list" and accepted_args[i].indexOf(args[i]) == null then
  • exit(args[i] + " is not a valid command, please check the docs.")
  • end if
  • end for
  • // push nulls to args until it is the same len ans the optional + required args len
  • i = 0
  • while i < accepted_args.len - args.len
  • args.push(null)
  • i = i + 1
  • end while
  • // TODO exec shit here
  • print(args)
  • //print(accepted_args)
  • print(self.striped_global_options)
  • print(self.used_options)
  • end function
  • Thor.exec_queue = function()
  • end function
testCLI.src
  • Mycli = {}
  • Mycli.name = "mycli"
  • Mycli.commands = {}
  • // args ending with * are required
  • // options ending with = require a value to be passed after the option
  • Mycli.commands.hello_sig = {}
  • Mycli.commands.hello_sig["description"] = "it says hello to you"
  • Mycli.commands.hello_sig["args"] = ["name*", "second_name"]
  • Mycli.commands.hello_sig["options"] = [{["-c", "--capitalize"]: "will capitalize your name"}, {["-f=", "--from="]: "name from the person saying hello"}]
  • // options that are not passed will be set to null, also if they are passed all the keys will be set to the options value
  • // if the functions is called with --help or -h then it wont be called and the documentation will be printed istead
  • Mycli.commands.hello = function(args = [], options = {})
  • if options["-c"] then
  • name = name.values[0]
  • name[0].upper
  • name = name.join("")
  • end if
  • print(["hello", name, second_name].join(" "))
  • end function
  • Mycli.main_sig = {}
  • Mycli.main_sig["description"] = "shit cli script"
  • //required args should come first than optional ones
  • Mycli.main_sig["args"] = ["email*", ["commands*", Mycli.commands]]
  • Mycli.main_sig["options"] = [{"-d": "dez"}, {["-c", "--capitalize"]: "will capitalize your name"}, {["-f=", "--from="]: "name from the person saying hello"}]
  • // the main fuction is the root function of the cli script
  • // this function will allways be called if the the required args are passed(and they are valid)
  • // so in this case bc we have another class as args this function will be called first
  • // then the matching command will be called after
  • Mycli.main = function(args = [], options = {})
  • globals["email"] = email
  • end function
  • // functions starting with __ wont trigger the main function
  • Mycli.__version = function()
  • print("0.0.1")
  • end function
  • import_code("/home/me/thor/libs/listLib.src") //requires on listlib
  • import_code("/home/me/thor/libs/thor.src") //requires on listlib
  • Thor.init(Mycli)
greetings.src
  • Greetings = {}
  • Greetings.greetings_sig = {}
  • Greetings.greetings_sig["description"] = "shit cli script"
  • //required args should come first than optional ones
  • Greetings.greetings_sig["args"] = ["name*", "second_name"]
  • Greetings.greetings_sig["options"] = [{["-c", "--capitalize"]: "the names"}, {["-f=", "--from="]: "from name"}]
  • Greetings.greetings = function(args = [], options = {})
  • print("hellow")
  • end function
  • import_code("/home/me/Thorr/libs/listLib.src") //requires on listlib
  • import_code("/home/me/Thorr/libs/thor.src") //requires on listlib
  • Thor.init(Greetings, "greetings")