diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b043ed45..68660155c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,32 +8,41 @@ - Non-exhaustive list of changes to help you fix your scripts: - `badusb`: - `setup()`: `mfr_name`, `prod_name`, `layout_path` parameters renamed to `mfrName`, `prodName`, `layoutPath` - - existing scripts using badusb will need to simply rename these + - effort required to update old scripts using badusb: very minimal - `dialog`: - removed, now replaced by `gui/dialog` and `gui/file_picker` (see below) - `event_loop`: - new module, allows timer functionality, callbacks and event-driven programming, used heavily alongside gpio and gui modules - `gpio`: - fully overhauled, now you `get()` pin instances and perform actions on them like `.init()` - - existing scripts using gpio will need some reworking + - now supports interrupts, callbacks and more cool things + - effort required to update old scripts using gpio: moderate - `gui`: - new module, fully overhauled, replaces dialog, keyboard, submenu, textbox modules - higher barrier to entry than older modules (requires usage of `event_loop` and `gui.viewDispatcher`), but much more flexible, powerful and easier to extend - includes all previously available js gui functionality (except `widget`), and also adds `gui/loading` and `gui/empty_screen` views - existing scripts using gui in any way will need a huge amount of reworking + - effort required to update old scripts using gui: extensive - `keyboard`: - removed, now replaced by `gui/text_input` and `gui/byte_input` (see above) - `storage`: - fully overhauled, now you `openFile()`s and perform actions on them like `.read()` - now supports many more operations including different open modes, directories and much more - `virtualInit()`, `virtualMount()`, `virtualQuit()` still work the same - - existing scripts using storage will need some reworking + - effort required to update old scripts using storage: moderate - `submenu`: - removed, now replaced by `gui/submenu` (see above) - `textbox`: - removed, now replace by `gui/text_box` (see above) - `widget`: - only gui functionality not ported to new gui module, remains unchanged for now but likely to be ported later on + - globals: + - `__filepath` and `__dirpath` renamed to `__filename` and `__dirname` like in nodejs + - `to_string()` renamed to `toString()`, now supports optional base parameter + - `to_hex_string()` removed, now use `toString(num, 16)` + - `parse_int()` renamed to `parseInt()`, now supports optional base parameter + - `to_upper_case()` and `to_lower_case()` renamed and moved to string class as `"".toUpperCase()` and `"".toLowerCase()` + - effort required to update old scripts using these: minimal - Added type definitions (typescript files for type checking in IDE, Flipper does not run typescript, and you code in javascript) - Documentation is incomplete and deprecated, from now on you should refer to type definitions (`applications/system/js_app/types`), those will always be correct - Type definitions for extra modules we have that OFW doesn't will come later diff --git a/applications/system/js_app/examples/apps/Scripts/Examples/load.js b/applications/system/js_app/examples/apps/Scripts/Examples/load.js index 3b8f2d8fd..82b2d2046 100644 --- a/applications/system/js_app/examples/apps/Scripts/Examples/load.js +++ b/applications/system/js_app/examples/apps/Scripts/Examples/load.js @@ -1,3 +1,3 @@ -let math = load(__dirpath + "/load_api.js"); +let math = load(__dirname + "/load_api.js"); let result = math.add(5, 10); print(result); diff --git a/applications/system/js_app/examples/apps/Scripts/Examples/path.js b/applications/system/js_app/examples/apps/Scripts/Examples/path.js index 1f50717a7..0be31b81d 100644 --- a/applications/system/js_app/examples/apps/Scripts/Examples/path.js +++ b/applications/system/js_app/examples/apps/Scripts/Examples/path.js @@ -1,8 +1,8 @@ let storage = require("storage"); -print("script has __dirpath of" + __dirpath); -print("script has __filepath of" + __filepath); -if (storage.fileExists(__dirpath + "/math.js")) { +print("script has __dirname of" + __dirname); +print("script has __filename of" + __filename); +if (storage.fileExists(__dirname + "/math.js")) { print("math.js exist here."); } else { print("math.js does not exist here."); diff --git a/applications/system/js_app/examples/apps/Scripts/Examples/stringutils.js b/applications/system/js_app/examples/apps/Scripts/Examples/stringutils.js index c1f4d447a..7c57f9bc5 100644 --- a/applications/system/js_app/examples/apps/Scripts/Examples/stringutils.js +++ b/applications/system/js_app/examples/apps/Scripts/Examples/stringutils.js @@ -12,8 +12,8 @@ let searchStr = "World"; let result2 = toString(sampleText.indexOf(searchStr)); print(result2); -let upperCaseText = "Text in upper case: " + toUpperCase(sampleText); +let upperCaseText = "Text in upper case: " + sampleText.toUpperCase(); print(upperCaseText); -let lowerCaseText = "Text in lower case: " + toLowerCase(sampleText); +let lowerCaseText = "Text in lower case: " + sampleText.toLowerCase(); print(lowerCaseText); diff --git a/applications/system/js_app/js_thread.c b/applications/system/js_app/js_thread.c index d26fe1fb0..31e9f721e 100644 --- a/applications/system/js_app/js_thread.c +++ b/applications/system/js_app/js_thread.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -206,87 +207,20 @@ static void js_global_to_string(struct mjs* mjs) { } static void js_parse_int(struct mjs* mjs) { - mjs_val_t arg = mjs_arg(mjs, 0); - if(!mjs_is_string(arg)) { - mjs_return(mjs, mjs_mk_number(mjs, 0)); - return; + const char* str; + int32_t base = 10; + if(mjs_nargs(mjs) == 1) { + JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&str)); + } else { + JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_STR(&str), JS_ARG_INT32(&base)); } - size_t str_len = 0; - const char* str = mjs_get_string(mjs, &arg, &str_len); - if((str_len == 0) || (str == NULL)) { - mjs_return(mjs, mjs_mk_number(mjs, 0)); - return; + int32_t num; + if(strint_to_int32(str, NULL, &num, base) != StrintParseNoError) { + num = 0; } - - int32_t num = 0; - int32_t sign = 1; - size_t i = 0; - - if(str[0] == '-') { - sign = -1; - i = 1; - } else if(str[0] == '+') { - i = 1; - } - - for(; i < str_len; i++) { - if(str[i] >= '0' && str[i] <= '9') { - num = num * 10 + (str[i] - '0'); - } else { - break; - } - } - num *= sign; - mjs_return(mjs, mjs_mk_number(mjs, num)); } -static void js_to_upper_case(struct mjs* mjs) { - mjs_val_t arg0 = mjs_arg(mjs, 0); - - size_t str_len; - const char* str = NULL; - if(mjs_is_string(arg0)) { - str = mjs_get_string(mjs, &arg0, &str_len); - } - if(!str) { - mjs_return(mjs, MJS_UNDEFINED); - return; - } - - char* upperStr = strdup(str); - for(size_t i = 0; i < str_len; i++) { - upperStr[i] = toupper(upperStr[i]); - } - - mjs_val_t resultStr = mjs_mk_string(mjs, upperStr, ~0, true); - free(upperStr); - mjs_return(mjs, resultStr); -} - -static void js_to_lower_case(struct mjs* mjs) { - mjs_val_t arg0 = mjs_arg(mjs, 0); - - size_t str_len; - const char* str = NULL; - if(mjs_is_string(arg0)) { - str = mjs_get_string(mjs, &arg0, &str_len); - } - if(!str) { - mjs_return(mjs, MJS_UNDEFINED); - return; - } - - char* lowerStr = strdup(str); - for(size_t i = 0; i < str_len; i++) { - lowerStr[i] = tolower(lowerStr[i]); - } - - mjs_val_t resultStr = mjs_mk_string(mjs, lowerStr, ~0, true); - free(lowerStr); - mjs_return(mjs, resultStr); -} - #ifdef JS_DEBUG static void js_dump_write_callback(void* ctx, const char* format, ...) { File* file = ctx; @@ -320,14 +254,14 @@ static int32_t js_thread(void* arg) { mjs_set( mjs, global, - "__filepath", + "__filename", ~0, mjs_mk_string( mjs, furi_string_get_cstr(worker->path), furi_string_size(worker->path), true)); mjs_set( mjs, global, - "__dirpath", + "__dirname", ~0, mjs_mk_string(mjs, furi_string_get_cstr(dirpath), furi_string_size(dirpath), true)); furi_string_free(dirpath); @@ -338,8 +272,6 @@ static int32_t js_thread(void* arg) { mjs_set(mjs, global, "ffi_address", ~0, MJS_MK_FN(js_ffi_address)); mjs_set(mjs, global, "require", ~0, MJS_MK_FN(js_require)); mjs_set(mjs, global, "parseInt", ~0, MJS_MK_FN(js_parse_int)); - mjs_set(mjs, global, "toUpperCase", ~0, MJS_MK_FN(js_to_upper_case)); - mjs_set(mjs, global, "toLowerCase", ~0, MJS_MK_FN(js_to_lower_case)); mjs_val_t console_obj = mjs_mk_object(mjs); mjs_set(mjs, console_obj, "log", ~0, MJS_MK_FN(js_console_log)); diff --git a/applications/system/js_app/types/global.d.ts b/applications/system/js_app/types/global.d.ts index 14e045a1e..052a2bb6a 100644 --- a/applications/system/js_app/types/global.d.ts +++ b/applications/system/js_app/types/global.d.ts @@ -14,37 +14,26 @@ declare function print(...args: any[]): void; /** * @brief Converts a number to a string * @param value The number to convert to a string - * @param base Integer base (`2`...`16`), default: 16 + * @param base Integer base (`2`...`16`), default: 10 */ declare function toString(value: number, base?: number): string; /** * @brief Converts a string to a number * @param text The string to convert to a number + * @param base Integer base (`2`...`16`), default: 10 */ -declare function parseInt(text: string): number; - -/** - * @brief Transforms a string to upper case - * @param text The string to transforms to upper case - */ -declare function toUpperCase(text: string): string; - -/** - * @brief Transforms a string to lower case - * @param text The string to transforms to lower case - */ -declare function toLowerCase(text: string): string; +declare function parseInt(text: string, base?: number): number; /** * @brief Path to the directory containing the current script */ -declare const __dirpath: string; +declare const __dirname: string; /** * @brief Path to the current script file */ -declare const __filepath: string; +declare const __filename: string; /** * @brief Reads a JS value from a file @@ -211,6 +200,14 @@ declare class String { * @param end The index to end substring at */ slice(start: number, end?: number): string; + /** + * @brief Return this string transformed to upper case + */ + toUpperCase(): string; + /** + * @brief Return this string transformed to lower case + */ + toLowerCase(): string; } declare class Boolean { } diff --git a/lib/mjs/mjs_exec.c b/lib/mjs/mjs_exec.c index 265e7d5c3..0213a871e 100644 --- a/lib/mjs/mjs_exec.c +++ b/lib/mjs/mjs_exec.c @@ -452,6 +452,12 @@ static int getprop_builtin_string( } else if(strcmp(name, "slice") == 0) { *res = mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_string_slice); return 1; + } else if(strcmp(name, "toUpperCase") == 0) { + *res = mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_string_to_upper_case); + return 1; + } else if(strcmp(name, "toLowerCase") == 0) { + *res = mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_string_to_lower_case); + return 1; } else if(isnum) { /* * string subscript: return a new one-byte string if the index diff --git a/lib/mjs/mjs_string.c b/lib/mjs/mjs_string.c index f74bf1074..f771ff4ea 100644 --- a/lib/mjs/mjs_string.c +++ b/lib/mjs/mjs_string.c @@ -286,6 +286,41 @@ MJS_PRIVATE mjs_val_t s_concat(struct mjs* mjs, mjs_val_t a, mjs_val_t b) { return res; } +MJS_PRIVATE void mjs_string_to_case(struct mjs* mjs, bool upper) { + mjs_val_t ret = MJS_UNDEFINED; + size_t size; + const char* s = NULL; + + /* get string from `this` */ + if(!mjs_check_arg(mjs, -1 /*this*/, "this", MJS_TYPE_STRING, NULL)) { + goto clean; + } + s = mjs_get_string(mjs, &mjs->vals.this_obj, &size); + + if(size == 0) { + ret = mjs_mk_string(mjs, "", 0, 1); + goto clean; + } + + char* tmp = malloc(size); + for(size_t i = 0; i < size; i++) { + tmp[i] = upper ? toupper(s[i]) : tolower(s[i]); + } + ret = mjs_mk_string(mjs, tmp, size, 1); + free(tmp); + +clean: + mjs_return(mjs, ret); +} + +MJS_PRIVATE void mjs_string_to_lower_case(struct mjs* mjs) { + mjs_string_to_case(mjs, false); +} + +MJS_PRIVATE void mjs_string_to_upper_case(struct mjs* mjs) { + mjs_string_to_case(mjs, true); +} + MJS_PRIVATE void mjs_string_slice(struct mjs* mjs) { int nargs = mjs_nargs(mjs); mjs_val_t ret = mjs_mk_number(mjs, 0); diff --git a/lib/mjs/mjs_string.h b/lib/mjs/mjs_string.h index ba6869b62..f0801f1a4 100644 --- a/lib/mjs/mjs_string.h +++ b/lib/mjs/mjs_string.h @@ -33,6 +33,8 @@ MJS_PRIVATE void embed_string( MJS_PRIVATE void mjs_mkstr(struct mjs* mjs); +MJS_PRIVATE void mjs_string_to_lower_case(struct mjs* mjs); +MJS_PRIVATE void mjs_string_to_upper_case(struct mjs* mjs); MJS_PRIVATE void mjs_string_slice(struct mjs* mjs); MJS_PRIVATE void mjs_string_index_of(struct mjs* mjs); MJS_PRIVATE void mjs_string_char_code_at(struct mjs* mjs);