diff --git a/vlib/builtin/js/builtin.js.v b/vlib/builtin/js/builtin.js.v index 99f451814c..a676acc19c 100644 --- a/vlib/builtin/js/builtin.js.v +++ b/vlib/builtin/js/builtin.js.v @@ -2,8 +2,11 @@ module builtin // used to generate JS throw statements. +[noreturn] pub fn js_throw(s any) { #throw s + + for {} } #let globalPrint; @@ -46,6 +49,7 @@ pub fn eprint(s string) { // Exits the process in node, and halts execution in the browser // because `process.exit` is undefined. Workaround for not having // a 'real' way to exit in the browser. +[noreturn] pub fn exit(c int) { JS.process.exit(c) js_throw('exit($c)') diff --git a/vlib/builtin/js/byte.js.v b/vlib/builtin/js/byte.js.v index c2bee28d0f..0a75772f10 100644 --- a/vlib/builtin/js/byte.js.v +++ b/vlib/builtin/js/byte.js.v @@ -68,3 +68,29 @@ pub fn (c byte) is_letter() bool { pub fn (c byte) is_alnum() bool { return c.is_letter() || c.is_digit() } + +// Define this on byte as well, so that we can do `s[0].is_capital()` +pub fn (c byte) is_capital() bool { + return c >= `A` && c <= `Z` +} + +// str_escaped returns the contents of `byte` as an escaped `string`. +// Example: assert byte(0).str_escaped() == r'`\0`' + +pub fn (b byte) str_escaped() string { + mut str := '' + match b { + 0 { str = r'`\0`' } + 7 { str = r'`\a`' } + 8 { str = r'`\b`' } + 9 { str = r'`\t`' } + 10 { str = r'`\n`' } + 11 { str = r'`\v`' } + 12 { str = r'`\f`' } + 13 { str = r'`\r`' } + 27 { str = r'`\e`' } + 32...126 { str = b.ascii_str() } + else { str = '0x' + b.hex() } + } + return str +} diff --git a/vlib/builtin/js/string.js.v b/vlib/builtin/js/string.js.v index d07bb5982e..126a4ca236 100644 --- a/vlib/builtin/js/string.js.v +++ b/vlib/builtin/js/string.js.v @@ -900,3 +900,13 @@ pub fn (s []string) join(sep string) string { // There's no better way to find length of JS String in bytes. #Object.defineProperty(string.prototype,"len", { get: function() {return new int(new TextEncoder().encode(this.str).length);}, set: function(l) {/* ignore */ } }); +// index returns the position of the first character of the input string. +// It will return `none` if the input string can't be found. +pub fn (s string) index(search string) ?int { + res := 0 + #res.val = s.str.indexOf(search) + if res == -1 { + return none + } + return res +} diff --git a/vlib/os/os.js.v b/vlib/os/os.js.v index c1641db3dd..87cf0e91f1 100644 --- a/vlib/os/os.js.v +++ b/vlib/os/os.js.v @@ -37,19 +37,36 @@ pub fn flush() { } } +pub fn getpid() int { + res := 0 + #res.val = $process.pid + + return res +} + // chmod change file access attributes of `path` to `mode`. // Octals like `0o600` can be used. -pub fn chmod(path string, mode int) { +pub fn chmod(path string, mode int) ? { $if js_node { + #try { #$fs.chmodSync(''+path,mode.valueOf()) + #} catch (error) { + #return error_with_code(new string("chmod failed: " + error.message),new int(error.code)) + #} + } $else { + return error('os.chmod() is available only for NodeJS') } } // chown changes the owner and group attributes of `path` to `owner` and `group`. // Octals like `0o600` can be used. -pub fn chown(path string, owner int, group int) { +pub fn chown(path string, owner int, group int) ? { $if js_node { + #try { #$fs.chownSync(''+path,owner.valueOf(),group.valueOf()) + #} catch (error) { return error_with_code(new string("chown failed: " + error.message),new int(error.code)) } + } $else { + return error('os.chown() is available only for NodeJS') } } @@ -89,7 +106,7 @@ pub fn execute(cmd string) Result { #let commands = cmd.str.split(' '); #let output = $child_process.spawnSync(commands[0],commands.slice(1,commands.length)); #exit_code = new int(output.status) - #stdout = newstring(output.stdout + '') + #stdout = new string(output.stdout + '') return Result{ exit_code: exit_code @@ -97,6 +114,14 @@ pub fn execute(cmd string) Result { } } +pub fn system(cmd string) int { + exit_code := 0 + #let commands = cmd.str.split(' '); + #exit_code.val = $child_process.execSync(commands[0],commands.slice(1,commands.length)); + + return exit_code +} + pub fn is_atty(fd int) int { res := 0 #res.val = +tty.isatty(fd.val) diff --git a/vlib/rand/rand.js.v b/vlib/rand/rand.js.v index ce4ea265c2..4171801be0 100644 --- a/vlib/rand/rand.js.v +++ b/vlib/rand/rand.js.v @@ -1,5 +1,7 @@ module rand +import time + // init initializes the default RNG. fn init() { default_rng = new_default() @@ -15,3 +17,51 @@ pub fn string(len int) string { return result } + +const ( + ulid_encoding = '0123456789ABCDEFGHJKMNPQRSTVWXYZ' +) + +// ulid generates an Unique Lexicographically sortable IDentifier. +// See https://github.com/ulid/spec . +// NB: ULIDs can leak timing information, if you make them public, because +// you can infer the rate at which some resource is being created, like +// users or business transactions. +// (https://news.ycombinator.com/item?id=14526173) +pub fn ulid() string { + return ulid_at_millisecond(u64(time.utc().unix_time_milli())) +} + +// ulid_at_millisecond does the same as `ulid` but takes a custom Unix millisecond timestamp via `unix_time_milli`. +pub fn ulid_at_millisecond(unix_time_milli u64) string { + mut buf := []byte{cap: 27} + mut t := unix_time_milli + mut i := 9 + for i >= 0 { + buf[i] = rand.ulid_encoding[int(t & 0x1f)] + t = t >> 5 + i-- + } + + mut x := default_rng.u64() + i = 10 + for i < 19 { + buf[i] = rand.ulid_encoding[int(x & 0x1f)] + + x = x >> 5 + i++ + } + + x = default_rng.u64() + for i < 26 { + buf[i] = rand.ulid_encoding[int(x & 0x1f)] + x = x >> 5 + i++ + } + + res := '' + println(buf) + #res.str = buf.arr.arr.map(String.fromCharCode).join('') + + return res +} diff --git a/vlib/v/pref/os.v b/vlib/v/pref/os.v index 578b00d00e..e546e54b30 100644 --- a/vlib/v/pref/os.v +++ b/vlib/v/pref/os.v @@ -112,5 +112,18 @@ pub fn get_host_os() OS { $if haiku { return .haiku } + $if js_node { + return .js_node + } + $if js_freestanding { + return .js_freestanding + } + + $if js_browser { + return .js_browser + } + $if js { + return .js_node + } panic('unknown host OS') } diff --git a/vlib/v/util/util.v b/vlib/v/util/util.v index 48980fdb25..fd918ab196 100644 --- a/vlib/v/util/util.v +++ b/vlib/v/util/util.v @@ -171,6 +171,9 @@ pub fn launch_tool(is_verbose bool, tool_name string, args []string) { } $if windows { exit(os.system('"$tool_exe" $tool_args')) + } $else $if js { + // no way to implement os.execvp in JS backend + exit(os.system('$tool_exe $tool_args')) } $else { os.execvp(tool_exe, args) or { panic(err) } }