- Syntax sugar and convenience functions for JavaScript.
Example:
import src/nodejs/jsugar from std/jsffi import JsObject from std/sugar import `=>` doAssert generate2FAcode() is cint doAssert not uuid1validate("".cstring) doAssert not uuid4validate("".cstring) doAssert not uuid5validate("".cstring) doAssert uuid1validate("e64cb2a6-3ff6-11eb-b378-0242ac130002".cstring) doAssert uuid4validate("854fc25b-02f3-45cc-b521-516991b9bb99".cstring) doAssert nextDays() is seq[JsObject] doAssert pastDays() is seq[JsObject] discard sparkline([1.cint, 2, 3, 4, 5], minimum = 0.cint, maximum = 10.cint) iife: # (() => { echo "Hello Immediately Invoked Function Expressions" # })(); constant ::= "This is a JavaScript 'const'!.".cstring # const constant = "This is a JavaScript 'const'!."; proc example(argument0, argument1: int) {.codegenDecl: arrow.} = # const example = (argument0, argument1) => { echo "JavaScript Arrow Function for Nim functions" # } let example2 = (arg0, arg1: int) {.codegenDecl: arrow.} => echo "JavaScript Arrow Function for Nim Arrow Functions" # const example2 = (arg0, arg01) => { echo("JavaScript Arrow Function for Nim functions") }; doAssert nth(-9.cint) == "-9th".cstring doAssert nth(0.cint) == "0th".cstring doAssert nth(9.cint) == "9th".cstring doAssert nth(1.cint) == "1st".cstring doAssert nth(42.cint) == "42nd".cstring doAssert nth(420.cint) == "420th".cstring doAssert nth(666.cint) == "666th".cstring doAssert toRGB("c0ffee".cstring) == [192.cint, 255, 238] doAssert toHex([192.cint, 255, 238]) == "c0ffee".cstring doAssert removeAccents("ÇáéíóúýÁÉÍÓÚÝàèìòùÀÈÌÒÙãõñäëïöüÿÄËÏÖÜÃÕÑâêîôûÂÊÎÔ".cstring) == "CaeiouyAEIOUYaeiouAEIOUaonaeiouyAEIOUAONaeiouAEIO".cstring doAssert removeAccents("È,É,Ê,Ë,Û,Ù,Ï,Î,À,Â,Ô,è,é,ê,ë,û,ù,ï,î,à,â,ô,Ç,ç,Ã,ã,Õ,õ".cstring) == "E,E,E,E,U,U,I,I,A,A,O,e,e,e,e,u,u,i,i,a,a,o,C,c,A,a,O,o".cstring doAssert editDistanceAscii("Kitten".cstring, "Bitten".cstring) == 1.cint ## Levenshtein distance when off: jsexport constant, example, example2 # export { constant, example, example2 };
Consts
arrow = "const $2 = ($3) =>"
- Arrow Function for Nim functions, use {.codegenDecl: arrow.}.
maxValidDate = "8640000000000000"
- new Date(8640000000000001) "Invalid Date". (Same as Math.pow(10, 8) * 24 * 60 * 60 * 1000)
minValidDate = "-8640000000000000"
- new Date(-8640000000000001) "Invalid Date". (Same as -maxValidDate)
Procs
func anyToCstring(thing: auto): cstring {. importjs: "(new TextDecoder(\'utf-8\').decode(#))", ...raises: [], tags: [].}
- https://github.com/juancarlospaco/nodejs/issues/1#issuecomment-851956152
func currentTimestamp(): int {.importjs: """Math.floor(new Date().getTime() / 1000)""", ...raises: [], tags: [].}
func daysBetweenYears(fromYear, toYear: Positive): int {....raises: [], tags: [].}
-
Get the number of days between fromYear-01-01 and toYear-01-01.
Example:
doAssert daysBetweenYears(1970, 2020) == 18262 doAssert daysBetweenYears(2000, 2020) == 7305 doAssert daysBetweenYears(1970, 1970) == 0 doAssert daysBetweenYears(2020, 2020) == 0 doAssert daysBetweenYears(1999, 2000) == 365
func editDistanceAscii(a, b: cstring): cint {.importjs: """ (() => { const s0 = #; const s1 = #; if (s0 === s1) return 0; if (!s0 || !s1) return Math.max(s0.length, s1.length); var prevRow = new Array(s1.length + 1); for (var i = 0; i < prevRow.length; ++i) { prevRow[i] = i; } for (i = 0; i < s0.length; ++i) { var result = i + 1; for (var j = 0; j < s1.length; ++j) { var curCol = result; result = prevRow[j] + ( (s0.charAt(i) === s1.charAt(j)) ? 0 : 1 ); var tmp = curCol + 1; if (result > tmp) { result = tmp; } tmp = prevRow[j + 1] + 1; if (result > tmp) { result = tmp; } prevRow[j] = curCol; } prevRow[j] = result; } return result; })()""", ...raises: [], tags: [].}
- https://github.com/hiddentao/fast-levenshtein
func generate2FAcode(): cint {.importjs: "parseInt(Math.floor(Math.random() * 1000000).toString().padStart(6, \'0\'))", ...raises: [], tags: [].}
- Convenience func to generate a valid 2 Factor Authentication code integer.
func jsexport(symbols: auto) {.importjs: "export { @ }", varargs, ...raises: [], tags: [].}
- Convenience alias for export { symbol0, symbol1, symbol2 };
func nextDays(days = 7.cint): seq[JsObject] {.importjs: "[...Array(#).keys()].map(days => new Date(Date.now() + 86400000 * days))", ...raises: [], tags: [].}
- Convenience func to create an seq of the next days, inclusive.
func nth(someOrdinalInteger: cint): cstring {.importjs: """ (() => { const n = #; if (/^(string|number)$$/.test(typeof n) === false) { return n; } let suffixes = ['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th'], match = n.toString().match(/\d$$/), suffix; if (!match) { return n; } suffix = suffixes[match[0]]; if (/1[123]$$/.test(n)) { suffix = 'th'; } return n + suffix; })()""", ...raises: [], tags: [].}
- Convenience func to get string ordinal suffixes from integers ("1st", "2nd", "3rd", etc).
func pastDays(days = 7.cint): seq[JsObject] {.importjs: "[...Array(#).keys()].map(days => new Date(Date.now() - 86400000 * days))", ...raises: [], tags: [].}
- Convenience func to create an seq of the past days, inclusive.
func removeAccents(s: cstring): cstring {.importjs: """(# .replace(/[\xC0-\xC5]/g, "A").replace(/[\xC6]/g, "AE").replace(/[\xC7]/g, "C") .replace(/[\xC8-\xCB]/g, "E").replace(/[\xCC-\xCF]/g, "I").replace(/[\xD0]/g, "D") .replace(/[\xD1]/g, "N").replace(/[\xD2-\xD6\xD8]/g, "O").replace(/[\xD9-\xDC]/g, "U") .replace(/[\xDD]/g, "Y").replace(/[\xDE]/g, "P").replace(/[\xE0-\xE5]/g, "a") .replace(/[\xE6]/g, "ae").replace(/[\xE7]/g, "c").replace(/[\xE8-\xEB]/g, "e") .replace(/[\xEC-\xEF]/g, "i").replace(/[\xF1]/g, "n").replace(/[\xF2-\xF6\xF8]/g, "o") .replace(/[\xF9-\xFC]/g, "u").replace(/[\xFE]/g, "p").replace(/[\xFD\xFF]/g, "y"))""", ...raises: [], tags: [].}
- Convenience func to replace accented chars (Diacritics) with normal chars (ASCII).
func shuffle(arrai: openArray[auto]) {.importjs: """#.sort(() => .5 - Math.random())""", ...raises: [], tags: [].}
-
Example:
var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] shuffle(x) doAssert x != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
func sparkline(numbers: openArray[cint]; minimum: cint; maximum: cint): cstring {. asmNoStackFrame, ...raises: [], tags: [].}
- Convenience func to generate "Sparklines" loading spinners from numbers.
func suffixAmPm(s: SomeInteger): cstring {.importjs: """ ((h = Math.abs(#)) => `$${h % 12 === 0 ? 12 : h % 12}$${h < 12 ? 'am' : 'pm'}`)()""", ...raises: [], tags: [].}
-
Example:
doAssert suffixAmPm(0) == "12am".cstring doAssert suffixAmPm(5) == "5am".cstring doAssert suffixAmPm(12) == "12pm".cstring doAssert suffixAmPm(15) == "3pm".cstring doAssert suffixAmPm(23) == "11pm".cstring doAssert suffixAmPm(-23) == "11pm".cstring
func toHex(color: array[3, cint]): cstring {.importjs: """ (() => { const n = #; return ((n[2] | n[1] << 8 | n[0] << 16) | 1 << 24).toString(16).slice(1); })()""", ...raises: [], tags: [].}
- Convenience func to convert a RGB integer array to 6 digit Hexadecimal string.
func toRGB(color: cstring): array[3, cint] {.importjs: """ (() => { const n = parseInt(#, 16); return [n >> 16, n >> 8 & 255, n & 255] })()""", ...raises: [], tags: [].}
- Convenience func to convert a 6 digit Hexadecimal string value to an RGB integer array.
func uuid1validate(uuidv1: cstring): bool {.importjs: """ (() => { const UUID_RE1 = new RegExp("^[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$$", "i"); return UUID_RE1.test(#); })()""", ...raises: [], tags: [].}
- Convenience func to validate 1 UUID v1 string.
func uuid4validate(uuidv4: cstring): bool {.importjs: """ (() => { const UUID_RE4 = new RegExp("^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$$", "i"); return UUID_RE4.test(#); })()""", ...raises: [], tags: [].}
- Convenience func to validate 1 UUID v4 string.
func uuid5validate(uuidv5: cstring): bool {.importjs: """ (() => { const UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$$/i; return UUID_RE5.test(#); })()""", ...raises: [], tags: [].}
- Convenience func to validate 1 UUID v5 string.
Iterators
iterator backoff[T: SomeNumber](a, b: T; factor: T = 2): T
-
Exponential backoff
Example:
block: var example: seq[int] for i in backoff(1, 9): example.add i doAssert example == @[1, 2, 4, 8] block: var example: seq[float] for i in backoff(1.0, 9.9): example.add i doAssert example == @[1.0, 2.0, 4.0, 8.0]
Templates
template `::=`(name: untyped; value: auto): untyped
- Convenience template for a JavaScript const (Nim var). Other libs already use := then we use ::=, because :== looks like a comparison.
template iife(code: untyped): untyped
- Convenience template for Anonymous Immediately Invoked Function Expressions.