mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-21 20:13:07 +00:00
[FL-3918] Full-fledged JS SDK + npm packages (#3963)
* feat: js sdk * refactor: move js back where it belongs * docs: generate docs using typedoc * feat: sdk versioning scheme * ci: silence pvs warning * docs: bring back old incomplete js docs * style: readAnalog naming * fix: rename script compatibility screens Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
parent
e4c8270824
commit
85e5642b2a
62 changed files with 3150 additions and 419 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -63,4 +63,7 @@ PVS-Studio.log
|
|||
|
||||
.gdbinit
|
||||
|
||||
/fbt_options_local.py
|
||||
/fbt_options_local.py
|
||||
|
||||
# JS packages
|
||||
node_modules/
|
||||
|
|
|
@ -1,4 +1,15 @@
|
|||
let tests = require("tests");
|
||||
let flipper = require("flipper");
|
||||
|
||||
tests.assert_eq(1337, 1337);
|
||||
tests.assert_eq("hello", "hello");
|
||||
|
||||
tests.assert_eq("compatible", sdkCompatibilityStatus(0, 1));
|
||||
tests.assert_eq("firmwareTooOld", sdkCompatibilityStatus(100500, 0));
|
||||
tests.assert_eq("firmwareTooNew", sdkCompatibilityStatus(-100500, 0));
|
||||
tests.assert_eq(true, doesSdkSupport(["baseline"]));
|
||||
tests.assert_eq(false, doesSdkSupport(["abobus", "other-nonexistent-feature"]));
|
||||
|
||||
tests.assert_eq("flipperdevices", flipper.firmwareVendor);
|
||||
tests.assert_eq(0, flipper.jsSdkVersion[0]);
|
||||
tests.assert_eq(1, flipper.jsSdkVersion[1]);
|
||||
|
|
|
@ -5,7 +5,6 @@ App(
|
|||
provides=[
|
||||
"updater_app",
|
||||
"js_app",
|
||||
"js_app_start",
|
||||
# "archive",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -6,6 +6,16 @@ App(
|
|||
stack_size=2 * 1024,
|
||||
resources="examples",
|
||||
order=0,
|
||||
provides=["js_app_start"],
|
||||
sources=[
|
||||
"js_app.c",
|
||||
"js_modules.c",
|
||||
"js_thread.c",
|
||||
"plugin_api/app_api_table.cpp",
|
||||
"views/console_view.c",
|
||||
"modules/js_flipper.c",
|
||||
"modules/js_tests.c",
|
||||
],
|
||||
)
|
||||
|
||||
App(
|
||||
|
@ -13,6 +23,7 @@ App(
|
|||
apptype=FlipperAppType.STARTUP,
|
||||
entry_point="js_app_on_system_start",
|
||||
order=160,
|
||||
sources=["js_app.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
|
|
|
@ -19,7 +19,7 @@ eventLoop.subscribe(eventLoop.timer("periodic", 1000), function (_, _item, led,
|
|||
// read potentiometer when button is pressed
|
||||
print("Press the button (PC1)");
|
||||
eventLoop.subscribe(button.interrupt(), function (_, _item, pot) {
|
||||
print("PC0 is at", pot.read_analog(), "mV");
|
||||
print("PC0 is at", pot.readAnalog(), "mV");
|
||||
}, pot);
|
||||
|
||||
// the program will just exit unless this is here
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include <core/common_defines.h>
|
||||
#include "js_modules.h"
|
||||
#include <m-array.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <assets_icons.h>
|
||||
|
||||
#include "modules/js_flipper.h"
|
||||
#ifdef FW_CFG_unit_tests
|
||||
|
@ -76,6 +78,12 @@ JsModuleData* js_find_loaded_module(JsModules* instance, const char* name) {
|
|||
}
|
||||
|
||||
mjs_val_t js_module_require(JsModules* modules, const char* name, size_t name_len) {
|
||||
// Ignore the initial part of the module name
|
||||
const char* optional_module_prefix = "@" JS_SDK_VENDOR "/fz-sdk/";
|
||||
if(strncmp(name, optional_module_prefix, strlen(optional_module_prefix)) == 0) {
|
||||
name += strlen(optional_module_prefix);
|
||||
}
|
||||
|
||||
// Check if module is already installed
|
||||
JsModuleData* module_inst = js_find_loaded_module(modules, name);
|
||||
if(module_inst) { //-V547
|
||||
|
@ -175,3 +183,133 @@ void* js_module_get(JsModules* modules, const char* name) {
|
|||
furi_string_free(module_name);
|
||||
return module_inst ? module_inst->context : NULL;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
JsSdkCompatStatusCompatible,
|
||||
JsSdkCompatStatusFirmwareTooOld,
|
||||
JsSdkCompatStatusFirmwareTooNew,
|
||||
} JsSdkCompatStatus;
|
||||
|
||||
/**
|
||||
* @brief Checks compatibility between the firmware and the JS SDK version
|
||||
* expected by the script
|
||||
*/
|
||||
static JsSdkCompatStatus
|
||||
js_internal_sdk_compatibility_status(int32_t exp_major, int32_t exp_minor) {
|
||||
if(exp_major < JS_SDK_MAJOR) return JsSdkCompatStatusFirmwareTooNew;
|
||||
if(exp_major > JS_SDK_MAJOR || exp_minor > JS_SDK_MINOR)
|
||||
return JsSdkCompatStatusFirmwareTooOld;
|
||||
return JsSdkCompatStatusCompatible;
|
||||
}
|
||||
|
||||
#define JS_SDK_COMPAT_ARGS \
|
||||
int32_t major, minor; \
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_INT32(&major), JS_ARG_INT32(&minor));
|
||||
|
||||
void js_sdk_compatibility_status(struct mjs* mjs) {
|
||||
JS_SDK_COMPAT_ARGS;
|
||||
JsSdkCompatStatus status = js_internal_sdk_compatibility_status(major, minor);
|
||||
switch(status) {
|
||||
case JsSdkCompatStatusCompatible:
|
||||
mjs_return(mjs, mjs_mk_string(mjs, "compatible", ~0, 0));
|
||||
return;
|
||||
case JsSdkCompatStatusFirmwareTooOld:
|
||||
mjs_return(mjs, mjs_mk_string(mjs, "firmwareTooOld", ~0, 0));
|
||||
return;
|
||||
case JsSdkCompatStatusFirmwareTooNew:
|
||||
mjs_return(mjs, mjs_mk_string(mjs, "firmwareTooNew", ~0, 0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void js_is_sdk_compatible(struct mjs* mjs) {
|
||||
JS_SDK_COMPAT_ARGS;
|
||||
JsSdkCompatStatus status = js_internal_sdk_compatibility_status(major, minor);
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, status == JsSdkCompatStatusCompatible));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Asks the user whether to continue executing an incompatible script
|
||||
*/
|
||||
static bool js_internal_compat_ask_user(const char* message) {
|
||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
DialogMessage* dialog = dialog_message_alloc();
|
||||
dialog_message_set_header(dialog, message, 64, 0, AlignCenter, AlignTop);
|
||||
dialog_message_set_text(
|
||||
dialog, "This script may not\nwork as expected", 79, 32, AlignCenter, AlignCenter);
|
||||
dialog_message_set_icon(dialog, &I_Warning_30x23, 0, 18);
|
||||
dialog_message_set_buttons(dialog, "Go back", NULL, "Run anyway");
|
||||
DialogMessageButton choice = dialog_message_show(dialogs, dialog);
|
||||
dialog_message_free(dialog);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
return choice == DialogMessageButtonRight;
|
||||
}
|
||||
|
||||
void js_check_sdk_compatibility(struct mjs* mjs) {
|
||||
JS_SDK_COMPAT_ARGS;
|
||||
JsSdkCompatStatus status = js_internal_sdk_compatibility_status(major, minor);
|
||||
if(status != JsSdkCompatStatusCompatible) {
|
||||
FURI_LOG_E(
|
||||
TAG,
|
||||
"Script requests JS SDK %ld.%ld, firmware provides JS SDK %d.%d",
|
||||
major,
|
||||
minor,
|
||||
JS_SDK_MAJOR,
|
||||
JS_SDK_MINOR);
|
||||
|
||||
const char* message = (status == JsSdkCompatStatusFirmwareTooOld) ? "Outdated Firmware" :
|
||||
"Outdated Script";
|
||||
if(!js_internal_compat_ask_user(message)) {
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_NOT_IMPLEMENTED_ERROR, "Incompatible script");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char* extra_features[] = {
|
||||
"baseline", // dummy "feature"
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Determines whether a feature is supported
|
||||
*/
|
||||
static bool js_internal_supports(const char* feature) {
|
||||
for(size_t i = 0; i < COUNT_OF(extra_features); i++) { // -V1008
|
||||
if(strcmp(feature, extra_features[i]) == 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines whether all of the requested features are supported
|
||||
*/
|
||||
static bool js_internal_supports_all_of(struct mjs* mjs, mjs_val_t feature_arr) {
|
||||
furi_assert(mjs_is_array(feature_arr));
|
||||
|
||||
for(size_t i = 0; i < mjs_array_length(mjs, feature_arr); i++) {
|
||||
mjs_val_t feature = mjs_array_get(mjs, feature_arr, i);
|
||||
const char* feature_str = mjs_get_string(mjs, &feature, NULL);
|
||||
if(!feature_str) return false;
|
||||
|
||||
if(!js_internal_supports(feature_str)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void js_does_sdk_support(struct mjs* mjs) {
|
||||
mjs_val_t features;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_ARR(&features));
|
||||
mjs_return(mjs, mjs_mk_boolean(mjs, js_internal_supports_all_of(mjs, features)));
|
||||
}
|
||||
|
||||
void js_check_sdk_features(struct mjs* mjs) {
|
||||
mjs_val_t features;
|
||||
JS_FETCH_ARGS_OR_RETURN(mjs, JS_EXACTLY, JS_ARG_ARR(&features));
|
||||
if(!js_internal_supports_all_of(mjs, features)) {
|
||||
FURI_LOG_E(TAG, "Script requests unsupported features");
|
||||
|
||||
if(!js_internal_compat_ask_user("Unsupported Feature")) {
|
||||
JS_ERROR_AND_RETURN(mjs, MJS_NOT_IMPLEMENTED_ERROR, "Incompatible script");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
#define PLUGIN_APP_ID "js"
|
||||
#define PLUGIN_API_VERSION 1
|
||||
|
||||
#define JS_SDK_VENDOR "flipperdevices"
|
||||
#define JS_SDK_MAJOR 0
|
||||
#define JS_SDK_MINOR 1
|
||||
|
||||
/**
|
||||
* @brief Returns the foreign pointer in `obj["_"]`
|
||||
*/
|
||||
|
@ -275,3 +279,28 @@ mjs_val_t js_module_require(JsModules* modules, const char* name, size_t name_le
|
|||
* @returns Pointer to module context, NULL if the module is not instantiated
|
||||
*/
|
||||
void* js_module_get(JsModules* modules, const char* name);
|
||||
|
||||
/**
|
||||
* @brief `sdkCompatibilityStatus` function
|
||||
*/
|
||||
void js_sdk_compatibility_status(struct mjs* mjs);
|
||||
|
||||
/**
|
||||
* @brief `isSdkCompatible` function
|
||||
*/
|
||||
void js_is_sdk_compatible(struct mjs* mjs);
|
||||
|
||||
/**
|
||||
* @brief `checkSdkCompatibility` function
|
||||
*/
|
||||
void js_check_sdk_compatibility(struct mjs* mjs);
|
||||
|
||||
/**
|
||||
* @brief `doesSdkSupport` function
|
||||
*/
|
||||
void js_does_sdk_support(struct mjs* mjs);
|
||||
|
||||
/**
|
||||
* @brief `checkSdkFeatures` function
|
||||
*/
|
||||
void js_check_sdk_features(struct mjs* mjs);
|
||||
|
|
|
@ -231,18 +231,29 @@ static int32_t js_thread(void* arg) {
|
|||
struct mjs* mjs = mjs_create(worker);
|
||||
worker->modules = js_modules_create(mjs, worker->resolver);
|
||||
mjs_val_t global = mjs_get_global(mjs);
|
||||
mjs_set(mjs, global, "print", ~0, MJS_MK_FN(js_print));
|
||||
mjs_set(mjs, global, "delay", ~0, MJS_MK_FN(js_delay));
|
||||
mjs_set(mjs, global, "toString", ~0, MJS_MK_FN(js_global_to_string));
|
||||
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_val_t console_obj = mjs_mk_object(mjs);
|
||||
mjs_set(mjs, console_obj, "log", ~0, MJS_MK_FN(js_console_log));
|
||||
mjs_set(mjs, console_obj, "warn", ~0, MJS_MK_FN(js_console_warn));
|
||||
mjs_set(mjs, console_obj, "error", ~0, MJS_MK_FN(js_console_error));
|
||||
mjs_set(mjs, console_obj, "debug", ~0, MJS_MK_FN(js_console_debug));
|
||||
mjs_set(mjs, global, "console", ~0, console_obj);
|
||||
|
||||
JS_ASSIGN_MULTI(mjs, global) {
|
||||
JS_FIELD("print", MJS_MK_FN(js_print));
|
||||
JS_FIELD("delay", MJS_MK_FN(js_delay));
|
||||
JS_FIELD("toString", MJS_MK_FN(js_global_to_string));
|
||||
JS_FIELD("ffi_address", MJS_MK_FN(js_ffi_address));
|
||||
JS_FIELD("require", MJS_MK_FN(js_require));
|
||||
JS_FIELD("console", console_obj);
|
||||
|
||||
JS_FIELD("sdkCompatibilityStatus", MJS_MK_FN(js_sdk_compatibility_status));
|
||||
JS_FIELD("isSdkCompatible", MJS_MK_FN(js_is_sdk_compatible));
|
||||
JS_FIELD("checkSdkCompatibility", MJS_MK_FN(js_check_sdk_compatibility));
|
||||
JS_FIELD("doesSdkSupport", MJS_MK_FN(js_does_sdk_support));
|
||||
JS_FIELD("checkSdkFeatures", MJS_MK_FN(js_check_sdk_features));
|
||||
}
|
||||
|
||||
JS_ASSIGN_MULTI(mjs, console_obj) {
|
||||
JS_FIELD("log", MJS_MK_FN(js_console_log));
|
||||
JS_FIELD("warn", MJS_MK_FN(js_console_warn));
|
||||
JS_FIELD("error", MJS_MK_FN(js_console_error));
|
||||
JS_FIELD("debug", MJS_MK_FN(js_console_debug));
|
||||
}
|
||||
|
||||
mjs_set_ffi_resolver(mjs, js_dlsym, worker->resolver);
|
||||
|
||||
|
|
|
@ -27,11 +27,19 @@ static void js_flipper_get_battery(struct mjs* mjs) {
|
|||
|
||||
void* js_flipper_create(struct mjs* mjs, mjs_val_t* object, JsModules* modules) {
|
||||
UNUSED(modules);
|
||||
mjs_val_t sdk_vsn = mjs_mk_array(mjs);
|
||||
mjs_array_push(mjs, sdk_vsn, mjs_mk_number(mjs, JS_SDK_MAJOR));
|
||||
mjs_array_push(mjs, sdk_vsn, mjs_mk_number(mjs, JS_SDK_MINOR));
|
||||
|
||||
mjs_val_t flipper_obj = mjs_mk_object(mjs);
|
||||
mjs_set(mjs, flipper_obj, "getModel", ~0, MJS_MK_FN(js_flipper_get_model));
|
||||
mjs_set(mjs, flipper_obj, "getName", ~0, MJS_MK_FN(js_flipper_get_name));
|
||||
mjs_set(mjs, flipper_obj, "getBatteryCharge", ~0, MJS_MK_FN(js_flipper_get_battery));
|
||||
*object = flipper_obj;
|
||||
JS_ASSIGN_MULTI(mjs, flipper_obj) {
|
||||
JS_FIELD("getModel", MJS_MK_FN(js_flipper_get_model));
|
||||
JS_FIELD("getName", MJS_MK_FN(js_flipper_get_name));
|
||||
JS_FIELD("getBatteryCharge", MJS_MK_FN(js_flipper_get_battery));
|
||||
JS_FIELD("firmwareVendor", mjs_mk_string(mjs, JS_SDK_VENDOR, ~0, false));
|
||||
JS_FIELD("jsSdkVersion", sdk_vsn);
|
||||
}
|
||||
|
||||
return (void*)1;
|
||||
}
|
||||
|
|
|
@ -220,7 +220,7 @@ static void js_gpio_interrupt(struct mjs* mjs) {
|
|||
* let gpio = require("gpio");
|
||||
* let pot = gpio.get("pc0");
|
||||
* pot.init({ direction: "in", inMode: "analog" });
|
||||
* print("voltage:" pot.read_analog(), "mV");
|
||||
* print("voltage:" pot.readAnalog(), "mV");
|
||||
* ```
|
||||
*/
|
||||
static void js_gpio_read_analog(struct mjs* mjs) {
|
||||
|
@ -274,7 +274,7 @@ static void js_gpio_get(struct mjs* mjs) {
|
|||
mjs_set(mjs, manager, "init", ~0, MJS_MK_FN(js_gpio_init));
|
||||
mjs_set(mjs, manager, "write", ~0, MJS_MK_FN(js_gpio_write));
|
||||
mjs_set(mjs, manager, "read", ~0, MJS_MK_FN(js_gpio_read));
|
||||
mjs_set(mjs, manager, "read_analog", ~0, MJS_MK_FN(js_gpio_read_analog));
|
||||
mjs_set(mjs, manager, "readAnalog", ~0, MJS_MK_FN(js_gpio_read_analog));
|
||||
mjs_set(mjs, manager, "interrupt", ~0, MJS_MK_FN(js_gpio_interrupt));
|
||||
mjs_return(mjs, manager);
|
||||
|
||||
|
|
20
applications/system/js_app/packages/create-fz-app/README.md
Normal file
20
applications/system/js_app/packages/create-fz-app/README.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Flipper Zero JavaScript SDK Wizard
|
||||
This package contains an interactive wizard that lets you scaffold a JavaScript
|
||||
application for Flipper Zero.
|
||||
|
||||
## Getting started
|
||||
Create your application using the interactive wizard:
|
||||
```shell
|
||||
npx @flipperdevices/create-fz-app@latest
|
||||
```
|
||||
|
||||
Then, enter the directory with your application and launch it:
|
||||
```shell
|
||||
cd my-flip-app
|
||||
npm start
|
||||
```
|
||||
|
||||
You are free to use `pnpm` or `yarn` instead of `npm`.
|
||||
|
||||
## Documentation
|
||||
Check out the [JavaScript section in the Developer Documentation](https://developer.flipper.net/flipperzero/doxygen/js.html)
|
68
applications/system/js_app/packages/create-fz-app/index.js
Executable file
68
applications/system/js_app/packages/create-fz-app/index.js
Executable file
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/env node
|
||||
import prompts from "prompts";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { replaceInFileSync } from "replace-in-file";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
(async () => {
|
||||
const { name, pkgManager, confirm } = await prompts([
|
||||
{
|
||||
type: "text",
|
||||
name: "name",
|
||||
message: "What is the name of your project?",
|
||||
initial: "my-flip-app"
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
name: "pkgManager",
|
||||
message: "What package manager should your project use?",
|
||||
choices: [
|
||||
{ title: "npm", value: "npm" },
|
||||
{ title: "pnpm", value: "pnpm" },
|
||||
{ title: "yarn", value: "yarn" },
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "confirm",
|
||||
name: "confirm",
|
||||
message: "Create project?",
|
||||
initial: true,
|
||||
},
|
||||
]);
|
||||
|
||||
if (!confirm)
|
||||
return;
|
||||
|
||||
if (fs.existsSync(name)) {
|
||||
const { replace } = await prompts([
|
||||
{
|
||||
type: "confirm",
|
||||
name: "replace",
|
||||
message: `File or directory \`${name}\` already exists. Continue anyway?`,
|
||||
initial: false,
|
||||
},
|
||||
]);
|
||||
if (!replace)
|
||||
return;
|
||||
}
|
||||
|
||||
fs.rmSync(name, { recursive: true, force: true });
|
||||
|
||||
console.log("Copying files...");
|
||||
fs.cpSync(path.resolve(__dirname, "template"), name, { recursive: true });
|
||||
replaceInFileSync({ files: `${name}/**/*`, from: /<app_name>/g, to: name });
|
||||
|
||||
console.log("Installing packages...");
|
||||
spawnSync("bash", ["-c", `cd ${name} && ${pkgManager} install`], {
|
||||
cwd: process.cwd(),
|
||||
detached: true,
|
||||
stdio: "inherit",
|
||||
});
|
||||
|
||||
console.log(`Done! Created ${name}. Run \`cd ${name} && ${pkgManager} start\` to run it on your Flipper.`);
|
||||
})();
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "@flipperdevices/create-fz-app",
|
||||
"version": "0.1.0",
|
||||
"description": "Template package for JS apps Flipper Zero",
|
||||
"bin": "index.js",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"flipper",
|
||||
"flipper zero"
|
||||
],
|
||||
"author": "Flipper Devices",
|
||||
"license": "GPL-3.0-only",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/flipperdevices/flipperzero-firmware.git",
|
||||
"directory": "applications/system/js_app/packages/create-fz-app"
|
||||
},
|
||||
"dependencies": {
|
||||
"prompts": "^2.4.2",
|
||||
"replace-in-file": "^8.2.0"
|
||||
}
|
||||
}
|
373
applications/system/js_app/packages/create-fz-app/pnpm-lock.yaml
Normal file
373
applications/system/js_app/packages/create-fz-app/pnpm-lock.yaml
Normal file
|
@ -0,0 +1,373 @@
|
|||
lockfileVersion: '9.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
prompts:
|
||||
specifier: ^2.4.2
|
||||
version: 2.4.2
|
||||
replace-in-file:
|
||||
specifier: ^8.2.0
|
||||
version: 8.2.0
|
||||
|
||||
packages:
|
||||
|
||||
'@isaacs/cliui@8.0.2':
|
||||
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
ansi-regex@5.0.1:
|
||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
ansi-regex@6.1.0:
|
||||
resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
ansi-styles@4.3.0:
|
||||
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
ansi-styles@6.2.1:
|
||||
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
balanced-match@1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
|
||||
brace-expansion@2.0.1:
|
||||
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
|
||||
|
||||
chalk@5.3.0:
|
||||
resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
|
||||
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
|
||||
|
||||
cliui@8.0.1:
|
||||
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
color-convert@2.0.1:
|
||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||
engines: {node: '>=7.0.0'}
|
||||
|
||||
color-name@1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
|
||||
cross-spawn@7.0.3:
|
||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
eastasianwidth@0.2.0:
|
||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
|
||||
emoji-regex@8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
|
||||
emoji-regex@9.2.2:
|
||||
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
|
||||
|
||||
escalade@3.2.0:
|
||||
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
foreground-child@3.3.0:
|
||||
resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
get-caller-file@2.0.5:
|
||||
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
||||
engines: {node: 6.* || 8.* || >= 10.*}
|
||||
|
||||
glob@10.4.5:
|
||||
resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
|
||||
hasBin: true
|
||||
|
||||
is-fullwidth-code-point@3.0.0:
|
||||
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
isexe@2.0.0:
|
||||
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||
|
||||
jackspeak@3.4.3:
|
||||
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
|
||||
|
||||
kleur@3.0.3:
|
||||
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
lru-cache@10.4.3:
|
||||
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
|
||||
|
||||
minimatch@9.0.5:
|
||||
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
minipass@7.1.2:
|
||||
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
package-json-from-dist@1.0.1:
|
||||
resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
|
||||
|
||||
path-key@3.1.1:
|
||||
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
path-scurry@1.11.1:
|
||||
resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
|
||||
engines: {node: '>=16 || 14 >=14.18'}
|
||||
|
||||
prompts@2.4.2:
|
||||
resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
replace-in-file@8.2.0:
|
||||
resolution: {integrity: sha512-hMsQtdYHwWviQT5ZbNsgfu0WuCiNlcUSnnD+aHAL081kbU9dPkPocDaHlDvAHKydTWWpx1apfcEcmvIyQk3CpQ==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
require-directory@2.1.1:
|
||||
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
shebang-regex@3.0.0:
|
||||
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
signal-exit@4.1.0:
|
||||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
sisteransi@1.0.5:
|
||||
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
|
||||
|
||||
string-width@4.2.3:
|
||||
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
string-width@5.1.2:
|
||||
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
strip-ansi@6.0.1:
|
||||
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
strip-ansi@7.1.0:
|
||||
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
which@2.0.2:
|
||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||
engines: {node: '>= 8'}
|
||||
hasBin: true
|
||||
|
||||
wrap-ansi@7.0.0:
|
||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
wrap-ansi@8.1.0:
|
||||
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
y18n@5.0.8:
|
||||
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
yargs-parser@21.1.1:
|
||||
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
yargs@17.7.2:
|
||||
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
snapshots:
|
||||
|
||||
'@isaacs/cliui@8.0.2':
|
||||
dependencies:
|
||||
string-width: 5.1.2
|
||||
string-width-cjs: string-width@4.2.3
|
||||
strip-ansi: 7.1.0
|
||||
strip-ansi-cjs: strip-ansi@6.0.1
|
||||
wrap-ansi: 8.1.0
|
||||
wrap-ansi-cjs: wrap-ansi@7.0.0
|
||||
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
optional: true
|
||||
|
||||
ansi-regex@5.0.1: {}
|
||||
|
||||
ansi-regex@6.1.0: {}
|
||||
|
||||
ansi-styles@4.3.0:
|
||||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
|
||||
ansi-styles@6.2.1: {}
|
||||
|
||||
balanced-match@1.0.2: {}
|
||||
|
||||
brace-expansion@2.0.1:
|
||||
dependencies:
|
||||
balanced-match: 1.0.2
|
||||
|
||||
chalk@5.3.0: {}
|
||||
|
||||
cliui@8.0.1:
|
||||
dependencies:
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
wrap-ansi: 7.0.0
|
||||
|
||||
color-convert@2.0.1:
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
|
||||
color-name@1.1.4: {}
|
||||
|
||||
cross-spawn@7.0.3:
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
shebang-command: 2.0.0
|
||||
which: 2.0.2
|
||||
|
||||
eastasianwidth@0.2.0: {}
|
||||
|
||||
emoji-regex@8.0.0: {}
|
||||
|
||||
emoji-regex@9.2.2: {}
|
||||
|
||||
escalade@3.2.0: {}
|
||||
|
||||
foreground-child@3.3.0:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.3
|
||||
signal-exit: 4.1.0
|
||||
|
||||
get-caller-file@2.0.5: {}
|
||||
|
||||
glob@10.4.5:
|
||||
dependencies:
|
||||
foreground-child: 3.3.0
|
||||
jackspeak: 3.4.3
|
||||
minimatch: 9.0.5
|
||||
minipass: 7.1.2
|
||||
package-json-from-dist: 1.0.1
|
||||
path-scurry: 1.11.1
|
||||
|
||||
is-fullwidth-code-point@3.0.0: {}
|
||||
|
||||
isexe@2.0.0: {}
|
||||
|
||||
jackspeak@3.4.3:
|
||||
dependencies:
|
||||
'@isaacs/cliui': 8.0.2
|
||||
optionalDependencies:
|
||||
'@pkgjs/parseargs': 0.11.0
|
||||
|
||||
kleur@3.0.3: {}
|
||||
|
||||
lru-cache@10.4.3: {}
|
||||
|
||||
minimatch@9.0.5:
|
||||
dependencies:
|
||||
brace-expansion: 2.0.1
|
||||
|
||||
minipass@7.1.2: {}
|
||||
|
||||
package-json-from-dist@1.0.1: {}
|
||||
|
||||
path-key@3.1.1: {}
|
||||
|
||||
path-scurry@1.11.1:
|
||||
dependencies:
|
||||
lru-cache: 10.4.3
|
||||
minipass: 7.1.2
|
||||
|
||||
prompts@2.4.2:
|
||||
dependencies:
|
||||
kleur: 3.0.3
|
||||
sisteransi: 1.0.5
|
||||
|
||||
replace-in-file@8.2.0:
|
||||
dependencies:
|
||||
chalk: 5.3.0
|
||||
glob: 10.4.5
|
||||
yargs: 17.7.2
|
||||
|
||||
require-directory@2.1.1: {}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
dependencies:
|
||||
shebang-regex: 3.0.0
|
||||
|
||||
shebang-regex@3.0.0: {}
|
||||
|
||||
signal-exit@4.1.0: {}
|
||||
|
||||
sisteransi@1.0.5: {}
|
||||
|
||||
string-width@4.2.3:
|
||||
dependencies:
|
||||
emoji-regex: 8.0.0
|
||||
is-fullwidth-code-point: 3.0.0
|
||||
strip-ansi: 6.0.1
|
||||
|
||||
string-width@5.1.2:
|
||||
dependencies:
|
||||
eastasianwidth: 0.2.0
|
||||
emoji-regex: 9.2.2
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
strip-ansi@6.0.1:
|
||||
dependencies:
|
||||
ansi-regex: 5.0.1
|
||||
|
||||
strip-ansi@7.1.0:
|
||||
dependencies:
|
||||
ansi-regex: 6.1.0
|
||||
|
||||
which@2.0.2:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
wrap-ansi@7.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
|
||||
wrap-ansi@8.1.0:
|
||||
dependencies:
|
||||
ansi-styles: 6.2.1
|
||||
string-width: 5.1.2
|
||||
strip-ansi: 7.1.0
|
||||
|
||||
y18n@5.0.8: {}
|
||||
|
||||
yargs-parser@21.1.1: {}
|
||||
|
||||
yargs@17.7.2:
|
||||
dependencies:
|
||||
cliui: 8.0.1
|
||||
escalade: 3.2.0
|
||||
get-caller-file: 2.0.5
|
||||
require-directory: 2.1.1
|
||||
string-width: 4.2.3
|
||||
y18n: 5.0.8
|
||||
yargs-parser: 21.1.1
|
2
applications/system/js_app/packages/create-fz-app/template/.gitignore
vendored
Normal file
2
applications/system/js_app/packages/create-fz-app/template/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/dist
|
||||
node_modules/
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
build: {
|
||||
// Where to put the compiled file
|
||||
output: "dist/<app_name>.js",
|
||||
|
||||
// Whether to reduce the final file size at the cost of readability and
|
||||
// clarity of error messages
|
||||
minify: false,
|
||||
|
||||
// Set this to `false` if you've thoroughly read the documentation and
|
||||
// are sure that you can use manual version checks to your advantage
|
||||
enforceSdkVersion: true,
|
||||
},
|
||||
|
||||
upload: {
|
||||
// Where to grab the file from. If you're not doing any extra processing
|
||||
// after the SDK, this should match `build.output`
|
||||
input: "dist/<app_name>.js",
|
||||
|
||||
// Where to put the file on the device
|
||||
output: "/ext/apps/Scripts/<app_name>.js",
|
||||
},
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// import modules
|
||||
// caution: `eventLoop` HAS to be imported before `gui`, and `gui` HAS to be
|
||||
// imported before any `gui` submodules.
|
||||
import * as eventLoop from "@flipperdevices/fz-sdk/event_loop";
|
||||
import * as gui from "@flipperdevices/fz-sdk/gui";
|
||||
import * as dialog from "@flipperdevices/fz-sdk/gui/dialog";
|
||||
|
||||
// a common pattern is to declare all the views that your app uses on one object
|
||||
const views = {
|
||||
dialog: dialog.makeWith({
|
||||
header: "Hello from <app_name>",
|
||||
text: "Check out index.ts and\nchange something :)",
|
||||
center: "Gonna do that!",
|
||||
}),
|
||||
};
|
||||
|
||||
// stop app on center button press
|
||||
eventLoop.subscribe(views.dialog.input, (_sub, button, eventLoop) => {
|
||||
if (button === "center")
|
||||
eventLoop.stop();
|
||||
}, eventLoop);
|
||||
|
||||
// stop app on back button press
|
||||
eventLoop.subscribe(gui.viewDispatcher.navigation, (_sub, _item, eventLoop) => {
|
||||
eventLoop.stop();
|
||||
}, eventLoop);
|
||||
|
||||
// run app
|
||||
gui.viewDispatcher.switchTo(views.dialog);
|
||||
eventLoop.run();
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "<app_name>",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "tsc && node node_modules/@flipperdevices/fz-sdk/sdk.js build",
|
||||
"start": "npm run build && node node_modules/@flipperdevices/fz-sdk/sdk.js upload"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@flipperdevices/fz-sdk": "^0.1",
|
||||
"typescript": "^5.6.3"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"checkJs": true,
|
||||
"module": "CommonJS",
|
||||
"noLib": true,
|
||||
"target": "ES2015",
|
||||
},
|
||||
"files": [
|
||||
"./node_modules/@flipperdevices/fz-sdk/global.d.ts",
|
||||
],
|
||||
"include": [
|
||||
"./**/*.ts",
|
||||
"./**/*.js"
|
||||
],
|
||||
"exclude": [
|
||||
"./node_modules/**/*",
|
||||
"dist/**/*",
|
||||
],
|
||||
}
|
1
applications/system/js_app/packages/fz-sdk/.gitignore
vendored
Normal file
1
applications/system/js_app/packages/fz-sdk/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
docs/
|
31
applications/system/js_app/packages/fz-sdk/README.md
Normal file
31
applications/system/js_app/packages/fz-sdk/README.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Flipper Zero JavaScript SDK
|
||||
This package contains official tooling and typings for developing Flipper Zero
|
||||
applications in JavaScript.
|
||||
|
||||
## Getting started
|
||||
Create your application using the interactive wizard:
|
||||
```shell
|
||||
npx @flipperdevices/create-fz-app@latest
|
||||
```
|
||||
|
||||
Then, enter the directory with your application and launch it:
|
||||
```shell
|
||||
cd my-flip-app
|
||||
npm start
|
||||
```
|
||||
|
||||
You are free to use `pnpm` or `yarn` instead of `npm`.
|
||||
|
||||
## Versioning
|
||||
For each version of this package, the major and minor components match those of
|
||||
the Flipper Zero JS SDK version that that package version targets. This version
|
||||
follows semver. For example, apps compiled with SDK version `0.1.0` will be
|
||||
compatible with SDK versions `0.1`...`1.0` (not including `1.0`).
|
||||
|
||||
Every API has a version history reflected in its JSDoc comment. It is heavily
|
||||
recommended to check SDK compatibility using a combination of
|
||||
`sdkCompatibilityStatus`, `isSdkCompatible`, `assertSdkCompatibility` depending
|
||||
on your use case.
|
||||
|
||||
## Documentation
|
||||
Check out the [JavaScript section in the Developer Documentation](https://developer.flipper.net/flipperzero/doxygen/js.html)
|
|
@ -1,8 +1,10 @@
|
|||
/**
|
||||
* @brief Special key codes that this module recognizes
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export type ModifierKey = "CTRL" | "SHIFT" | "ALT" | "GUI";
|
||||
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export type MainKey =
|
||||
"DOWN" | "LEFT" | "RIGHT" | "UP" |
|
||||
|
||||
|
@ -28,16 +30,19 @@ export type MainKey =
|
|||
"m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" |
|
||||
"y" | "z";
|
||||
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export type KeyCode = MainKey | ModifierKey | number;
|
||||
|
||||
/**
|
||||
* @brief Initializes the module
|
||||
* @param settings USB device settings. Omit to select default parameters
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function setup(settings?: { vid: number, pid: number, mfrName?: string, prodName?: string }): void;
|
||||
|
||||
/**
|
||||
* @brief Tells whether the virtual USB HID device has successfully connected
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function isConnected(): boolean;
|
||||
|
||||
|
@ -46,6 +51,7 @@ export declare function isConnected(): boolean;
|
|||
* @param keys The arguments represent a set of keys to. Out of that set, only
|
||||
* one of the keys may represent a "main key" (see `MainKey`), with
|
||||
* the rest being modifier keys (see `ModifierKey`).
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function press(...keys: KeyCode[]): void;
|
||||
|
||||
|
@ -54,6 +60,7 @@ export declare function press(...keys: KeyCode[]): void;
|
|||
* @param keys The arguments represent a set of keys to. Out of that set, only
|
||||
* one of the keys may represent a "main key" (see `MainKey`), with
|
||||
* the rest being modifier keys (see `ModifierKey`).
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function hold(...keys: KeyCode[]): void;
|
||||
|
||||
|
@ -62,6 +69,7 @@ export declare function hold(...keys: KeyCode[]): void;
|
|||
* @param keys The arguments represent a set of keys to. Out of that set, only
|
||||
* one of the keys may represent a "main key" (see `MainKey`), with
|
||||
* the rest being modifier keys (see `ModifierKey`).
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function release(...keys: KeyCode[]): void;
|
||||
|
||||
|
@ -69,6 +77,7 @@ export declare function release(...keys: KeyCode[]): void;
|
|||
* @brief Prints a string by repeatedly pressing and releasing keys
|
||||
* @param string The string to print
|
||||
* @param delay How many milliseconds to wait between key presses
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function print(string: string, delay?: number): void;
|
||||
|
||||
|
@ -77,5 +86,6 @@ export declare function print(string: string, delay?: number): void;
|
|||
* "Enter" after printing the string
|
||||
* @param string The string to print
|
||||
* @param delay How many milliseconds to wait between key presses
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function println(string: string, delay?: number): void;
|
|
@ -0,0 +1 @@
|
|||
# Welcome
|
182
applications/system/js_app/packages/fz-sdk/event_loop/index.d.ts
vendored
Normal file
182
applications/system/js_app/packages/fz-sdk/event_loop/index.d.ts
vendored
Normal file
|
@ -0,0 +1,182 @@
|
|||
/**
|
||||
* Module for dealing with events
|
||||
*
|
||||
* ```js
|
||||
* let eventLoop = require("event_loop");
|
||||
* ```
|
||||
*
|
||||
* The event loop is central to event-based programming in many frameworks, and
|
||||
* our JS subsystem is no exception. It is a good idea to familiarize yourself
|
||||
* with the event loop first before using any of the advanced modules (e.g. GPIO
|
||||
* and GUI).
|
||||
*
|
||||
* # Conceptualizing the event loop
|
||||
* If you ever wrote JavaScript before, you have definitely seen callbacks. It's
|
||||
* when a function accepts another function (usually an anonymous one) as one of
|
||||
* the arguments, which it will call later on, e.g. when an event happens or
|
||||
* when data becomes ready:
|
||||
* ```js
|
||||
* setTimeout(function() { console.log("Hello, World!") }, 1000);
|
||||
* ```
|
||||
*
|
||||
* Many JavaScript engines employ a queue that the runtime fetches events from
|
||||
* as they occur, subsequently calling the corresponding callbacks. This is done
|
||||
* in a long-running loop, hence the name "event loop". Here's the pseudocode
|
||||
* for a typical event loop:
|
||||
* ```js
|
||||
* while(loop_is_running()) {
|
||||
* if(event_available_in_queue()) {
|
||||
* let event = fetch_event_from_queue();
|
||||
* let callback = get_callback_associated_with(event);
|
||||
* if(callback)
|
||||
* callback(get_extra_data_for(event));
|
||||
* } else {
|
||||
* // avoid wasting CPU time
|
||||
* sleep_until_any_event_becomes_available();
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Most JS runtimes enclose the event loop within themselves, so that most JS
|
||||
* programmers does not even need to be aware of its existence. This is not the
|
||||
* case with our JS subsystem.
|
||||
*
|
||||
* # Example
|
||||
* This is how one would write something similar to the `setTimeout` example
|
||||
* above:
|
||||
* ```js
|
||||
* // import module
|
||||
* let eventLoop = require("event_loop");
|
||||
*
|
||||
* // create an event source that will fire once 1 second after it has been created
|
||||
* let timer = eventLoop.timer("oneshot", 1000);
|
||||
*
|
||||
* // subscribe a callback to the event source
|
||||
* eventLoop.subscribe(timer, function(_subscription, _item, eventLoop) {
|
||||
* print("Hello, World!");
|
||||
* eventLoop.stop();
|
||||
* }, eventLoop); // notice this extra argument. we'll come back to this later
|
||||
*
|
||||
* // run the loop until it is stopped
|
||||
* eventLoop.run();
|
||||
*
|
||||
* // the previous line will only finish executing once `.stop()` is called, hence
|
||||
* // the following line will execute only after "Hello, World!" is printed
|
||||
* print("Stopped");
|
||||
* ```
|
||||
*
|
||||
* I promised you that we'll come back to the extra argument after the callback
|
||||
* function. Our JavaScript engine does not support closures (anonymous
|
||||
* functions that access values outside of their arguments), so we ask
|
||||
* `subscribe` to pass an outside value (namely, `eventLoop`) as an argument to
|
||||
* the callback so that we can access it. We can modify this extra state:
|
||||
* ```js
|
||||
* // this timer will fire every second
|
||||
* let timer = eventLoop.timer("periodic", 1000);
|
||||
* eventLoop.subscribe(timer, function(_subscription, _item, counter, eventLoop) {
|
||||
* print("Counter is at:", counter);
|
||||
* if(counter === 10)
|
||||
* eventLoop.stop();
|
||||
* // modify the extra arguments that will be passed to us the next time
|
||||
* return [counter + 1, eventLoop];
|
||||
* }, 0, eventLoop);
|
||||
* ```
|
||||
*
|
||||
* Because we have two extra arguments, if we return anything other than an
|
||||
* array of length 2, the arguments will be kept as-is for the next call.
|
||||
*
|
||||
* The first two arguments that get passed to our callback are:
|
||||
* - The subscription manager that lets us `.cancel()` our subscription
|
||||
* - The event item, used for events that have extra data. Timer events do
|
||||
* not, they just produce `undefined`.
|
||||
*
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
type Lit = undefined | null | {};
|
||||
|
||||
/**
|
||||
* Subscription control interface
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export interface Subscription {
|
||||
/**
|
||||
* Cancels the subscription, preventing any future events managed by the
|
||||
* subscription from firing
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
cancel(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opaque event source identifier
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export type Contract<Item = undefined> = symbol & { "__tag__": "contract" };
|
||||
// introducing a nominal type in a hacky way; the `__tag__` property doesn't really exist.
|
||||
|
||||
/**
|
||||
* A callback can be assigned to an event loop to listen to an event. It may
|
||||
* return an array with values that will be passed to it as arguments the next
|
||||
* time that it is called. The first argument is always the subscription
|
||||
* manager, and the second argument is always the item that trigged the event.
|
||||
* The type of the item is defined by the event source.
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export type Callback<Item, Args extends Lit[]> = (subscription: Subscription, item: Item, ...args: Args) => Args | undefined | void;
|
||||
|
||||
/**
|
||||
* Subscribes a callback to an event
|
||||
* @param contract Event identifier
|
||||
* @param callback Function to call when the event is triggered
|
||||
* @param args Initial arguments passed to the callback
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export function subscribe<Item, Args extends Lit[]>(contract: Contract<Item>, callback: Callback<Item, Args>, ...args: Args): Subscription;
|
||||
/**
|
||||
* Runs the event loop until it is stopped (potentially never)
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export function run(): void | never;
|
||||
/**
|
||||
* Stops the event loop
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export function stop(): void;
|
||||
|
||||
/**
|
||||
* Creates a timer event that can be subscribed to just like any other event
|
||||
* @param mode Either `"oneshot"` or `"periodic"`
|
||||
* @param interval Timer interval in milliseconds
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export function timer(mode: "oneshot" | "periodic", interval: number): Contract;
|
||||
|
||||
/**
|
||||
* Message queue
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare class Queue<T> {
|
||||
/**
|
||||
* Message event
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
input: Contract<T>;
|
||||
/**
|
||||
* Sends a message to the queue
|
||||
* @param message message to send
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
send(message: T): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a message queue
|
||||
* @param length maximum queue capacity
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export function queue<T>(length: number): Queue<T>;
|
41
applications/system/js_app/packages/fz-sdk/flipper/index.d.ts
vendored
Normal file
41
applications/system/js_app/packages/fz-sdk/flipper/index.d.ts
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Module for querying device properties
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Returns the device model
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function getModel(): string;
|
||||
|
||||
/**
|
||||
* @brief Returns the name of the virtual dolphin
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function getName(): string;
|
||||
|
||||
/**
|
||||
* @brief Returns the battery charge percentage
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function getBatteryCharge(): number;
|
||||
|
||||
/**
|
||||
* @warning Do **NOT** use this to check the presence or absence of features. If
|
||||
* you do, I'm gonna be sad :( Instead, refer to `checkSdkFeatures` and
|
||||
* other similar mechanisms.
|
||||
* @note Original firmware reports `"flipperdevices"`.
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare const firmwareVendor: string;
|
||||
|
||||
/**
|
||||
* @warning Do **NOT** use this to check the presence or absence of features. If
|
||||
* you do, I'm gonna be sad :( Instead, refer to
|
||||
* `checkSdkCompatibility` and other similar mechanisms.
|
||||
* @note You're looking at JS SDK 0.1
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare const jsSdkVersion: [number, number];
|
344
applications/system/js_app/packages/fz-sdk/global.d.ts
vendored
Normal file
344
applications/system/js_app/packages/fz-sdk/global.d.ts
vendored
Normal file
|
@ -0,0 +1,344 @@
|
|||
/**
|
||||
* Things from this module are automatically available to you without having to
|
||||
* explicitly import anything.
|
||||
*
|
||||
* # SDK versioning and features
|
||||
*
|
||||
* ## Motivation
|
||||
* It is very important that you check that features are implemented before you
|
||||
* use them. By adding the necessary checks, you ensure that your users get a
|
||||
* clear warning instead of a cryptic error message when running the script.
|
||||
*
|
||||
* This system has been designed in collaboration with our community in order to
|
||||
* make things better for everybody involved. You can find out more in this
|
||||
* discussion: https://github.com/flipperdevices/flipperzero-firmware/pull/3961
|
||||
*
|
||||
* ## Community agreement
|
||||
* Each interpreter implementation (aka "JS SDK", aka "JS API"), including
|
||||
* those found in third-party firmware distributions, defines two markers for
|
||||
* signaling what it supports: the **SDK version** and the
|
||||
* **extra feature set**.
|
||||
*
|
||||
* The **SDK version** consists of two semver-like integer components: the major
|
||||
* version and the minor version. Like semver, the major version is bumped when
|
||||
* a breaking change is introduced (i.e. one that would require correction of
|
||||
* apps by their developers), and the minor version is bumped when a new
|
||||
* non-breaking feature is introduced. Because we have adopted TypeScript,
|
||||
* the https://www.semver-ts.org/ standard is used to determine whether a change
|
||||
* is breaking or not. The basis of `semver-ts` is the "no new red squiggles"
|
||||
* rule.
|
||||
*
|
||||
* Every major version is associated with a set of **extra features** that are
|
||||
* present in some firmware distributions but not others. Distributions may
|
||||
* cross-port features between each other, until at some point they get ported
|
||||
* into the upstream firmware distribution. With the next major release of the
|
||||
* JS SDK, all extra features present in the upstream distribution are now
|
||||
* declared **baseline features**, and thus no longer recognized as "extra
|
||||
* features".
|
||||
*
|
||||
* Before using a feature, you must check that the interpreter that you're
|
||||
* running on actually supports it. If you don't, the portability of your
|
||||
* application will suffer.
|
||||
*
|
||||
* ## Implementation
|
||||
* Use the following functions to check version compatibility:
|
||||
* - `checkSdkCompatibility` when your script absolutely cannot function on an
|
||||
* incompatible interpreter
|
||||
* - `isSdkCompatible` when your script can leverage multiple interpreter
|
||||
* editions to its advantage
|
||||
* - `sdkCompatibilityStatus` when you need a detailed status on compatibility
|
||||
*
|
||||
* Use the following functions to check feature compatibility:
|
||||
* - `checkSdkFeatures` when your script absolutely cannot function on an
|
||||
* incompatible interpreter
|
||||
* - `doesSdkSupport` when your script can leverage multiple interpreter
|
||||
* editions to its advantage
|
||||
*
|
||||
* ## Automatic version enforcement
|
||||
* The SDK will automatically insert a call to `checkSdkCompatibility` in the
|
||||
* beginning of the resulting script. If you would like to disable this check
|
||||
* and instead use other manual compatibility checking facilities, edit your
|
||||
* `fz-sdk.config.json5`.
|
||||
*
|
||||
* # Standard library
|
||||
* Standard library features are mostly unimplemented. This module defines,
|
||||
* among other things, the features that _are_ implemented.
|
||||
*
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Checks compatibility between the script and the JS SDK that the
|
||||
* firmware provides
|
||||
*
|
||||
* @note You're looking at JS SDK v0.1
|
||||
*
|
||||
* @param expectedMajor JS SDK major version expected by the script
|
||||
* @param expectedMinor JS SDK minor version expected by the script
|
||||
* @returns Compatibility status:
|
||||
* - `"compatible"` if the script and the JS SDK are compatible
|
||||
* - `"firmwareTooOld"` if the expected major version is larger than the
|
||||
* version of the firmware, or if the expected minor version is larger than
|
||||
* the version of the firmware
|
||||
* - `"firmwareTooNew"` if the expected major version is lower than the
|
||||
* version of the firmware
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
declare function sdkCompatibilityStatus(expectedMajor: number, expectedMinor: number):
|
||||
"compatible" | "firmwareTooOld" | "firmwareTooNew";
|
||||
|
||||
/**
|
||||
* @brief Checks compatibility between the script and the JS SDK that the
|
||||
* firmware provides in a boolean fashion
|
||||
*
|
||||
* @note You're looking at JS SDK v0.1
|
||||
*
|
||||
* @param expectedMajor JS SDK major version expected by the script
|
||||
* @param expectedMinor JS SDK minor version expected by the script
|
||||
* @returns `true` if the two are compatible, `false` otherwise
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
declare function isSdkCompatible(expectedMajor: number, expectedMinor: number): boolean;
|
||||
|
||||
/**
|
||||
* @brief Asks the user whether to continue executing the script if the versions
|
||||
* are not compatible. Does nothing if they are.
|
||||
*
|
||||
* @note You're looking at JS SDK v0.1
|
||||
*
|
||||
* @param expectedMajor JS SDK major version expected by the script
|
||||
* @param expectedMinor JS SDK minor version expected by the script
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
declare function checkSdkCompatibility(expectedMajor: number, expectedMinor: number): void | never;
|
||||
|
||||
/**
|
||||
* @brief Checks whether all of the specified extra features are supported by
|
||||
* the interpreter.
|
||||
* @warning This function will return `false` if a queried feature is now
|
||||
* recognized as a baseline feature. For more info, consult the module
|
||||
* documentation.
|
||||
* @param features Array of named features to query
|
||||
*/
|
||||
declare function doesSdkSupport(features: string[]): boolean;
|
||||
|
||||
/**
|
||||
* @brief Checks whether all of the specified extra features are supported by
|
||||
* the interpreter, asking the user if they want to continue running the
|
||||
* script if they're not.
|
||||
* @warning This function will act as if the feature is not implemented for
|
||||
* features that are now recognized as baseline features. For more
|
||||
* info, consult the module documentation.
|
||||
* @param features Array of named features to query
|
||||
*/
|
||||
declare function checkSdkFeatures(features: string[]): void | never;
|
||||
|
||||
/**
|
||||
* @brief Pauses JavaScript execution for a while
|
||||
* @param ms How many milliseconds to pause the execution for
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
declare function delay(ms: number): void;
|
||||
|
||||
/**
|
||||
* @brief Prints to the GUI console view
|
||||
* @param args The arguments are converted to strings, concatenated without any
|
||||
* spaces in between and printed to the console view
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
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: 10
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
declare function toString(value: number, base?: number): string;
|
||||
|
||||
/**
|
||||
* @brief Reads a JS value from a file
|
||||
*
|
||||
* Reads a file at the specified path, interprets it as a JS value and returns
|
||||
* said value.
|
||||
*
|
||||
* @param path The path to the file
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
declare function load(path: string): any;
|
||||
|
||||
/**
|
||||
* @brief Loads a natively implemented module
|
||||
* @param module The name of the module to load
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
declare function require(module: string): any;
|
||||
|
||||
/**
|
||||
* @brief mJS Foreign Pointer type
|
||||
*
|
||||
* JavaScript code cannot do anything with values of `RawPointer` type except
|
||||
* acquire them from native code and pass them right back to other parts of
|
||||
* native code. These values cannot be turned into something meaningful, nor can
|
||||
* be they modified.
|
||||
*
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
declare type RawPointer = symbol & { "__tag__": "raw_ptr" };
|
||||
// introducing a nominal type in a hacky way; the `__tag__` property doesn't really exist.
|
||||
|
||||
/**
|
||||
* @brief Holds raw bytes
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
declare class ArrayBuffer {
|
||||
/**
|
||||
* @brief The pointer to the byte buffer
|
||||
* @note Like other `RawPointer` values, this value is essentially useless
|
||||
* to JS code.
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
getPtr: RawPointer;
|
||||
/**
|
||||
* @brief The length of the buffer in bytes
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
byteLength: number;
|
||||
/**
|
||||
* @brief Creates an `ArrayBuffer` that contains a sub-part of the buffer
|
||||
* @param start The index of the byte in the source buffer to be used as the
|
||||
* start for the new buffer
|
||||
* @param end The index of the byte in the source buffer that follows the
|
||||
* byte to be used as the last byte for the new buffer
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
slice(start: number, end?: number): ArrayBuffer;
|
||||
}
|
||||
|
||||
declare function ArrayBuffer(): ArrayBuffer;
|
||||
|
||||
declare type ElementType = "u8" | "i8" | "u16" | "i16" | "u32" | "i32";
|
||||
|
||||
declare class TypedArray<E extends ElementType> {
|
||||
/**
|
||||
* @brief The length of the buffer in bytes
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
byteLength: number;
|
||||
/**
|
||||
* @brief The length of the buffer in typed elements
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
length: number;
|
||||
/**
|
||||
* @brief The underlying `ArrayBuffer`
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
buffer: ArrayBuffer;
|
||||
}
|
||||
|
||||
declare class Uint8Array extends TypedArray<"u8"> { }
|
||||
declare class Int8Array extends TypedArray<"i8"> { }
|
||||
declare class Uint16Array extends TypedArray<"u16"> { }
|
||||
declare class Int16Array extends TypedArray<"i16"> { }
|
||||
declare class Uint32Array extends TypedArray<"u32"> { }
|
||||
declare class Int32Array extends TypedArray<"i32"> { }
|
||||
|
||||
declare function Uint8Array(data: ArrayBuffer | number | number[]): Uint8Array;
|
||||
declare function Int8Array(data: ArrayBuffer | number | number[]): Int8Array;
|
||||
declare function Uint16Array(data: ArrayBuffer | number | number[]): Uint16Array;
|
||||
declare function Int16Array(data: ArrayBuffer | number | number[]): Int16Array;
|
||||
declare function Uint32Array(data: ArrayBuffer | number | number[]): Uint32Array;
|
||||
declare function Int32Array(data: ArrayBuffer | number | number[]): Int32Array;
|
||||
|
||||
declare const console: {
|
||||
/**
|
||||
* @brief Prints to the UART logs at the `[I]` level
|
||||
* @param args The arguments are converted to strings, concatenated without any
|
||||
* spaces in between and printed to the logs
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
log(...args: any[]): void;
|
||||
/**
|
||||
* @brief Prints to the UART logs at the `[D]` level
|
||||
* @param args The arguments are converted to strings, concatenated without any
|
||||
* spaces in between and printed to the logs
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
debug(...args: any[]): void;
|
||||
/**
|
||||
* @brief Prints to the UART logs at the `[W]` level
|
||||
* @param args The arguments are converted to strings, concatenated without any
|
||||
* spaces in between and printed to the logs
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
warn(...args: any[]): void;
|
||||
/**
|
||||
* @brief Prints to the UART logs at the `[E]` level
|
||||
* @param args The arguments are converted to strings, concatenated without any
|
||||
* spaces in between and printed to the logs
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
error(...args: any[]): void;
|
||||
};
|
||||
|
||||
declare class Array<T> {
|
||||
/**
|
||||
* @brief Takes items out of the array
|
||||
*
|
||||
* Removes elements from the array and returns them in a new array
|
||||
*
|
||||
* @param start The index to start taking elements from
|
||||
* @param deleteCount How many elements to take
|
||||
* @returns The elements that were taken out of the original array as a new
|
||||
* array
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
splice(start: number, deleteCount: number): T[];
|
||||
/**
|
||||
* @brief Adds a value to the end of the array
|
||||
* @param value The value to add
|
||||
* @returns New length of the array
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
push(value: T): number;
|
||||
/**
|
||||
* @brief How many elements there are in the array
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
length: number;
|
||||
}
|
||||
|
||||
declare class String {
|
||||
/**
|
||||
* @brief How many characters there are in the string
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
length: number;
|
||||
/**
|
||||
* @brief Returns the character code at an index in the string
|
||||
* @param index The index to consult
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
charCodeAt(index: number): number;
|
||||
/**
|
||||
* See `charCodeAt`
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
at(index: number): number;
|
||||
}
|
||||
|
||||
declare class Boolean { }
|
||||
|
||||
declare class Function { }
|
||||
|
||||
declare class Number { }
|
||||
|
||||
declare class Object { }
|
||||
|
||||
declare class RegExp { }
|
||||
|
||||
declare interface IArguments { }
|
||||
|
||||
declare type Partial<O extends object> = { [K in keyof O]?: O[K] };
|
|
@ -1,5 +1,37 @@
|
|||
/**
|
||||
* Module for accessing the GPIO (General Purpose Input/Output) ports
|
||||
*
|
||||
* ```js
|
||||
* let eventLoop = require("event_loop");
|
||||
* let gpio = require("gpio");
|
||||
* ```
|
||||
*
|
||||
* This module depends on the `event_loop` module, so it _must_ only be imported
|
||||
* after `event_loop` is imported.
|
||||
*
|
||||
* # Example
|
||||
* ```js
|
||||
* let eventLoop = require("event_loop");
|
||||
* let gpio = require("gpio");
|
||||
*
|
||||
* let led = gpio.get("pc3");
|
||||
* led.init({ direction: "out", outMode: "push_pull" });
|
||||
*
|
||||
* led.write(true);
|
||||
* delay(1000);
|
||||
* led.write(false);
|
||||
* delay(1000);
|
||||
* ```
|
||||
*
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
import type { Contract } from "../event_loop";
|
||||
|
||||
/**
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export interface Mode {
|
||||
direction: "in" | "out";
|
||||
outMode?: "push_pull" | "open_drain";
|
||||
|
@ -8,31 +40,39 @@ export interface Mode {
|
|||
pull?: "up" | "down";
|
||||
}
|
||||
|
||||
/**
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export interface Pin {
|
||||
/**
|
||||
* Configures a pin. This may be done several times.
|
||||
* @param mode Pin configuration object
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
init(mode: Mode): void;
|
||||
/**
|
||||
* Sets the output value of a pin if it's been configured with
|
||||
* `direction: "out"`.
|
||||
* @param value Logic value to output
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
write(value: boolean): void;
|
||||
/**
|
||||
* Gets the input value of a pin if it's been configured with
|
||||
* `direction: "in"`, but not `inMode: "analog"`.
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
read(): boolean;
|
||||
/**
|
||||
* Gets the input voltage of a pin in millivolts if it's been configured
|
||||
* with `direction: "in"` and `inMode: "analog"`
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
read_analog(): number;
|
||||
readAnalog(): number;
|
||||
/**
|
||||
* Returns an `event_loop` event that can be used to listen to interrupts,
|
||||
* as configured by `init`
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
interrupt(): Contract;
|
||||
}
|
||||
|
@ -41,5 +81,6 @@ export interface Pin {
|
|||
* Returns an object that can be used to manage a GPIO pin. For the list of
|
||||
* available pins, see https://docs.flipper.net/gpio-and-modules#miFsS
|
||||
* @param pin Pin name (e.g. `"PC3"`) or number (e.g. `7`)
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export function get(pin: string | number): Pin;
|
45
applications/system/js_app/packages/fz-sdk/gui/dialog.d.ts
vendored
Normal file
45
applications/system/js_app/packages/fz-sdk/gui/dialog.d.ts
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* Displays a dialog with up to three options.
|
||||
*
|
||||
* <img src="../images/dialog.png" width="200" alt="Sample screenshot of the view" />
|
||||
*
|
||||
* ```js
|
||||
* let eventLoop = require("event_loop");
|
||||
* let gui = require("gui");
|
||||
* let dialogView = require("gui/dialog");
|
||||
* ```
|
||||
*
|
||||
* This module depends on the `gui` module, which in turn depends on the
|
||||
* `event_loop` module, so they _must_ be imported in this order. It is also
|
||||
* recommended to conceptualize these modules first before using this one.
|
||||
*
|
||||
* # Example
|
||||
* For an example refer to the `gui.js` example script.
|
||||
*
|
||||
* # View props
|
||||
* - `header`: Text displayed in bold at the top of the screen
|
||||
* - `text`: Text displayed in the middle of the string
|
||||
* - `left`: Text for the left button
|
||||
* - `center`: Text for the center button
|
||||
* - `right`: Text for the right button
|
||||
*
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
import type { View, ViewFactory } from ".";
|
||||
import type { Contract } from "../event_loop";
|
||||
|
||||
type Props = {
|
||||
header: string,
|
||||
text: string,
|
||||
left: string,
|
||||
center: string,
|
||||
right: string,
|
||||
}
|
||||
declare class Dialog extends View<Props> {
|
||||
input: Contract<"left" | "center" | "right">;
|
||||
}
|
||||
declare class DialogFactory extends ViewFactory<Props, Dialog> { }
|
||||
declare const factory: DialogFactory;
|
||||
export = factory;
|
32
applications/system/js_app/packages/fz-sdk/gui/empty_screen.d.ts
vendored
Normal file
32
applications/system/js_app/packages/fz-sdk/gui/empty_screen.d.ts
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* Displays nothing.
|
||||
*
|
||||
* <img src="../images/empty.png" width="200" alt="Sample screenshot of the view" />
|
||||
*
|
||||
* ```js
|
||||
* let eventLoop = require("event_loop");
|
||||
* let gui = require("gui");
|
||||
* let emptyView = require("gui/empty_screen");
|
||||
* ```
|
||||
*
|
||||
* This module depends on the `gui` module, which in turn depends on the
|
||||
* `event_loop` module, so they _must_ be imported in this order. It is also
|
||||
* recommended to conceptualize these modules first before using this one.
|
||||
*
|
||||
* # Example
|
||||
* For an example refer to the GUI example.
|
||||
*
|
||||
* # View props
|
||||
* This view does not have any props.
|
||||
*
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
import type { View, ViewFactory } from ".";
|
||||
|
||||
type Props = {};
|
||||
declare class EmptyScreen extends View<Props> { }
|
||||
declare class EmptyScreenFactory extends ViewFactory<Props, EmptyScreen> { }
|
||||
declare const factory: EmptyScreenFactory;
|
||||
export = factory;
|
171
applications/system/js_app/packages/fz-sdk/gui/index.d.ts
vendored
Normal file
171
applications/system/js_app/packages/fz-sdk/gui/index.d.ts
vendored
Normal file
|
@ -0,0 +1,171 @@
|
|||
/**
|
||||
* ```js
|
||||
* let eventLoop = require("event_loop");
|
||||
* let gui = require("gui");
|
||||
* ```
|
||||
*
|
||||
* This module depends on the `event_loop` module, so it _must_ only be imported
|
||||
* after `event_loop` is imported.
|
||||
*
|
||||
* ## Conceptualizing GUI
|
||||
* ### Event loop
|
||||
* It is highly recommended to familiarize yourself with the event loop first
|
||||
* before doing GUI-related things.
|
||||
*
|
||||
* ### Canvas
|
||||
* The canvas is just a drawing area with no abstractions over it. Drawing on
|
||||
* the canvas directly (i.e. not through a viewport) is useful in case you want
|
||||
* to implement a custom design element, but this is rather uncommon.
|
||||
*
|
||||
* ### Viewport
|
||||
* A viewport is a window into a rectangular portion of the canvas. Applications
|
||||
* always access the canvas through a viewport.
|
||||
*
|
||||
* ### View
|
||||
* In Flipper's terminology, a "View" is a fullscreen design element that
|
||||
* assumes control over the entire viewport and all input events. Different
|
||||
* types of views are available (not all of which are unfortunately currently
|
||||
* implemented in JS):
|
||||
* | View | Has JS adapter? |
|
||||
* |----------------------|------------------|
|
||||
* | `button_menu` | ❌ |
|
||||
* | `button_panel` | ❌ |
|
||||
* | `byte_input` | ❌ |
|
||||
* | `dialog_ex` | ✅ (as `dialog`) |
|
||||
* | `empty_screen` | ✅ |
|
||||
* | `file_browser` | ❌ |
|
||||
* | `loading` | ✅ |
|
||||
* | `menu` | ❌ |
|
||||
* | `number_input` | ❌ |
|
||||
* | `popup` | ❌ |
|
||||
* | `submenu` | ✅ |
|
||||
* | `text_box` | ✅ |
|
||||
* | `text_input` | ✅ |
|
||||
* | `variable_item_list` | ❌ |
|
||||
* | `widget` | ❌ |
|
||||
*
|
||||
* In JS, each view has its own set of properties (or just "props"). The
|
||||
* programmer can manipulate these properties in two ways:
|
||||
* - Instantiate a `View` using the `makeWith(props)` method, passing an
|
||||
* object with the initial properties
|
||||
* - Call `set(name, value)` to modify a property of an existing `View`
|
||||
*
|
||||
* ### View Dispatcher
|
||||
* The view dispatcher holds references to all the views that an application
|
||||
* needs and switches between them as the application makes requests to do so.
|
||||
*
|
||||
* ### Scene Manager
|
||||
* The scene manager is an optional add-on to the view dispatcher that makes
|
||||
* managing applications with complex navigation flows easier. It is currently
|
||||
* inaccessible from JS.
|
||||
*
|
||||
* ### Approaches
|
||||
* In total, there are three different approaches that you may take when writing
|
||||
* a GUI application:
|
||||
* | Approach | Use cases | Available from JS |
|
||||
* |----------------|------------------------------------------------------------------------------|-------------------|
|
||||
* | ViewPort only | Accessing the graphics API directly, without any of the nice UI abstractions | ❌ |
|
||||
* | ViewDispatcher | Common UI elements that fit with the overall look of the system | ✅ |
|
||||
* | SceneManager | Additional navigation flow management for complex applications | ❌ |
|
||||
*
|
||||
* # Example
|
||||
* An example with three different views using the ViewDispatcher approach:
|
||||
* ```js
|
||||
* let eventLoop = require("event_loop");
|
||||
* let gui = require("gui");
|
||||
* let loadingView = require("gui/loading");
|
||||
* let submenuView = require("gui/submenu");
|
||||
* let emptyView = require("gui/empty_screen");
|
||||
*
|
||||
* // Common pattern: declare all the views in an object. This is absolutely not
|
||||
* // required, but adds clarity to the script.
|
||||
* let views = {
|
||||
* // the view dispatcher auto-✨magically✨ remembers views as they are created
|
||||
* loading: loadingView.make(),
|
||||
* empty: emptyView.make(),
|
||||
* demos: submenuView.makeWith({
|
||||
* items: [
|
||||
* "Hourglass screen",
|
||||
* "Empty screen",
|
||||
* "Exit app",
|
||||
* ],
|
||||
* }),
|
||||
* };
|
||||
*
|
||||
* // go to different screens depending on what was selected
|
||||
* eventLoop.subscribe(views.demos.chosen, function (_sub, index, gui, eventLoop, views) {
|
||||
* if (index === 0) {
|
||||
* gui.viewDispatcher.switchTo(views.loading);
|
||||
* } else if (index === 1) {
|
||||
* gui.viewDispatcher.switchTo(views.empty);
|
||||
* } else if (index === 2) {
|
||||
* eventLoop.stop();
|
||||
* }
|
||||
* }, gui, eventLoop, views);
|
||||
*
|
||||
* // go to the demo chooser screen when the back key is pressed
|
||||
* eventLoop.subscribe(gui.viewDispatcher.navigation, function (_sub, _, gui, views) {
|
||||
* gui.viewDispatcher.switchTo(views.demos);
|
||||
* }, gui, views);
|
||||
*
|
||||
* // run UI
|
||||
* gui.viewDispatcher.switchTo(views.demos);
|
||||
* eventLoop.run();
|
||||
* ```
|
||||
*
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
import type { Contract } from "../event_loop";
|
||||
|
||||
type Properties = { [K: string]: any };
|
||||
|
||||
export declare class View<Props extends Properties> {
|
||||
set<P extends keyof Props>(property: P, value: Props[P]): void;
|
||||
}
|
||||
|
||||
export declare class ViewFactory<Props extends Properties, V extends View<Props>> {
|
||||
make(): V;
|
||||
makeWith(initial: Partial<Props>): V;
|
||||
}
|
||||
|
||||
/**
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
declare class ViewDispatcher {
|
||||
/**
|
||||
* Event source for `sendCustom` events
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
custom: Contract<number>;
|
||||
/**
|
||||
* Event source for navigation events (back key presses)
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
navigation: Contract;
|
||||
/**
|
||||
* Sends a number to the custom event handler
|
||||
* @param event number to send
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
sendCustom(event: number): void;
|
||||
/**
|
||||
* Switches to a view
|
||||
* @param assoc View-ViewDispatcher association as returned by `add`
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
switchTo(assoc: View<any>): void;
|
||||
/**
|
||||
* Sends this ViewDispatcher to the front or back, above or below all other
|
||||
* GUI viewports
|
||||
* @param direction Either `"front"` or `"back"`
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
sendTo(direction: "front" | "back"): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export const viewDispatcher: ViewDispatcher;
|
33
applications/system/js_app/packages/fz-sdk/gui/loading.d.ts
vendored
Normal file
33
applications/system/js_app/packages/fz-sdk/gui/loading.d.ts
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* Displays an animated hourglass icon. Suppresses all `navigation` events,
|
||||
* making it impossible for the user to exit the view by pressing the back key.
|
||||
*
|
||||
* <img src="../images/loading.png" width="200" alt="Sample screenshot of the view" />
|
||||
*
|
||||
* ```js
|
||||
* let eventLoop = require("event_loop");
|
||||
* let gui = require("gui");
|
||||
* let loadingView = require("gui/loading");
|
||||
* ```
|
||||
*
|
||||
* This module depends on the `gui` module, which in turn depends on the
|
||||
* `event_loop` module, so they _must_ be imported in this order. It is also
|
||||
* recommended to conceptualize these modules first before using this one.
|
||||
*
|
||||
* # Example
|
||||
* For an example refer to the GUI example.
|
||||
*
|
||||
* # View props
|
||||
* This view does not have any props.
|
||||
*
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
import type { View, ViewFactory } from ".";
|
||||
|
||||
type Props = {};
|
||||
declare class Loading extends View<Props> { }
|
||||
declare class LoadingFactory extends ViewFactory<Props, Loading> { }
|
||||
declare const factory: LoadingFactory;
|
||||
export = factory;
|
39
applications/system/js_app/packages/fz-sdk/gui/submenu.d.ts
vendored
Normal file
39
applications/system/js_app/packages/fz-sdk/gui/submenu.d.ts
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* Displays a scrollable list of clickable textual entries.
|
||||
*
|
||||
* <img src="../images/submenu.png" width="200" alt="Sample screenshot of the view" />
|
||||
*
|
||||
* ```js
|
||||
* let eventLoop = require("event_loop");
|
||||
* let gui = require("gui");
|
||||
* let submenuView = require("gui/submenu");
|
||||
* ```
|
||||
*
|
||||
* This module depends on the `gui` module, which in turn depends on the
|
||||
* `event_loop` module, so they _must_ be imported in this order. It is also
|
||||
* recommended to conceptualize these modules first before using this one.
|
||||
*
|
||||
* # Example
|
||||
* For an example refer to the GUI example.
|
||||
*
|
||||
* # View props
|
||||
* - `header`: Text displayed at the top of the screen in bold
|
||||
* - `items`: Array of selectable textual items
|
||||
*
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
import type { View, ViewFactory } from ".";
|
||||
import type { Contract } from "../event_loop";
|
||||
|
||||
type Props = {
|
||||
header: string,
|
||||
items: string[],
|
||||
};
|
||||
declare class Submenu extends View<Props> {
|
||||
chosen: Contract<number>;
|
||||
}
|
||||
declare class SubmenuFactory extends ViewFactory<Props, Submenu> { }
|
||||
declare const factory: SubmenuFactory;
|
||||
export = factory;
|
41
applications/system/js_app/packages/fz-sdk/gui/text_box.d.ts
vendored
Normal file
41
applications/system/js_app/packages/fz-sdk/gui/text_box.d.ts
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Displays a scrollable read-only text field.
|
||||
*
|
||||
* <img src="text_box.png" width="200" alt="Sample screenshot of the view" />
|
||||
*
|
||||
* ```js
|
||||
* let eventLoop = require("event_loop");
|
||||
* let gui = require("gui");
|
||||
* let textBoxView = require("gui/text_box");
|
||||
* ```
|
||||
*
|
||||
* This module depends on the `gui` module, which in turn depends on the
|
||||
* `event_loop` module, so they _must_ be imported in this order. It is also
|
||||
* recommended to conceptualize these modules first before using this one.
|
||||
*
|
||||
* # Example
|
||||
* For an example refer to the `gui.js` example script.
|
||||
*
|
||||
* # View props
|
||||
* - `text`: Text in the text box
|
||||
* - `font`: The font to display the text in (`"text"` or `"hex"`)
|
||||
* - `focus`: The initial focus of the text box (`"start"` or `"end"`)
|
||||
*
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
import type { View, ViewFactory } from ".";
|
||||
import type { Contract } from "../event_loop";
|
||||
|
||||
type Props = {
|
||||
text: string,
|
||||
font: "text" | "hex",
|
||||
focus: "start" | "end",
|
||||
}
|
||||
declare class TextBox extends View<Props> {
|
||||
chosen: Contract<number>;
|
||||
}
|
||||
declare class TextBoxFactory extends ViewFactory<Props, TextBox> { }
|
||||
declare const factory: TextBoxFactory;
|
||||
export = factory;
|
41
applications/system/js_app/packages/fz-sdk/gui/text_input.d.ts
vendored
Normal file
41
applications/system/js_app/packages/fz-sdk/gui/text_input.d.ts
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Displays a keyboard.
|
||||
*
|
||||
* <img src="../images/text_input.png" width="200" alt="Sample screenshot of the view" />
|
||||
*
|
||||
* ```js
|
||||
* let eventLoop = require("event_loop");
|
||||
* let gui = require("gui");
|
||||
* let textInputView = require("gui/text_input");
|
||||
* ```
|
||||
*
|
||||
* This module depends on the `gui` module, which in turn depends on the
|
||||
* `event_loop` module, so they _must_ be imported in this order. It is also
|
||||
* recommended to conceptualize these modules first before using this one.
|
||||
*
|
||||
* # Example
|
||||
* For an example refer to the `gui.js` example script.
|
||||
*
|
||||
* # View props
|
||||
* - `header`: Text displayed at the top of the screen
|
||||
* - `minLength`: Minimum allowed text length
|
||||
* - `maxLength`: Maximum allowed text length
|
||||
*
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
import type { View, ViewFactory } from ".";
|
||||
import type { Contract } from "../event_loop";
|
||||
|
||||
type Props = {
|
||||
header: string,
|
||||
minLength: number,
|
||||
maxLength: number,
|
||||
}
|
||||
declare class TextInput extends View<Props> {
|
||||
input: Contract<string>;
|
||||
}
|
||||
declare class TextInputFactory extends ViewFactory<Props, TextInput> { }
|
||||
declare const factory: TextInputFactory;
|
||||
export = factory;
|
|
@ -1,24 +1,54 @@
|
|||
/**
|
||||
* Math operations
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function abs(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function acos(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function acosh(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function asin(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function asinh(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function atan(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function atan2(a: number, b: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function atanh(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function cbrt(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function ceil(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function clz32(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function cos(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function exp(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function floor(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function max(n: number, m: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function min(n: number, m: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function pow(n: number, m: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function random(): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function sign(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function sin(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function sqrt(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
export function trunc(n: number): number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
declare const PI: number;
|
||||
/** @version Added in JS SDK 0.1 */
|
||||
declare const EPSILON: number;
|
|
@ -1,6 +1,13 @@
|
|||
/**
|
||||
* Module for using the color LED and vibration motor
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Signals success to the user via the color LED, speaker and vibration
|
||||
* motor
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function success(): void;
|
||||
|
||||
|
@ -10,11 +17,15 @@ export declare function success(): void;
|
|||
*/
|
||||
export declare function error(): void;
|
||||
|
||||
/**
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export type Color = "red" | "green" | "blue" | "yellow" | "cyan" | "magenta";
|
||||
|
||||
/**
|
||||
* @brief Displays a basic color on the color LED
|
||||
* @param color The color to display, see `Color`
|
||||
* @param duration The duration, either `"short"` (10ms) or `"long"` (100ms)
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function blink(color: Color, duration: "short" | "long"): void;
|
29
applications/system/js_app/packages/fz-sdk/package.json
Normal file
29
applications/system/js_app/packages/fz-sdk/package.json
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "@flipperdevices/fz-sdk",
|
||||
"version": "0.1.0",
|
||||
"description": "Type declarations and documentation for native JS modules available on Flipper Zero",
|
||||
"keywords": [
|
||||
"flipper",
|
||||
"flipper zero",
|
||||
"framework"
|
||||
],
|
||||
"author": "Flipper Devices",
|
||||
"license": "GPL-3.0-only",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/flipperdevices/flipperzero-firmware.git",
|
||||
"directory": "applications/system/js_app/packages/fz-sdk"
|
||||
},
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.24.0",
|
||||
"esbuild-plugin-tsc": "^0.4.0",
|
||||
"json5": "^2.2.3",
|
||||
"typedoc": "^0.26.10",
|
||||
"typedoc-material-theme": "^1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"prompts": "^2.4.2",
|
||||
"serialport": "^12.0.0"
|
||||
}
|
||||
}
|
896
applications/system/js_app/packages/fz-sdk/pnpm-lock.yaml
Normal file
896
applications/system/js_app/packages/fz-sdk/pnpm-lock.yaml
Normal file
|
@ -0,0 +1,896 @@
|
|||
lockfileVersion: '9.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
prompts:
|
||||
specifier: ^2.4.2
|
||||
version: 2.4.2
|
||||
serialport:
|
||||
specifier: ^12.0.0
|
||||
version: 12.0.0
|
||||
devDependencies:
|
||||
esbuild:
|
||||
specifier: ^0.24.0
|
||||
version: 0.24.0
|
||||
esbuild-plugin-tsc:
|
||||
specifier: ^0.4.0
|
||||
version: 0.4.0(typescript@5.6.3)
|
||||
json5:
|
||||
specifier: ^2.2.3
|
||||
version: 2.2.3
|
||||
typedoc:
|
||||
specifier: ^0.26.10
|
||||
version: 0.26.10(typescript@5.6.3)
|
||||
typedoc-material-theme:
|
||||
specifier: ^1.1.0
|
||||
version: 1.1.0(typedoc@0.26.10(typescript@5.6.3))
|
||||
|
||||
packages:
|
||||
|
||||
'@esbuild/aix-ppc64@0.24.0':
|
||||
resolution: {integrity: sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/android-arm64@0.24.0':
|
||||
resolution: {integrity: sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.24.0':
|
||||
resolution: {integrity: sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.24.0':
|
||||
resolution: {integrity: sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/darwin-arm64@0.24.0':
|
||||
resolution: {integrity: sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.24.0':
|
||||
resolution: {integrity: sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.24.0':
|
||||
resolution: {integrity: sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.24.0':
|
||||
resolution: {integrity: sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/linux-arm64@0.24.0':
|
||||
resolution: {integrity: sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.24.0':
|
||||
resolution: {integrity: sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.24.0':
|
||||
resolution: {integrity: sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.24.0':
|
||||
resolution: {integrity: sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.24.0':
|
||||
resolution: {integrity: sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.24.0':
|
||||
resolution: {integrity: sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.24.0':
|
||||
resolution: {integrity: sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.24.0':
|
||||
resolution: {integrity: sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.24.0':
|
||||
resolution: {integrity: sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/netbsd-x64@0.24.0':
|
||||
resolution: {integrity: sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.24.0':
|
||||
resolution: {integrity: sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.24.0':
|
||||
resolution: {integrity: sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/sunos-x64@0.24.0':
|
||||
resolution: {integrity: sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/win32-arm64@0.24.0':
|
||||
resolution: {integrity: sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.24.0':
|
||||
resolution: {integrity: sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.24.0':
|
||||
resolution: {integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@material/material-color-utilities@0.2.7':
|
||||
resolution: {integrity: sha512-0FCeqG6WvK4/Cc06F/xXMd/pv4FeisI0c1tUpBbfhA2n9Y8eZEv4Karjbmf2ZqQCPUWMrGp8A571tCjizxoTiQ==}
|
||||
|
||||
'@serialport/binding-mock@10.2.2':
|
||||
resolution: {integrity: sha512-HAFzGhk9OuFMpuor7aT5G1ChPgn5qSsklTFOTUX72Rl6p0xwcSVsRtG/xaGp6bxpN7fI9D/S8THLBWbBgS6ldw==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@serialport/bindings-cpp@12.0.1':
|
||||
resolution: {integrity: sha512-r2XOwY2dDvbW7dKqSPIk2gzsr6M6Qpe9+/Ngs94fNaNlcTRCV02PfaoDmRgcubpNVVcLATlxSxPTIDw12dbKOg==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
|
||||
'@serialport/bindings-interface@1.2.2':
|
||||
resolution: {integrity: sha512-CJaUd5bLvtM9c5dmO9rPBHPXTa9R2UwpkJ0wdh9JCYcbrPWsKz+ErvR0hBLeo7NPeiFdjFO4sonRljiw4d2XiA==}
|
||||
engines: {node: ^12.22 || ^14.13 || >=16}
|
||||
|
||||
'@serialport/parser-byte-length@12.0.0':
|
||||
resolution: {integrity: sha512-0ei0txFAj+s6FTiCJFBJ1T2hpKkX8Md0Pu6dqMrYoirjPskDLJRgZGLqoy3/lnU1bkvHpnJO+9oJ3PB9v8rNlg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@serialport/parser-cctalk@12.0.0':
|
||||
resolution: {integrity: sha512-0PfLzO9t2X5ufKuBO34DQKLXrCCqS9xz2D0pfuaLNeTkyGUBv426zxoMf3rsMRodDOZNbFblu3Ae84MOQXjnZw==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@serialport/parser-delimiter@11.0.0':
|
||||
resolution: {integrity: sha512-aZLJhlRTjSmEwllLG7S4J8s8ctRAS0cbvCpO87smLvl3e4BgzbVgF6Z6zaJd3Aji2uSiYgfedCdNc4L6W+1E2g==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@serialport/parser-delimiter@12.0.0':
|
||||
resolution: {integrity: sha512-gu26tVt5lQoybhorLTPsH2j2LnX3AOP2x/34+DUSTNaUTzu2fBXw+isVjQJpUBFWu6aeQRZw5bJol5X9Gxjblw==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@serialport/parser-inter-byte-timeout@12.0.0':
|
||||
resolution: {integrity: sha512-GnCh8K0NAESfhCuXAt+FfBRz1Cf9CzIgXfp7SdMgXwrtuUnCC/yuRTUFWRvuzhYKoAo1TL0hhUo77SFHUH1T/w==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@serialport/parser-packet-length@12.0.0':
|
||||
resolution: {integrity: sha512-p1hiCRqvGHHLCN/8ZiPUY/G0zrxd7gtZs251n+cfNTn+87rwcdUeu9Dps3Aadx30/sOGGFL6brIRGK4l/t7MuQ==}
|
||||
engines: {node: '>=8.6.0'}
|
||||
|
||||
'@serialport/parser-readline@11.0.0':
|
||||
resolution: {integrity: sha512-rRAivhRkT3YO28WjmmG4FQX6L+KMb5/ikhyylRfzWPw0nSXy97+u07peS9CbHqaNvJkMhH1locp2H36aGMOEIA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@serialport/parser-readline@12.0.0':
|
||||
resolution: {integrity: sha512-O7cywCWC8PiOMvo/gglEBfAkLjp/SENEML46BXDykfKP5mTPM46XMaX1L0waWU6DXJpBgjaL7+yX6VriVPbN4w==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@serialport/parser-ready@12.0.0':
|
||||
resolution: {integrity: sha512-ygDwj3O4SDpZlbrRUraoXIoIqb8sM7aMKryGjYTIF0JRnKeB1ys8+wIp0RFMdFbO62YriUDextHB5Um5cKFSWg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@serialport/parser-regex@12.0.0':
|
||||
resolution: {integrity: sha512-dCAVh4P/pZrLcPv9NJ2mvPRBg64L5jXuiRxIlyxxdZGH4WubwXVXY/kBTihQmiAMPxbT3yshSX8f2+feqWsxqA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@serialport/parser-slip-encoder@12.0.0':
|
||||
resolution: {integrity: sha512-0APxDGR9YvJXTRfY+uRGhzOhTpU5akSH183RUcwzN7QXh8/1jwFsFLCu0grmAUfi+fItCkR+Xr1TcNJLR13VNA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@serialport/parser-spacepacket@12.0.0':
|
||||
resolution: {integrity: sha512-dozONxhPC/78pntuxpz/NOtVps8qIc/UZzdc/LuPvVsqCoJXiRxOg6ZtCP/W58iibJDKPZPAWPGYeZt9DJxI+Q==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@serialport/stream@12.0.0':
|
||||
resolution: {integrity: sha512-9On64rhzuqKdOQyiYLYv2lQOh3TZU/D3+IWCR5gk0alPel2nwpp4YwDEGiUBfrQZEdQ6xww0PWkzqth4wqwX3Q==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@shikijs/core@1.22.0':
|
||||
resolution: {integrity: sha512-S8sMe4q71TJAW+qG93s5VaiihujRK6rqDFqBnxqvga/3LvqHEnxqBIOPkt//IdXVtHkQWKu4nOQNk0uBGicU7Q==}
|
||||
|
||||
'@shikijs/engine-javascript@1.22.0':
|
||||
resolution: {integrity: sha512-AeEtF4Gcck2dwBqCFUKYfsCq0s+eEbCEbkUuFou53NZ0sTGnJnJ/05KHQFZxpii5HMXbocV9URYVowOP2wH5kw==}
|
||||
|
||||
'@shikijs/engine-oniguruma@1.22.0':
|
||||
resolution: {integrity: sha512-5iBVjhu/DYs1HB0BKsRRFipRrD7rqjxlWTj4F2Pf+nQSPqc3kcyqFFeZXnBMzDf0HdqaFVvhDRAGiYNvyLP+Mw==}
|
||||
|
||||
'@shikijs/types@1.22.0':
|
||||
resolution: {integrity: sha512-Fw/Nr7FGFhlQqHfxzZY8Cwtwk5E9nKDUgeLjZgt3UuhcM3yJR9xj3ZGNravZZok8XmEZMiYkSMTPlPkULB8nww==}
|
||||
|
||||
'@shikijs/vscode-textmate@9.3.0':
|
||||
resolution: {integrity: sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==}
|
||||
|
||||
'@types/hast@3.0.4':
|
||||
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
|
||||
|
||||
'@types/mdast@4.0.4':
|
||||
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
|
||||
|
||||
'@types/unist@3.0.3':
|
||||
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
|
||||
|
||||
'@ungap/structured-clone@1.2.0':
|
||||
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
|
||||
|
||||
argparse@2.0.1:
|
||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||
|
||||
balanced-match@1.0.2:
|
||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||
|
||||
brace-expansion@2.0.1:
|
||||
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
|
||||
|
||||
ccount@2.0.1:
|
||||
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
|
||||
|
||||
character-entities-html4@2.1.0:
|
||||
resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==}
|
||||
|
||||
character-entities-legacy@3.0.0:
|
||||
resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==}
|
||||
|
||||
comma-separated-tokens@2.0.3:
|
||||
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
|
||||
|
||||
debug@4.3.4:
|
||||
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
|
||||
engines: {node: '>=6.0'}
|
||||
peerDependencies:
|
||||
supports-color: '*'
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
|
||||
dequal@2.0.3:
|
||||
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
devlop@1.1.0:
|
||||
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
|
||||
|
||||
entities@4.5.0:
|
||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
esbuild-plugin-tsc@0.4.0:
|
||||
resolution: {integrity: sha512-q9gWIovt1nkwchMLc2zhyksaiHOv3kDK4b0AUol8lkMCRhJ1zavgfb2fad6BKp7FT9rh/OHmEBXVjczLoi/0yw==}
|
||||
peerDependencies:
|
||||
typescript: ^4.0.0 || ^5.0.0
|
||||
|
||||
esbuild@0.24.0:
|
||||
resolution: {integrity: sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
hast-util-to-html@9.0.3:
|
||||
resolution: {integrity: sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==}
|
||||
|
||||
hast-util-whitespace@3.0.0:
|
||||
resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==}
|
||||
|
||||
html-void-elements@3.0.0:
|
||||
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
|
||||
|
||||
json5@2.2.3:
|
||||
resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
|
||||
engines: {node: '>=6'}
|
||||
hasBin: true
|
||||
|
||||
kleur@3.0.3:
|
||||
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
linkify-it@5.0.0:
|
||||
resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
|
||||
|
||||
lunr@2.3.9:
|
||||
resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==}
|
||||
|
||||
markdown-it@14.1.0:
|
||||
resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
|
||||
hasBin: true
|
||||
|
||||
mdast-util-to-hast@13.2.0:
|
||||
resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==}
|
||||
|
||||
mdurl@2.0.0:
|
||||
resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
|
||||
|
||||
micromark-util-character@2.1.0:
|
||||
resolution: {integrity: sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==}
|
||||
|
||||
micromark-util-encode@2.0.0:
|
||||
resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==}
|
||||
|
||||
micromark-util-sanitize-uri@2.0.0:
|
||||
resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==}
|
||||
|
||||
micromark-util-symbol@2.0.0:
|
||||
resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==}
|
||||
|
||||
micromark-util-types@2.0.0:
|
||||
resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==}
|
||||
|
||||
minimatch@9.0.5:
|
||||
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
ms@2.1.2:
|
||||
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||
|
||||
node-addon-api@7.0.0:
|
||||
resolution: {integrity: sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==}
|
||||
|
||||
node-gyp-build@4.6.0:
|
||||
resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==}
|
||||
hasBin: true
|
||||
|
||||
oniguruma-to-js@0.4.3:
|
||||
resolution: {integrity: sha512-X0jWUcAlxORhOqqBREgPMgnshB7ZGYszBNspP+tS9hPD3l13CdaXcHbgImoHUHlrvGx/7AvFEkTRhAGYh+jzjQ==}
|
||||
|
||||
prompts@2.4.2:
|
||||
resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
property-information@6.5.0:
|
||||
resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
|
||||
|
||||
punycode.js@2.3.1:
|
||||
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
regex@4.3.3:
|
||||
resolution: {integrity: sha512-r/AadFO7owAq1QJVeZ/nq9jNS1vyZt+6t1p/E59B56Rn2GCya+gr1KSyOzNL/er+r+B7phv5jG2xU2Nz1YkmJg==}
|
||||
|
||||
serialport@12.0.0:
|
||||
resolution: {integrity: sha512-AmH3D9hHPFmnF/oq/rvigfiAouAKyK/TjnrkwZRYSFZxNggJxwvbAbfYrLeuvq7ktUdhuHdVdSjj852Z55R+uA==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
|
||||
shiki@1.22.0:
|
||||
resolution: {integrity: sha512-/t5LlhNs+UOKQCYBtl5ZsH/Vclz73GIqT2yQsCBygr8L/ppTdmpL4w3kPLoZJbMKVWtoG77Ue1feOjZfDxvMkw==}
|
||||
|
||||
sisteransi@1.0.5:
|
||||
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
|
||||
|
||||
space-separated-tokens@2.0.2:
|
||||
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
|
||||
|
||||
stringify-entities@4.0.4:
|
||||
resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
|
||||
|
||||
strip-comments@2.0.1:
|
||||
resolution: {integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
trim-lines@3.0.1:
|
||||
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
|
||||
|
||||
typedoc-material-theme@1.1.0:
|
||||
resolution: {integrity: sha512-LLWGVb8w+i+QGnsu/a0JKjcuzndFQt/UeGVOQz0HFFGGocROEHv5QYudIACrj+phL2LDwH05tJx0Ob3pYYH2UA==}
|
||||
engines: {node: '>=18.0.0', npm: '>=8.6.0'}
|
||||
peerDependencies:
|
||||
typedoc: ^0.25.13 || ^0.26.3
|
||||
|
||||
typedoc@0.26.10:
|
||||
resolution: {integrity: sha512-xLmVKJ8S21t+JeuQLNueebEuTVphx6IrP06CdV7+0WVflUSW3SPmR+h1fnWVdAR/FQePEgsSWCUHXqKKjzuUAw==}
|
||||
engines: {node: '>= 18'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x
|
||||
|
||||
typescript@5.6.3:
|
||||
resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
uc.micro@2.1.0:
|
||||
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
|
||||
|
||||
unist-util-is@6.0.0:
|
||||
resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
|
||||
|
||||
unist-util-position@5.0.0:
|
||||
resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==}
|
||||
|
||||
unist-util-stringify-position@4.0.0:
|
||||
resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==}
|
||||
|
||||
unist-util-visit-parents@6.0.1:
|
||||
resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==}
|
||||
|
||||
unist-util-visit@5.0.0:
|
||||
resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
|
||||
|
||||
vfile-message@4.0.2:
|
||||
resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
|
||||
|
||||
vfile@6.0.3:
|
||||
resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
|
||||
|
||||
yaml@2.6.0:
|
||||
resolution: {integrity: sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==}
|
||||
engines: {node: '>= 14'}
|
||||
hasBin: true
|
||||
|
||||
zwitch@2.0.4:
|
||||
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
||||
|
||||
snapshots:
|
||||
|
||||
'@esbuild/aix-ppc64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.24.0':
|
||||
optional: true
|
||||
|
||||
'@material/material-color-utilities@0.2.7': {}
|
||||
|
||||
'@serialport/binding-mock@10.2.2':
|
||||
dependencies:
|
||||
'@serialport/bindings-interface': 1.2.2
|
||||
debug: 4.3.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@serialport/bindings-cpp@12.0.1':
|
||||
dependencies:
|
||||
'@serialport/bindings-interface': 1.2.2
|
||||
'@serialport/parser-readline': 11.0.0
|
||||
debug: 4.3.4
|
||||
node-addon-api: 7.0.0
|
||||
node-gyp-build: 4.6.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@serialport/bindings-interface@1.2.2': {}
|
||||
|
||||
'@serialport/parser-byte-length@12.0.0': {}
|
||||
|
||||
'@serialport/parser-cctalk@12.0.0': {}
|
||||
|
||||
'@serialport/parser-delimiter@11.0.0': {}
|
||||
|
||||
'@serialport/parser-delimiter@12.0.0': {}
|
||||
|
||||
'@serialport/parser-inter-byte-timeout@12.0.0': {}
|
||||
|
||||
'@serialport/parser-packet-length@12.0.0': {}
|
||||
|
||||
'@serialport/parser-readline@11.0.0':
|
||||
dependencies:
|
||||
'@serialport/parser-delimiter': 11.0.0
|
||||
|
||||
'@serialport/parser-readline@12.0.0':
|
||||
dependencies:
|
||||
'@serialport/parser-delimiter': 12.0.0
|
||||
|
||||
'@serialport/parser-ready@12.0.0': {}
|
||||
|
||||
'@serialport/parser-regex@12.0.0': {}
|
||||
|
||||
'@serialport/parser-slip-encoder@12.0.0': {}
|
||||
|
||||
'@serialport/parser-spacepacket@12.0.0': {}
|
||||
|
||||
'@serialport/stream@12.0.0':
|
||||
dependencies:
|
||||
'@serialport/bindings-interface': 1.2.2
|
||||
debug: 4.3.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@shikijs/core@1.22.0':
|
||||
dependencies:
|
||||
'@shikijs/engine-javascript': 1.22.0
|
||||
'@shikijs/engine-oniguruma': 1.22.0
|
||||
'@shikijs/types': 1.22.0
|
||||
'@shikijs/vscode-textmate': 9.3.0
|
||||
'@types/hast': 3.0.4
|
||||
hast-util-to-html: 9.0.3
|
||||
|
||||
'@shikijs/engine-javascript@1.22.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 1.22.0
|
||||
'@shikijs/vscode-textmate': 9.3.0
|
||||
oniguruma-to-js: 0.4.3
|
||||
|
||||
'@shikijs/engine-oniguruma@1.22.0':
|
||||
dependencies:
|
||||
'@shikijs/types': 1.22.0
|
||||
'@shikijs/vscode-textmate': 9.3.0
|
||||
|
||||
'@shikijs/types@1.22.0':
|
||||
dependencies:
|
||||
'@shikijs/vscode-textmate': 9.3.0
|
||||
'@types/hast': 3.0.4
|
||||
|
||||
'@shikijs/vscode-textmate@9.3.0': {}
|
||||
|
||||
'@types/hast@3.0.4':
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
|
||||
'@types/mdast@4.0.4':
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
|
||||
'@types/unist@3.0.3': {}
|
||||
|
||||
'@ungap/structured-clone@1.2.0': {}
|
||||
|
||||
argparse@2.0.1: {}
|
||||
|
||||
balanced-match@1.0.2: {}
|
||||
|
||||
brace-expansion@2.0.1:
|
||||
dependencies:
|
||||
balanced-match: 1.0.2
|
||||
|
||||
ccount@2.0.1: {}
|
||||
|
||||
character-entities-html4@2.1.0: {}
|
||||
|
||||
character-entities-legacy@3.0.0: {}
|
||||
|
||||
comma-separated-tokens@2.0.3: {}
|
||||
|
||||
debug@4.3.4:
|
||||
dependencies:
|
||||
ms: 2.1.2
|
||||
|
||||
dequal@2.0.3: {}
|
||||
|
||||
devlop@1.1.0:
|
||||
dependencies:
|
||||
dequal: 2.0.3
|
||||
|
||||
entities@4.5.0: {}
|
||||
|
||||
esbuild-plugin-tsc@0.4.0(typescript@5.6.3):
|
||||
dependencies:
|
||||
strip-comments: 2.0.1
|
||||
typescript: 5.6.3
|
||||
|
||||
esbuild@0.24.0:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.24.0
|
||||
'@esbuild/android-arm': 0.24.0
|
||||
'@esbuild/android-arm64': 0.24.0
|
||||
'@esbuild/android-x64': 0.24.0
|
||||
'@esbuild/darwin-arm64': 0.24.0
|
||||
'@esbuild/darwin-x64': 0.24.0
|
||||
'@esbuild/freebsd-arm64': 0.24.0
|
||||
'@esbuild/freebsd-x64': 0.24.0
|
||||
'@esbuild/linux-arm': 0.24.0
|
||||
'@esbuild/linux-arm64': 0.24.0
|
||||
'@esbuild/linux-ia32': 0.24.0
|
||||
'@esbuild/linux-loong64': 0.24.0
|
||||
'@esbuild/linux-mips64el': 0.24.0
|
||||
'@esbuild/linux-ppc64': 0.24.0
|
||||
'@esbuild/linux-riscv64': 0.24.0
|
||||
'@esbuild/linux-s390x': 0.24.0
|
||||
'@esbuild/linux-x64': 0.24.0
|
||||
'@esbuild/netbsd-x64': 0.24.0
|
||||
'@esbuild/openbsd-arm64': 0.24.0
|
||||
'@esbuild/openbsd-x64': 0.24.0
|
||||
'@esbuild/sunos-x64': 0.24.0
|
||||
'@esbuild/win32-arm64': 0.24.0
|
||||
'@esbuild/win32-ia32': 0.24.0
|
||||
'@esbuild/win32-x64': 0.24.0
|
||||
|
||||
hast-util-to-html@9.0.3:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
'@types/unist': 3.0.3
|
||||
ccount: 2.0.1
|
||||
comma-separated-tokens: 2.0.3
|
||||
hast-util-whitespace: 3.0.0
|
||||
html-void-elements: 3.0.0
|
||||
mdast-util-to-hast: 13.2.0
|
||||
property-information: 6.5.0
|
||||
space-separated-tokens: 2.0.2
|
||||
stringify-entities: 4.0.4
|
||||
zwitch: 2.0.4
|
||||
|
||||
hast-util-whitespace@3.0.0:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
|
||||
html-void-elements@3.0.0: {}
|
||||
|
||||
json5@2.2.3: {}
|
||||
|
||||
kleur@3.0.3: {}
|
||||
|
||||
linkify-it@5.0.0:
|
||||
dependencies:
|
||||
uc.micro: 2.1.0
|
||||
|
||||
lunr@2.3.9: {}
|
||||
|
||||
markdown-it@14.1.0:
|
||||
dependencies:
|
||||
argparse: 2.0.1
|
||||
entities: 4.5.0
|
||||
linkify-it: 5.0.0
|
||||
mdurl: 2.0.0
|
||||
punycode.js: 2.3.1
|
||||
uc.micro: 2.1.0
|
||||
|
||||
mdast-util-to-hast@13.2.0:
|
||||
dependencies:
|
||||
'@types/hast': 3.0.4
|
||||
'@types/mdast': 4.0.4
|
||||
'@ungap/structured-clone': 1.2.0
|
||||
devlop: 1.1.0
|
||||
micromark-util-sanitize-uri: 2.0.0
|
||||
trim-lines: 3.0.1
|
||||
unist-util-position: 5.0.0
|
||||
unist-util-visit: 5.0.0
|
||||
vfile: 6.0.3
|
||||
|
||||
mdurl@2.0.0: {}
|
||||
|
||||
micromark-util-character@2.1.0:
|
||||
dependencies:
|
||||
micromark-util-symbol: 2.0.0
|
||||
micromark-util-types: 2.0.0
|
||||
|
||||
micromark-util-encode@2.0.0: {}
|
||||
|
||||
micromark-util-sanitize-uri@2.0.0:
|
||||
dependencies:
|
||||
micromark-util-character: 2.1.0
|
||||
micromark-util-encode: 2.0.0
|
||||
micromark-util-symbol: 2.0.0
|
||||
|
||||
micromark-util-symbol@2.0.0: {}
|
||||
|
||||
micromark-util-types@2.0.0: {}
|
||||
|
||||
minimatch@9.0.5:
|
||||
dependencies:
|
||||
brace-expansion: 2.0.1
|
||||
|
||||
ms@2.1.2: {}
|
||||
|
||||
node-addon-api@7.0.0: {}
|
||||
|
||||
node-gyp-build@4.6.0: {}
|
||||
|
||||
oniguruma-to-js@0.4.3:
|
||||
dependencies:
|
||||
regex: 4.3.3
|
||||
|
||||
prompts@2.4.2:
|
||||
dependencies:
|
||||
kleur: 3.0.3
|
||||
sisteransi: 1.0.5
|
||||
|
||||
property-information@6.5.0: {}
|
||||
|
||||
punycode.js@2.3.1: {}
|
||||
|
||||
regex@4.3.3: {}
|
||||
|
||||
serialport@12.0.0:
|
||||
dependencies:
|
||||
'@serialport/binding-mock': 10.2.2
|
||||
'@serialport/bindings-cpp': 12.0.1
|
||||
'@serialport/parser-byte-length': 12.0.0
|
||||
'@serialport/parser-cctalk': 12.0.0
|
||||
'@serialport/parser-delimiter': 12.0.0
|
||||
'@serialport/parser-inter-byte-timeout': 12.0.0
|
||||
'@serialport/parser-packet-length': 12.0.0
|
||||
'@serialport/parser-readline': 12.0.0
|
||||
'@serialport/parser-ready': 12.0.0
|
||||
'@serialport/parser-regex': 12.0.0
|
||||
'@serialport/parser-slip-encoder': 12.0.0
|
||||
'@serialport/parser-spacepacket': 12.0.0
|
||||
'@serialport/stream': 12.0.0
|
||||
debug: 4.3.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
shiki@1.22.0:
|
||||
dependencies:
|
||||
'@shikijs/core': 1.22.0
|
||||
'@shikijs/engine-javascript': 1.22.0
|
||||
'@shikijs/engine-oniguruma': 1.22.0
|
||||
'@shikijs/types': 1.22.0
|
||||
'@shikijs/vscode-textmate': 9.3.0
|
||||
'@types/hast': 3.0.4
|
||||
|
||||
sisteransi@1.0.5: {}
|
||||
|
||||
space-separated-tokens@2.0.2: {}
|
||||
|
||||
stringify-entities@4.0.4:
|
||||
dependencies:
|
||||
character-entities-html4: 2.1.0
|
||||
character-entities-legacy: 3.0.0
|
||||
|
||||
strip-comments@2.0.1: {}
|
||||
|
||||
trim-lines@3.0.1: {}
|
||||
|
||||
typedoc-material-theme@1.1.0(typedoc@0.26.10(typescript@5.6.3)):
|
||||
dependencies:
|
||||
'@material/material-color-utilities': 0.2.7
|
||||
typedoc: 0.26.10(typescript@5.6.3)
|
||||
|
||||
typedoc@0.26.10(typescript@5.6.3):
|
||||
dependencies:
|
||||
lunr: 2.3.9
|
||||
markdown-it: 14.1.0
|
||||
minimatch: 9.0.5
|
||||
shiki: 1.22.0
|
||||
typescript: 5.6.3
|
||||
yaml: 2.6.0
|
||||
|
||||
typescript@5.6.3: {}
|
||||
|
||||
uc.micro@2.1.0: {}
|
||||
|
||||
unist-util-is@6.0.0:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
|
||||
unist-util-position@5.0.0:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
|
||||
unist-util-stringify-position@4.0.0:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
|
||||
unist-util-visit-parents@6.0.1:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
unist-util-is: 6.0.0
|
||||
|
||||
unist-util-visit@5.0.0:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
unist-util-is: 6.0.0
|
||||
unist-util-visit-parents: 6.0.1
|
||||
|
||||
vfile-message@4.0.2:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
unist-util-stringify-position: 4.0.0
|
||||
|
||||
vfile@6.0.3:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
vfile-message: 4.0.2
|
||||
|
||||
yaml@2.6.0: {}
|
||||
|
||||
zwitch@2.0.4: {}
|
176
applications/system/js_app/packages/fz-sdk/sdk.js
Normal file
176
applications/system/js_app/packages/fz-sdk/sdk.js
Normal file
|
@ -0,0 +1,176 @@
|
|||
#!/usr/bin/env node
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { SerialPort } from "serialport";
|
||||
import prompts from "prompts";
|
||||
import esbuild from "esbuild";
|
||||
import json5 from "json5";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
async function build(config) {
|
||||
await esbuild.build({
|
||||
entryPoints: ["./dist/index.js"],
|
||||
outfile: config.output,
|
||||
tsconfig: "./tsconfig.json",
|
||||
format: "cjs",
|
||||
bundle: true,
|
||||
minify: config.minify,
|
||||
external: [
|
||||
"@flipperdevices/fz-sdk/*"
|
||||
],
|
||||
supported: {
|
||||
"array-spread": false,
|
||||
"arrow": false,
|
||||
"async-await": false,
|
||||
"async-generator": false,
|
||||
"bigint": false,
|
||||
"class": false,
|
||||
"const-and-let": true,
|
||||
"decorators": false,
|
||||
"default-argument": false,
|
||||
"destructuring": false,
|
||||
"dynamic-import": false,
|
||||
"exponent-operator": false,
|
||||
"export-star-as": false,
|
||||
"for-await": false,
|
||||
"for-of": false,
|
||||
"function-name-configurable": false,
|
||||
"function-or-class-property-access": false,
|
||||
"generator": false,
|
||||
"hashbang": false,
|
||||
"import-assertions": false,
|
||||
"import-meta": false,
|
||||
"inline-script": false,
|
||||
"logical-assignment": false,
|
||||
"nested-rest-binding": false,
|
||||
"new-target": false,
|
||||
"node-colon-prefix-import": false,
|
||||
"node-colon-prefix-require": false,
|
||||
"nullish-coalescing": false,
|
||||
"object-accessors": false,
|
||||
"object-extensions": false,
|
||||
"object-rest-spread": false,
|
||||
"optional-catch-binding": false,
|
||||
"optional-chain": false,
|
||||
"regexp-dot-all-flag": false,
|
||||
"regexp-lookbehind-assertions": false,
|
||||
"regexp-match-indices": false,
|
||||
"regexp-named-capture-groups": false,
|
||||
"regexp-set-notation": false,
|
||||
"regexp-sticky-and-unicode-flags": false,
|
||||
"regexp-unicode-property-escapes": false,
|
||||
"rest-argument": false,
|
||||
"template-literal": false,
|
||||
"top-level-await": false,
|
||||
"typeof-exotic-object-is-object": false,
|
||||
"unicode-escapes": false,
|
||||
"using": false,
|
||||
},
|
||||
});
|
||||
|
||||
let outContents = fs.readFileSync(config.output, "utf8");
|
||||
outContents = "let exports = {};\n" + outContents;
|
||||
|
||||
if (config.enforceSdkVersion) {
|
||||
const version = json5.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf8")).version;
|
||||
let [major, minor, _] = version.split(".");
|
||||
outContents = `checkSdkCompatibility(${major}, ${minor});\n${outContents}`;
|
||||
}
|
||||
|
||||
fs.writeFileSync(config.output, outContents);
|
||||
}
|
||||
|
||||
async function upload(config) {
|
||||
const appFile = fs.readFileSync(config.input, "utf8");
|
||||
const flippers = (await SerialPort.list()).filter(x => x.serialNumber?.startsWith("flip_"));
|
||||
|
||||
if (!flippers) {
|
||||
console.error("No Flippers found");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let portPath = flippers[0].path;
|
||||
if (flippers.length > 1) {
|
||||
port = (await prompts([{
|
||||
type: "select",
|
||||
name: "port",
|
||||
message: "Select Flipper to run the app on",
|
||||
choices: flippers.map(x => ({ title: x.serialNumber.replace("flip_", ""), value: x.path })),
|
||||
}])).port;
|
||||
}
|
||||
|
||||
console.log(`Connecting to Flipper at ${portPath}`);
|
||||
let port = new SerialPort({ path: portPath, baudRate: 230400 });
|
||||
let received = "";
|
||||
let lastMatch = 0;
|
||||
async function waitFor(string, timeoutMs) {
|
||||
return new Promise((resolve, _reject) => {
|
||||
let timeout = undefined;
|
||||
if (timeoutMs) {
|
||||
timeout = setTimeout(() => {
|
||||
console.error("Error: timeout");
|
||||
process.exit(1);
|
||||
}, timeoutMs);
|
||||
}
|
||||
setInterval(() => {
|
||||
let idx = received.indexOf(string, lastMatch);
|
||||
if (idx !== -1) {
|
||||
lastMatch = idx;
|
||||
if (timeoutMs)
|
||||
clearTimeout(timeout);
|
||||
resolve();
|
||||
}
|
||||
}, 50);
|
||||
});
|
||||
}
|
||||
port.on("data", (data) => {
|
||||
received += data.toString();
|
||||
});
|
||||
|
||||
await waitFor(">: ", 1000);
|
||||
console.log("Uploading application file");
|
||||
port.write(`storage remove ${config.output}\x0d`);
|
||||
port.drain();
|
||||
await waitFor(">: ", 1000);
|
||||
port.write(`storage write_chunk ${config.output} ${appFile.length}\x0d`);
|
||||
await waitFor("Ready", 1000);
|
||||
port.write(appFile);
|
||||
port.drain();
|
||||
await waitFor(">: ", 1000);
|
||||
|
||||
console.log("Launching application");
|
||||
port.write(`js ${config.output}\x0d`);
|
||||
port.drain();
|
||||
|
||||
await waitFor("Running", 1000);
|
||||
process.stdout.write(received.slice(lastMatch));
|
||||
port.on("data", (data) => {
|
||||
process.stdout.write(data.toString());
|
||||
});
|
||||
process.on("exit", () => {
|
||||
port.write("\x03");
|
||||
});
|
||||
|
||||
await waitFor("Script done!", 0);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const commands = {
|
||||
"build": build,
|
||||
"upload": upload,
|
||||
};
|
||||
|
||||
const config = json5.parse(fs.readFileSync("./fz-sdk.config.json5", "utf8"));
|
||||
const command = process.argv[2];
|
||||
|
||||
if (!Object.keys(commands).includes(command)) {
|
||||
console.error(`Unknown command ${command}. Supported: ${Object.keys(commands).join(", ")}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await commands[command](config[command]);
|
||||
})();
|
|
@ -1,7 +1,14 @@
|
|||
/**
|
||||
* Module for accessing the serial port
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Initializes the serial port
|
||||
* @param port The port to initialize (`"lpuart"` or `"start"`)
|
||||
* @param baudRate
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function setup(port: "lpuart" | "usart", baudRate: number): void;
|
||||
|
||||
|
@ -13,6 +20,7 @@ export declare function setup(port: "lpuart" | "usart", baudRate: number): void;
|
|||
* - Arrays of numbers will get sent as a sequence of bytes.
|
||||
* - `ArrayBuffer`s and `TypedArray`s will be sent as a sequence
|
||||
* of bytes.
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function write<E extends ElementType>(value: string | number | number[] | ArrayBuffer | TypedArray<E>): void;
|
||||
|
||||
|
@ -24,6 +32,7 @@ export declare function write<E extends ElementType>(value: string | number | nu
|
|||
* unset, the function will wait forever.
|
||||
* @returns The received data interpreted as ASCII, or `undefined` if 0 bytes
|
||||
* were read.
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function read(length: number, timeout?: number): string | undefined;
|
||||
|
||||
|
@ -39,6 +48,7 @@ export declare function read(length: number, timeout?: number): string | undefin
|
|||
* applies to characters, not entire strings.
|
||||
* @returns The received data interpreted as ASCII, or `undefined` if 0 bytes
|
||||
* were read.
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function readln(timeout?: number): string;
|
||||
|
||||
|
@ -50,6 +60,7 @@ export declare function readln(timeout?: number): string;
|
|||
* unset, the function will wait forever.
|
||||
* @returns The received data as an ArrayBuffer, or `undefined` if 0 bytes were
|
||||
* read.
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function readBytes(length: number, timeout?: number): ArrayBuffer;
|
||||
|
||||
|
@ -73,5 +84,6 @@ export declare function readBytes(length: number, timeout?: number): ArrayBuffer
|
|||
* @returns The index of the matched pattern if multiple were provided, or 0 if
|
||||
* only one was provided and it matched, or `undefined` if none of the
|
||||
* patterns matched.
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function expect(patterns: string | number[] | string[] | number[][], timeout?: number): number | undefined;
|
|
@ -1,8 +1,15 @@
|
|||
/**
|
||||
* Module for accessing the filesystem
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
/**
|
||||
* File readability mode:
|
||||
* - `"r"`: read-only
|
||||
* - `"w"`: write-only
|
||||
* - `"rw"`: read-write
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export type AccessMode = "r" | "w" | "rw";
|
||||
|
||||
|
@ -13,53 +20,78 @@ export type AccessMode = "r" | "w" | "rw";
|
|||
* - `"open_append"`: open file and set r/w pointer to EOF, or create a new one if it doesn't exist
|
||||
* - `"create_new"`: create new file or fail if it exists
|
||||
* - `"create_always"`: truncate and open file, or create a new empty one if it doesn't exist
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export type OpenMode = "open_existing" | "open_always" | "open_append" | "create_new" | "create_always";
|
||||
|
||||
/** Standard UNIX timestamp */
|
||||
/**
|
||||
* Standard UNIX timestamp
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export type Timestamp = number;
|
||||
|
||||
/** File information structure */
|
||||
/**
|
||||
* File information structure
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare class FileInfo {
|
||||
/**
|
||||
* Full path (e.g. "/ext/test", returned by `stat`) or file name
|
||||
* (e.g. "test", returned by `readDirectory`)
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
path: string;
|
||||
/**
|
||||
* Is the file a directory?
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
isDirectory: boolean;
|
||||
/**
|
||||
* File size in bytes, or 0 in the case of directories
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
size: number;
|
||||
/**
|
||||
* Time of last access as a UNIX timestamp
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
accessTime: Timestamp;
|
||||
}
|
||||
|
||||
/** Filesystem information structure */
|
||||
/**
|
||||
* Filesystem information structure
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare class FsInfo {
|
||||
/** Total size of the filesystem, in bytes */
|
||||
/**
|
||||
* Total size of the filesystem, in bytes
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
totalSpace: number;
|
||||
/** Free space in the filesystem, in bytes */
|
||||
/**
|
||||
* Free space in the filesystem, in bytes
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
freeSpace: number;
|
||||
}
|
||||
|
||||
// file operations
|
||||
|
||||
/** File class */
|
||||
/**
|
||||
* File class
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare class File {
|
||||
/**
|
||||
* Closes the file. After this method is called, all other operations
|
||||
* related to this file become unavailable.
|
||||
* @returns `true` on success, `false` on failure
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
close(): boolean;
|
||||
/**
|
||||
* Is the file currently open?
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
isOpen(): boolean;
|
||||
/**
|
||||
|
@ -70,6 +102,7 @@ export declare class File {
|
|||
* @returns an `ArrayBuf` if the mode is `"binary"`, a `string` if the mode
|
||||
* is `ascii`. The number of bytes that was actually read may be
|
||||
* fewer than requested.
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
read<T extends ArrayBuffer | string>(mode: T extends ArrayBuffer ? "binary" : "ascii", bytes: number): T;
|
||||
/**
|
||||
|
@ -77,36 +110,43 @@ export declare class File {
|
|||
* @param data The data to write: a string that will be ASCII-encoded, or an
|
||||
* ArrayBuf
|
||||
* @returns the amount of bytes that was actually written
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
write(data: ArrayBuffer | string): number;
|
||||
/**
|
||||
* Moves the R/W pointer forward
|
||||
* @param bytes How many bytes to move the pointer forward by
|
||||
* @returns `true` on success, `false` on failure
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
seekRelative(bytes: number): boolean;
|
||||
/**
|
||||
* Moves the R/W pointer to an absolute position inside the file
|
||||
* @param bytes The position inside the file
|
||||
* @returns `true` on success, `false` on failure
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
seekAbsolute(bytes: number): boolean;
|
||||
/**
|
||||
* Gets the absolute position of the R/W pointer in bytes
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
tell(): number;
|
||||
/**
|
||||
* Discards the data after the current position of the R/W pointer in a file
|
||||
* opened in either write-only or read-write mode.
|
||||
* @returns `true` on success, `false` on failure
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
truncate(): boolean;
|
||||
/**
|
||||
* Reads the total size of the file in bytes
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
size(): number;
|
||||
/**
|
||||
* Detects whether the R/W pointer has reached the end of the file
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
eof(): boolean;
|
||||
/**
|
||||
|
@ -115,6 +155,7 @@ export declare class File {
|
|||
* @param dest The file to copy the bytes into
|
||||
* @param bytes The number of bytes to copy
|
||||
* @returns `true` on success, `false` on failure
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
copyTo(dest: File, bytes: number): boolean;
|
||||
}
|
||||
|
@ -126,12 +167,14 @@ export declare class File {
|
|||
* @param openMode `"open_existing"`, `"open_always"`, `"open_append"`,
|
||||
* `"create_new"` or `"create_always"`; see `OpenMode`
|
||||
* @returns a `File` on success, or `undefined` on failure
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function openFile(path: string, accessMode: AccessMode, openMode: OpenMode): File | undefined;
|
||||
/**
|
||||
* Detects whether a file exists
|
||||
* @param path The path to the file
|
||||
* @returns `true` on success, `false` on failure
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function fileExists(path: string): boolean;
|
||||
|
||||
|
@ -142,17 +185,20 @@ export declare function fileExists(path: string): boolean;
|
|||
* @param path The path to the directory
|
||||
* @returns Array of `FileInfo` structures with directory entries,
|
||||
* or `undefined` on failure
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function readDirectory(path: string): FileInfo[] | undefined;
|
||||
/**
|
||||
* Detects whether a directory exists
|
||||
* @param path The path to the directory
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function directoryExists(path: string): boolean;
|
||||
/**
|
||||
* Creates an empty directory
|
||||
* @param path The path to the new directory
|
||||
* @returns `true` on success, `false` on failure
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function makeDirectory(path: string): boolean;
|
||||
|
||||
|
@ -161,24 +207,28 @@ export declare function makeDirectory(path: string): boolean;
|
|||
/**
|
||||
* Detects whether a file or a directory exists
|
||||
* @param path The path to the file or directory
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function fileOrDirExists(path: string): boolean;
|
||||
/**
|
||||
* Acquires metadata about a file or directory
|
||||
* @param path The path to the file or directory
|
||||
* @returns A `FileInfo` structure or `undefined` on failure
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function stat(path: string): FileInfo | undefined;
|
||||
/**
|
||||
* Removes a file or an empty directory
|
||||
* @param path The path to the file or directory
|
||||
* @returns `true` on success, `false` on failure
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function remove(path: string): boolean;
|
||||
/**
|
||||
* Removes a file or recursively removes a possibly non-empty directory
|
||||
* @param path The path to the file or directory
|
||||
* @returns `true` on success, `false` on failure
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function rmrf(path: string): boolean;
|
||||
/**
|
||||
|
@ -187,6 +237,7 @@ export declare function rmrf(path: string): boolean;
|
|||
* @param newPath The new path that the file or directory will become accessible
|
||||
* under
|
||||
* @returns `true` on success, `false` on failure
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function rename(oldPath: string, newPath: string): boolean;
|
||||
/**
|
||||
|
@ -194,11 +245,13 @@ export declare function rename(oldPath: string, newPath: string): boolean;
|
|||
* @param oldPath The original path to the file or directory
|
||||
* @param newPath The new path that the copy of the file or directory will be
|
||||
* accessible under
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function copy(oldPath: string, newPath: string): boolean;
|
||||
/**
|
||||
* Fetches generic information about a filesystem
|
||||
* @param filesystem The path to the filesystem (e.g. `"/ext"` or `"/int"`)
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function fsInfo(filesystem: string): FsInfo | undefined;
|
||||
/**
|
||||
|
@ -218,6 +271,7 @@ export declare function fsInfo(filesystem: string): FsInfo | undefined;
|
|||
* @param maxLen The maximum length of the filename with the numeric suffix
|
||||
* @returns The base of the filename with the next available numeric suffix,
|
||||
* without the extension or the base directory.
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function nextAvailableFilename(dirPath: string, fileName: string, fileExt: string, maxLen: number): string;
|
||||
|
||||
|
@ -226,6 +280,7 @@ export declare function nextAvailableFilename(dirPath: string, fileName: string,
|
|||
/**
|
||||
* Determines whether the two paths are equivalent. Respects filesystem-defined
|
||||
* path equivalence rules.
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function arePathsEqual(path1: string, path2: string): boolean;
|
||||
/**
|
||||
|
@ -233,5 +288,6 @@ export declare function arePathsEqual(path1: string, path2: string): boolean;
|
|||
* filesystem-defined path equivalence rules.
|
||||
* @param parentPath The parent path
|
||||
* @param childPath The child path
|
||||
* @version Added in JS SDK 0.1
|
||||
*/
|
||||
export declare function isSubpathOf(parentPath: string, childPath: string): boolean;
|
|
@ -1,6 +1,8 @@
|
|||
/**
|
||||
* Unit test module. Only available if the firmware has been configured with
|
||||
* `FIRMWARE_APP_SET=unit_tests`.
|
||||
* @version Added in JS SDK 0.1
|
||||
* @module
|
||||
*/
|
||||
|
||||
export function fail(message: string): never;
|
13
applications/system/js_app/packages/fz-sdk/tsconfig.json
Normal file
13
applications/system/js_app/packages/fz-sdk/tsconfig.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"checkJs": true,
|
||||
"module": "CommonJS",
|
||||
"noLib": true,
|
||||
},
|
||||
"include": [
|
||||
"./**/*.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
]
|
||||
}
|
19
applications/system/js_app/packages/fz-sdk/typedoc.json
Normal file
19
applications/system/js_app/packages/fz-sdk/typedoc.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"$schema": "https://typedoc.org/schema.json",
|
||||
"name": "Flipper Zero JS API",
|
||||
"excludePrivate": true,
|
||||
"entryPointStrategy": "expand",
|
||||
"entryPoints": [
|
||||
".",
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
],
|
||||
"cleanOutputDir": true,
|
||||
"out": "./docs",
|
||||
"plugin": [
|
||||
"typedoc-material-theme",
|
||||
],
|
||||
"readme": "./docs_readme.md",
|
||||
"themeColor": "#ff8200",
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
type Lit = undefined | null | {};
|
||||
|
||||
/**
|
||||
* Subscription control interface
|
||||
*/
|
||||
export interface Subscription {
|
||||
/**
|
||||
* Cancels the subscription, preventing any future events managed by the
|
||||
* subscription from firing
|
||||
*/
|
||||
cancel(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opaque event source identifier
|
||||
*/
|
||||
export type Contract<Item = undefined> = symbol;
|
||||
|
||||
/**
|
||||
* A callback can be assigned to an event loop to listen to an event. It may
|
||||
* return an array with values that will be passed to it as arguments the next
|
||||
* time that it is called. The first argument is always the subscription
|
||||
* manager, and the second argument is always the item that trigged the event.
|
||||
* The type of the item is defined by the event source.
|
||||
*/
|
||||
export type Callback<Item, Args extends Lit[]> = (subscription: Subscription, item: Item, ...args: Args) => Args | undefined | void;
|
||||
|
||||
/**
|
||||
* Subscribes a callback to an event
|
||||
* @param contract Event identifier
|
||||
* @param callback Function to call when the event is triggered
|
||||
* @param args Initial arguments passed to the callback
|
||||
*/
|
||||
export function subscribe<Item, Args extends Lit[]>(contract: Contract<Item>, callback: Callback<Item, Args>, ...args: Args): Subscription;
|
||||
/**
|
||||
* Runs the event loop until it is stopped (potentially never)
|
||||
*/
|
||||
export function run(): void | never;
|
||||
/**
|
||||
* Stops the event loop
|
||||
*/
|
||||
export function stop(): void;
|
||||
|
||||
/**
|
||||
* Creates a timer event that can be subscribed to just like any other event
|
||||
* @param mode Either `"oneshot"` or `"periodic"`
|
||||
* @param interval Timer interval in milliseconds
|
||||
*/
|
||||
export function timer(mode: "oneshot" | "periodic", interval: number): Contract;
|
||||
|
||||
/**
|
||||
* Message queue
|
||||
*/
|
||||
export interface Queue<T> {
|
||||
/**
|
||||
* Message event
|
||||
*/
|
||||
input: Contract<T>;
|
||||
/**
|
||||
* Sends a message to the queue
|
||||
* @param message message to send
|
||||
*/
|
||||
send(message: T): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a message queue
|
||||
* @param length maximum queue capacity
|
||||
*/
|
||||
export function queue<T>(length: number): Queue<T>;
|
|
@ -1,14 +0,0 @@
|
|||
/**
|
||||
* @brief Returns the device model
|
||||
*/
|
||||
export declare function getModel(): string;
|
||||
|
||||
/**
|
||||
* @brief Returns the name of the virtual dolphin
|
||||
*/
|
||||
export declare function getName(): string;
|
||||
|
||||
/**
|
||||
* @brief Returns the battery charge percentage
|
||||
*/
|
||||
export declare function getBatteryCharge(): number;
|
178
applications/system/js_app/types/global.d.ts
vendored
178
applications/system/js_app/types/global.d.ts
vendored
|
@ -1,178 +0,0 @@
|
|||
/**
|
||||
* @brief Pauses JavaScript execution for a while
|
||||
* @param ms How many milliseconds to pause the execution for
|
||||
*/
|
||||
declare function delay(ms: number): void;
|
||||
|
||||
/**
|
||||
* @brief Prints to the GUI console view
|
||||
* @param args The arguments are converted to strings, concatenated without any
|
||||
* spaces in between and printed to the console view
|
||||
*/
|
||||
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
|
||||
*/
|
||||
declare function toString(value: number, base?: number): string;
|
||||
|
||||
/**
|
||||
* @brief Reads a JS value from a file
|
||||
*
|
||||
* Reads a file at the specified path, interprets it as a JS value and returns
|
||||
* said value.
|
||||
*
|
||||
* @param path The path to the file
|
||||
*/
|
||||
declare function load(path: string): any;
|
||||
|
||||
/**
|
||||
* @brief mJS Foreign Pointer type
|
||||
*
|
||||
* JavaScript code cannot do anything with values of `RawPointer` type except
|
||||
* acquire them from native code and pass them right back to other parts of
|
||||
* native code. These values cannot be turned into something meaningful, nor can
|
||||
* be they modified.
|
||||
*/
|
||||
declare type RawPointer = symbol & { "__tag__": "raw_ptr" };
|
||||
// introducing a nominal type in a hacky way; the `__tag__` property doesn't really exist.
|
||||
|
||||
/**
|
||||
* @brief Holds raw bytes
|
||||
*/
|
||||
declare class ArrayBuffer {
|
||||
/**
|
||||
* @brief The pointer to the byte buffer
|
||||
* @note Like other `RawPointer` values, this value is essentially useless
|
||||
* to JS code.
|
||||
*/
|
||||
getPtr: RawPointer;
|
||||
/**
|
||||
* @brief The length of the buffer in bytes
|
||||
*/
|
||||
byteLength: number;
|
||||
/**
|
||||
* @brief Creates an `ArrayBuffer` that contains a sub-part of the buffer
|
||||
* @param start The index of the byte in the source buffer to be used as the
|
||||
* start for the new buffer
|
||||
* @param end The index of the byte in the source buffer that follows the
|
||||
* byte to be used as the last byte for the new buffer
|
||||
*/
|
||||
slice(start: number, end?: number): ArrayBuffer;
|
||||
}
|
||||
|
||||
declare function ArrayBuffer(): ArrayBuffer;
|
||||
|
||||
declare type ElementType = "u8" | "i8" | "u16" | "i16" | "u32" | "i32";
|
||||
|
||||
declare class TypedArray<E extends ElementType> {
|
||||
/**
|
||||
* @brief The length of the buffer in bytes
|
||||
*/
|
||||
byteLength: number;
|
||||
/**
|
||||
* @brief The length of the buffer in typed elements
|
||||
*/
|
||||
length: number;
|
||||
/**
|
||||
* @brief The underlying `ArrayBuffer`
|
||||
*/
|
||||
buffer: ArrayBuffer;
|
||||
}
|
||||
|
||||
declare class Uint8Array extends TypedArray<"u8"> { }
|
||||
declare class Int8Array extends TypedArray<"i8"> { }
|
||||
declare class Uint16Array extends TypedArray<"u16"> { }
|
||||
declare class Int16Array extends TypedArray<"i16"> { }
|
||||
declare class Uint32Array extends TypedArray<"u32"> { }
|
||||
declare class Int32Array extends TypedArray<"i32"> { }
|
||||
|
||||
declare function Uint8Array(data: ArrayBuffer | number | number[]): Uint8Array;
|
||||
declare function Int8Array(data: ArrayBuffer | number | number[]): Int8Array;
|
||||
declare function Uint16Array(data: ArrayBuffer | number | number[]): Uint16Array;
|
||||
declare function Int16Array(data: ArrayBuffer | number | number[]): Int16Array;
|
||||
declare function Uint32Array(data: ArrayBuffer | number | number[]): Uint32Array;
|
||||
declare function Int32Array(data: ArrayBuffer | number | number[]): Int32Array;
|
||||
|
||||
declare const console: {
|
||||
/**
|
||||
* @brief Prints to the UART logs at the `[I]` level
|
||||
* @param args The arguments are converted to strings, concatenated without any
|
||||
* spaces in between and printed to the logs
|
||||
*/
|
||||
log(...args: any[]): void;
|
||||
/**
|
||||
* @brief Prints to the UART logs at the `[D]` level
|
||||
* @param args The arguments are converted to strings, concatenated without any
|
||||
* spaces in between and printed to the logs
|
||||
*/
|
||||
debug(...args: any[]): void;
|
||||
/**
|
||||
* @brief Prints to the UART logs at the `[W]` level
|
||||
* @param args The arguments are converted to strings, concatenated without any
|
||||
* spaces in between and printed to the logs
|
||||
*/
|
||||
warn(...args: any[]): void;
|
||||
/**
|
||||
* @brief Prints to the UART logs at the `[E]` level
|
||||
* @param args The arguments are converted to strings, concatenated without any
|
||||
* spaces in between and printed to the logs
|
||||
*/
|
||||
error(...args: any[]): void;
|
||||
};
|
||||
|
||||
declare class Array<T> {
|
||||
/**
|
||||
* @brief Takes items out of the array
|
||||
*
|
||||
* Removes elements from the array and returns them in a new array
|
||||
*
|
||||
* @param start The index to start taking elements from
|
||||
* @param deleteCount How many elements to take
|
||||
* @returns The elements that were taken out of the original array as a new
|
||||
* array
|
||||
*/
|
||||
splice(start: number, deleteCount: number): T[];
|
||||
/**
|
||||
* @brief Adds a value to the end of the array
|
||||
* @param value The value to add
|
||||
* @returns New length of the array
|
||||
*/
|
||||
push(value: T): number;
|
||||
/**
|
||||
* @brief How many elements there are in the array
|
||||
*/
|
||||
length: number;
|
||||
}
|
||||
|
||||
declare class String {
|
||||
/**
|
||||
* @brief How many characters there are in the string
|
||||
*/
|
||||
length: number;
|
||||
/**
|
||||
* @brief Returns the character code at an index in the string
|
||||
* @param index The index to consult
|
||||
*/
|
||||
charCodeAt(index: number): number;
|
||||
/**
|
||||
* See `charCodeAt`
|
||||
*/
|
||||
at(index: number): number;
|
||||
}
|
||||
|
||||
declare class Boolean { }
|
||||
|
||||
declare class Function { }
|
||||
|
||||
declare class Number { }
|
||||
|
||||
declare class Object { }
|
||||
|
||||
declare class RegExp { }
|
||||
|
||||
declare interface IArguments { }
|
||||
|
||||
declare type Partial<O extends object> = { [K in keyof O]?: O[K] };
|
16
applications/system/js_app/types/gui/dialog.d.ts
vendored
16
applications/system/js_app/types/gui/dialog.d.ts
vendored
|
@ -1,16 +0,0 @@
|
|||
import type { View, ViewFactory } from ".";
|
||||
import type { Contract } from "../event_loop";
|
||||
|
||||
type Props = {
|
||||
header: string,
|
||||
text: string,
|
||||
left: string,
|
||||
center: string,
|
||||
right: string,
|
||||
}
|
||||
declare class Dialog extends View<Props> {
|
||||
input: Contract<"left" | "center" | "right">;
|
||||
}
|
||||
declare class DialogFactory extends ViewFactory<Props, Dialog> { }
|
||||
declare const factory: DialogFactory;
|
||||
export = factory;
|
|
@ -1,7 +0,0 @@
|
|||
import type { View, ViewFactory } from ".";
|
||||
|
||||
type Props = {};
|
||||
declare class EmptyScreen extends View<Props> { }
|
||||
declare class EmptyScreenFactory extends ViewFactory<Props, EmptyScreen> { }
|
||||
declare const factory: EmptyScreenFactory;
|
||||
export = factory;
|
41
applications/system/js_app/types/gui/index.d.ts
vendored
41
applications/system/js_app/types/gui/index.d.ts
vendored
|
@ -1,41 +0,0 @@
|
|||
import type { Contract } from "../event_loop";
|
||||
|
||||
type Properties = { [K: string]: any };
|
||||
|
||||
export declare class View<Props extends Properties> {
|
||||
set<P extends keyof Props>(property: P, value: Props[P]): void;
|
||||
}
|
||||
|
||||
export declare class ViewFactory<Props extends Properties, V extends View<Props>> {
|
||||
make(): V;
|
||||
makeWith(initial: Partial<Props>): V;
|
||||
}
|
||||
|
||||
declare class ViewDispatcher {
|
||||
/**
|
||||
* Event source for `sendCustom` events
|
||||
*/
|
||||
custom: Contract<number>;
|
||||
/**
|
||||
* Event source for navigation events (back key presses)
|
||||
*/
|
||||
navigation: Contract;
|
||||
/**
|
||||
* Sends a number to the custom event handler
|
||||
* @param event number to send
|
||||
*/
|
||||
sendCustom(event: number): void;
|
||||
/**
|
||||
* Switches to a view
|
||||
* @param assoc View-ViewDispatcher association as returned by `add`
|
||||
*/
|
||||
switchTo(assoc: View<any>): void;
|
||||
/**
|
||||
* Sends this ViewDispatcher to the front or back, above or below all other
|
||||
* GUI viewports
|
||||
* @param direction Either `"front"` or `"back"`
|
||||
*/
|
||||
sendTo(direction: "front" | "back"): void;
|
||||
}
|
||||
|
||||
export const viewDispatcher: ViewDispatcher;
|
|
@ -1,7 +0,0 @@
|
|||
import type { View, ViewFactory } from ".";
|
||||
|
||||
type Props = {};
|
||||
declare class Loading extends View<Props> { }
|
||||
declare class LoadingFactory extends ViewFactory<Props, Loading> { }
|
||||
declare const factory: LoadingFactory;
|
||||
export = factory;
|
|
@ -1,13 +0,0 @@
|
|||
import type { View, ViewFactory } from ".";
|
||||
import type { Contract } from "../event_loop";
|
||||
|
||||
type Props = {
|
||||
header: string,
|
||||
items: string[],
|
||||
};
|
||||
declare class Submenu extends View<Props> {
|
||||
chosen: Contract<number>;
|
||||
}
|
||||
declare class SubmenuFactory extends ViewFactory<Props, Submenu> { }
|
||||
declare const factory: SubmenuFactory;
|
||||
export = factory;
|
|
@ -1,14 +0,0 @@
|
|||
import type { View, ViewFactory } from ".";
|
||||
import type { Contract } from "../event_loop";
|
||||
|
||||
type Props = {
|
||||
text: string,
|
||||
font: "text" | "hex",
|
||||
focus: "start" | "end",
|
||||
}
|
||||
declare class TextBox extends View<Props> {
|
||||
chosen: Contract<number>;
|
||||
}
|
||||
declare class TextBoxFactory extends ViewFactory<Props, TextBox> { }
|
||||
declare const factory: TextBoxFactory;
|
||||
export = factory;
|
|
@ -1,14 +0,0 @@
|
|||
import type { View, ViewFactory } from ".";
|
||||
import type { Contract } from "../event_loop";
|
||||
|
||||
type Props = {
|
||||
header: string,
|
||||
minLength: number,
|
||||
maxLength: number,
|
||||
}
|
||||
declare class TextInput extends View<Props> {
|
||||
input: Contract<string>;
|
||||
}
|
||||
declare class TextInputFactory extends ViewFactory<Props, TextInput> { }
|
||||
declare const factory: TextInputFactory;
|
||||
export = factory;
|
|
@ -61,7 +61,7 @@ Reads a digital value from a pin configured with `direction: "in"` and any
|
|||
#### Returns
|
||||
Boolean logic level
|
||||
|
||||
### `Pin.read_analog()`
|
||||
### `Pin.readAnalog()`
|
||||
Reads an analog voltage level in millivolts from a pin configured with
|
||||
`direction: "in"` and `inMode: "analog"`
|
||||
|
||||
|
|
|
@ -146,10 +146,17 @@ void mjs_init_builtin(struct mjs* mjs, mjs_val_t obj) {
|
|||
// mjs_set(mjs, obj, "JSON", ~0, v);
|
||||
|
||||
/*
|
||||
* Populate Object.create()
|
||||
* Populate Object
|
||||
*/
|
||||
v = mjs_mk_object(mjs);
|
||||
mjs_set(mjs, v, "create", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t)mjs_op_create_object));
|
||||
mjs_set(
|
||||
mjs,
|
||||
v,
|
||||
"defineProperty",
|
||||
~0,
|
||||
mjs_mk_foreign_func(
|
||||
mjs, (mjs_func_ptr_t)mjs_op_object_define_property)); // stub, do not use
|
||||
mjs_set(mjs, obj, "Object", ~0, v);
|
||||
|
||||
/*
|
||||
|
|
|
@ -294,6 +294,11 @@ clean:
|
|||
mjs_return(mjs, ret);
|
||||
}
|
||||
|
||||
MJS_PRIVATE void mjs_op_object_define_property(struct mjs* mjs) {
|
||||
// stub, do not use
|
||||
mjs_return(mjs, MJS_UNDEFINED);
|
||||
}
|
||||
|
||||
mjs_val_t
|
||||
mjs_struct_to_obj(struct mjs* mjs, const void* base, const struct mjs_c_struct_member* defs) {
|
||||
mjs_val_t obj;
|
||||
|
|
|
@ -50,6 +50,11 @@ MJS_PRIVATE mjs_err_t mjs_set_internal(
|
|||
*/
|
||||
MJS_PRIVATE void mjs_op_create_object(struct mjs* mjs);
|
||||
|
||||
/*
|
||||
* Stub of `Object.defineProperty()`
|
||||
*/
|
||||
MJS_PRIVATE void mjs_op_object_define_property(struct mjs* mjs);
|
||||
|
||||
/*
|
||||
* Cell destructor for object arena
|
||||
*/
|
||||
|
|
|
@ -76,7 +76,8 @@ static int s_assign_ops[] = {
|
|||
|
||||
static int findtok(int* toks, int tok) {
|
||||
int i = 0;
|
||||
while(tok != toks[i] && toks[i] != TOK_EOF) i++;
|
||||
while(tok != toks[i] && toks[i] != TOK_EOF)
|
||||
i++;
|
||||
return toks[i];
|
||||
}
|
||||
|
||||
|
@ -87,7 +88,7 @@ static void emit_op(struct pstate* pstate, int tok) {
|
|||
}
|
||||
|
||||
#define BINOP_STACK_FRAME_SIZE 16
|
||||
#define STACK_LIMIT 8192
|
||||
#define STACK_LIMIT 8192
|
||||
|
||||
// Intentionally left as macro rather than a function, to let the
|
||||
// compiler to inline calls and mimimize runtime stack usage.
|
||||
|
@ -166,7 +167,8 @@ static mjs_err_t parse_statement_list(struct pstate* p, int et) {
|
|||
if(drop) emit_byte(p, OP_DROP);
|
||||
res = parse_statement(p);
|
||||
drop = 1;
|
||||
while(p->tok.tok == TOK_SEMICOLON) pnext1(p);
|
||||
while(p->tok.tok == TOK_SEMICOLON)
|
||||
pnext1(p);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -523,7 +525,11 @@ static mjs_err_t parse_expr(struct pstate* p) {
|
|||
static mjs_err_t parse_let(struct pstate* p) {
|
||||
mjs_err_t res = MJS_OK;
|
||||
LOG(LL_VERBOSE_DEBUG, ("[%.*s]", 10, p->tok.ptr));
|
||||
EXPECT(p, TOK_KEYWORD_LET);
|
||||
if((p)->tok.tok != TOK_KEYWORD_VAR && (p)->tok.tok != TOK_KEYWORD_LET &&
|
||||
(p)->tok.tok != TOK_KEYWORD_CONST)
|
||||
SYNTAX_ERROR(p);
|
||||
else
|
||||
pnext1(p);
|
||||
for(;;) {
|
||||
struct tok tmp = p->tok;
|
||||
EXPECT(p, TOK_IDENT);
|
||||
|
@ -910,6 +916,8 @@ static mjs_err_t parse_statement(struct pstate* p) {
|
|||
pnext1(p);
|
||||
return MJS_OK;
|
||||
case TOK_KEYWORD_LET:
|
||||
case TOK_KEYWORD_VAR:
|
||||
case TOK_KEYWORD_CONST:
|
||||
return parse_let(p);
|
||||
case TOK_OPEN_CURLY:
|
||||
return parse_block(p, 1);
|
||||
|
@ -939,7 +947,6 @@ static mjs_err_t parse_statement(struct pstate* p) {
|
|||
case TOK_KEYWORD_SWITCH:
|
||||
case TOK_KEYWORD_THROW:
|
||||
case TOK_KEYWORD_TRY:
|
||||
case TOK_KEYWORD_VAR:
|
||||
case TOK_KEYWORD_VOID:
|
||||
case TOK_KEYWORD_WITH:
|
||||
mjs_set_errorf(
|
||||
|
|
|
@ -80,12 +80,13 @@ static int getnum(struct pstate* p) {
|
|||
}
|
||||
|
||||
static int is_reserved_word_token(const char* s, int len) {
|
||||
const char* reserved[] = {"break", "case", "catch", "continue", "debugger", "default",
|
||||
"delete", "do", "else", "false", "finally", "for",
|
||||
"function", "if", "in", "instanceof", "new", "null",
|
||||
"return", "switch", "this", "throw", "true", "try",
|
||||
"typeof", "var", "void", "while", "with", "let",
|
||||
"undefined", NULL};
|
||||
const char* reserved[] = {"break", "case", "catch", "continue", "debugger",
|
||||
"default", "delete", "do", "else", "false",
|
||||
"finally", "for", "function", "if", "in",
|
||||
"instanceof", "new", "null", "return", "switch",
|
||||
"this", "throw", "true", "try", "typeof",
|
||||
"var", "void", "while", "with", "let",
|
||||
"const", "undefined", NULL};
|
||||
int i;
|
||||
if(!mjs_is_alpha(s[0])) return 0;
|
||||
for(i = 0; reserved[i] != NULL; i++) {
|
||||
|
@ -95,7 +96,8 @@ static int is_reserved_word_token(const char* s, int len) {
|
|||
}
|
||||
|
||||
static int getident(struct pstate* p) {
|
||||
while(mjs_is_ident(p->pos[0]) || mjs_is_digit(p->pos[0])) p->pos++;
|
||||
while(mjs_is_ident(p->pos[0]) || mjs_is_digit(p->pos[0]))
|
||||
p->pos++;
|
||||
p->tok.len = p->pos - p->tok.ptr;
|
||||
p->pos--;
|
||||
return TOK_IDENT;
|
||||
|
@ -125,7 +127,8 @@ static void skip_spaces_and_comments(struct pstate* p) {
|
|||
p->pos++;
|
||||
}
|
||||
if(p->pos[0] == '/' && p->pos[1] == '/') {
|
||||
while(p->pos[0] != '\0' && p->pos[0] != '\n') p->pos++;
|
||||
while(p->pos[0] != '\0' && p->pos[0] != '\n')
|
||||
p->pos++;
|
||||
}
|
||||
if(p->pos[0] == '/' && p->pos[1] == '*') {
|
||||
p->pos += 2;
|
||||
|
@ -142,8 +145,8 @@ static void skip_spaces_and_comments(struct pstate* p) {
|
|||
}
|
||||
|
||||
static int ptranslate(int tok) {
|
||||
#define DT(a, b) ((a) << 8 | (b))
|
||||
#define TT(a, b, c) ((a) << 16 | (b) << 8 | (c))
|
||||
#define DT(a, b) ((a) << 8 | (b))
|
||||
#define TT(a, b, c) ((a) << 16 | (b) << 8 | (c))
|
||||
#define QT(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
|
||||
/* Map token ID produced by mjs_tok.c to token ID produced by lemon */
|
||||
/* clang-format off */
|
||||
|
|
|
@ -125,6 +125,7 @@ enum {
|
|||
TOK_KEYWORD_WHILE,
|
||||
TOK_KEYWORD_WITH,
|
||||
TOK_KEYWORD_LET,
|
||||
TOK_KEYWORD_CONST,
|
||||
TOK_KEYWORD_UNDEFINED,
|
||||
TOK_MAX
|
||||
};
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
"checkJs": true,
|
||||
"module": "CommonJS",
|
||||
"typeRoots": [
|
||||
"./applications/system/js_app/types"
|
||||
"./applications/system/js_app/packages/fz-sdk/"
|
||||
],
|
||||
"noLib": true,
|
||||
},
|
||||
"include": [
|
||||
"./applications/system/js_app/examples/apps/Scripts",
|
||||
"./applications/debug/unit_tests/resources/unit_tests/js",
|
||||
"./applications/system/js_app/types/global.d.ts",
|
||||
"./applications/system/js_app/packages/fz-sdk/global.d.ts",
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue