diff --git a/.eslintignore b/.eslintignore index fcbea07f9..a82960313 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,6 +1,8 @@ -apps/animclk/V29.LBM.js -apps/banglerun/rollup.config.js -apps/schoolCalendar/fullcalendar/main.js -apps/authentiwatch/qr_packed.js -apps/qrcode/qr-scanner.umd.min.js -*.test.js + +# Needs to be ignored because it uses ESM export/import +apps/gipy/pkg/gps.js +apps/gipy/pkg/gps.d.ts +apps/gipy/pkg/gps_bg.wasm.d.ts + +# Needs to be ignored because it includes broken JS +apps/health/chart.min.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..b7590a77e --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,250 @@ +const lintExemptions = require("./apps/lint_exemptions.js"); +const fs = require("fs"); +const path = require("path"); + +function findGeneratedJS(roots) { + function* listFiles(dir, allow) { + for (const f of fs.readdirSync(dir)) { + const filepath = path.join(dir, f); + const stat = fs.statSync(filepath); + + if (stat.isDirectory()) { + yield* listFiles(filepath, allow); + } else if(allow(filepath)) { + yield filepath; + } + } + } + + return roots.flatMap(root => + [...listFiles(root, f => f.endsWith(".ts"))] + .map(f => f.replace(/\.ts$/, ".js")) + ); +} + +module.exports = { + "env": { + // TODO: "espruino": false + // TODO: "banglejs": false + // For a prototype of the above, see https://github.com/espruino/BangleApps/pull/3237 + }, + "extends": "eslint:recommended", + "globals": { + // Methods and Fields at https://banglejs.com/reference + "Array": "readonly", + "ArrayBuffer": "readonly", + "ArrayBufferView": "readonly", + "Bangle": "readonly", + "BluetoothDevice": "readonly", + "BluetoothRemoteGATTCharacteristic": "readonly", + "BluetoothRemoteGATTServer": "readonly", + "BluetoothRemoteGATTService": "readonly", + "Boolean": "readonly", + "console": "readonly", + "DataView": "readonly", + "Date": "readonly", + "E": "readonly", + "Error": "readonly", + "Flash": "readonly", + "Float32Array": "readonly", + "Float64Array": "readonly", + "Function": "readonly", + "Graphics": "readonly", + "I2C": "readonly", + "Int16Array": "readonly", + "Int32Array": "readonly", + "Int8Array": "readonly", + "InternalError": "readonly", + "JSON": "readonly", + "Math": "readonly", + "Modules": "readonly", + "NRF": "readonly", + "Number": "readonly", + "Object": "readonly", + "OneWire": "readonly", + "Pin": "readonly", + "process": "readonly", + "Promise": "readonly", + "ReferenceError": "readonly", + "RegExp": "readonly", + "Serial": "readonly", + "SPI": "readonly", + "StorageFile": "readonly", + "String": "readonly", + "SyntaxError": "readonly", + "TFMicroInterpreter": "readonly", + "TypeError": "readonly", + "Uint16Array": "readonly", + "Uint24Array": "readonly", + "Uint32Array": "readonly", + "Uint8Array": "readonly", + "Uint8ClampedArray": "readonly", + "Unistroke": "readonly", + "Waveform": "readonly", + // Methods and Fields at https://banglejs.com/reference + "__FILE__": "readonly", + "analogRead": "readonly", + "analogWrite": "readonly", + "arguments": "readonly", + "atob": "readonly", + "Bluetooth": "readonly", + "BTN": "readonly", + "BTN1": "readonly", + "BTN2": "readonly", + "BTN3": "readonly", + "BTN4": "readonly", + "BTN5": "readonly", + "btoa": "readonly", + "changeInterval": "readonly", + "clearInterval": "readonly", + "clearTimeout": "readonly", + "clearWatch": "readonly", + "decodeURIComponent": "readonly", + "digitalPulse": "readonly", + "digitalRead": "readonly", + "digitalWrite": "readonly", + "dump": "readonly", + "echo": "readonly", + "edit": "readonly", + "encodeURIComponent": "readonly", + "eval": "readonly", + "getPinMode": "readonly", + "getSerial": "readonly", + "getTime": "readonly", + "global": "readonly", + "globalThis": "readonly", + "HIGH": "readonly", + "I2C1": "readonly", + "Infinity": "readonly", + "isFinite": "readonly", + "isNaN": "readonly", + "LED": "readonly", + "LED1": "readonly", + "LED2": "readonly", + "load": "readonly", + "LoopbackA": "readonly", + "LoopbackB": "readonly", + "LOW": "readonly", + "NaN": "readonly", + "parseFloat": "readonly", + "parseInt": "readonly", + "peek16": "readonly", + "peek32": "readonly", + "peek8": "readonly", + "pinMode": "readonly", + "poke16": "readonly", + "poke32": "readonly", + "poke8": "readonly", + "print": "readonly", + "require": "readonly", + "reset": "readonly", + "save": "readonly", + "Serial1": "readonly", + "setBusyIndicator": "readonly", + "setInterval": "readonly", + "setSleepIndicator": "readonly", + "setTime": "readonly", + "setTimeout": "readonly", + "setWatch": "readonly", + "shiftOut": "readonly", + "SPI1": "readonly", + "Terminal": "readonly", + "trace": "readonly", + "VIBRATE": "readonly", + // Aliases and not defined at https://banglejs.com/reference + "g": "readonly", + "WIDGETS": "readonly", + "module": "readonly", + "exports": "writable", + "D0": "readonly", + "D1": "readonly", + "D2": "readonly", + "D3": "readonly", + "D4": "readonly", + "D5": "readonly", + "D6": "readonly", + "D7": "readonly", + "D8": "readonly", + "D9": "readonly", + "D10": "readonly", + "D11": "readonly", + "D12": "readonly", + "D13": "readonly", + "D14": "readonly", + "D15": "readonly", + "D16": "readonly", + "D17": "readonly", + "D18": "readonly", + "D19": "readonly", + "D20": "readonly", + "D21": "readonly", + "D22": "readonly", + "D23": "readonly", + "D24": "readonly", + "D25": "readonly", + "D26": "readonly", + "D27": "readonly", + "D28": "readonly", + "D29": "readonly", + "D30": "readonly", + "D31": "readonly", + + "bleServiceOptions": "writable", // available in boot.js code that's called ad part of bootupdate + }, + "parserOptions": { + "ecmaVersion": 11 + }, + "rules": { + "indent": [ + "off", + 2, + { + "SwitchCase": 1 + } + ], + "no-constant-condition": "off", + "no-delete-var": "off", + "no-empty": ["warn", { "allowEmptyCatch": true }], + "no-global-assign": "off", + "no-inner-declarations": "off", + "no-prototype-builtins": "off", + "no-redeclare": "off", + "no-unreachable": "warn", + "no-cond-assign": "warn", + "no-useless-catch": "warn", + "no-undef": "warn", + "no-unused-vars": ["warn", { "args": "none" } ], + "no-useless-escape": "off", + "no-control-regex" : "off" + }, + overrides: [ + { + files: ["*.ts"], + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + ], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + rules: { + "no-delete-var": "off", + "no-empty": ["error", { "allowEmptyCatch": true }], + "no-prototype-builtins": "off", + "prefer-const": "off", + "prefer-rest-params": "off", + "no-control-regex" : "off", + "@typescript-eslint/no-delete-var": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-this-alias": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-var-requires": "off", + } + }, + ...Object.entries(lintExemptions).map(([filePath, {rules}]) => ({ + files: [filePath], + rules: Object.fromEntries(rules.map(rule => [rule, "off"])), + })), + ], + ignorePatterns: findGeneratedJS(["apps/", "modules/"]), + reportUnusedDisableDirectives: true, +} diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..345bce54f --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: espruino +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: ['http://www.espruino.com/Donate']# Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/ISSUE_TEMPLATE/bangle-bug-report-custom-form.yaml b/.github/ISSUE_TEMPLATE/bangle-bug-report-custom-form.yaml index 484b3ba85..045a6e18a 100644 --- a/.github/ISSUE_TEMPLATE/bangle-bug-report-custom-form.yaml +++ b/.github/ISSUE_TEMPLATE/bangle-bug-report-custom-form.yaml @@ -58,3 +58,7 @@ body: validations: required: true + - type: textarea + id: apps + attributes: + label: Installed apps \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..a20c7ed7c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,9 @@ +version: 2 + +updates: + - package-ecosystem: "gitsubmodule" + directory: "/" + schedule: + interval: "daily" + reviewers: + - "gfwilliams" diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 1eb009153..bebe18748 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -1,4 +1,4 @@ -name: Node CI +name: build on: [push, pull_request] @@ -6,29 +6,22 @@ jobs: build: runs-on: ubuntu-latest - strategy: - matrix: - node-version: [16.x] - steps: - name: Checkout repository and submodules - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: recursive - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 + - name: Use Node.js 18.x + uses: actions/setup-node@v3 with: - node-version: ${{ matrix.node-version }} - - name: install testing dependencies - run: npm i - - name: test all apps and widgets - run: npm run test - - name: install typescript dependencies + node-version: 18.x + - name: Install testing dependencies + run: npm ci + - name: Test all apps and widgets + run: npm test + - name: Install typescript dependencies working-directory: ./typescript run: npm ci - - name: build types + - name: Build all TS apps and widgets working-directory: ./typescript - run: npm run build:types - - name: build all TS apps and widgets - working-directory: ./typescript - run: npm run build \ No newline at end of file + run: npm run build diff --git a/.gitignore b/.gitignore index 231851dd6..7687a770a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ .htaccess node_modules -package-lock.json .DS_Store *.js.bak appdates.csv @@ -12,3 +11,7 @@ tests/Layout/testresult.bmp apps.local.json _site .jekyll-cache +.owncloudsync.log +Desktop.ini +.sync_*.db* +*.swp diff --git a/.gitmodules b/.gitmodules index fd6663d2a..c2c1104c2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "EspruinoAppLoaderCore"] path = core url = https://github.com/espruino/EspruinoAppLoaderCore.git +[submodule "webtools"] + path = webtools + url = https://github.com/espruino/EspruinoWebTools.git diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..69aa0ab3d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,9 @@ +Contributing to BangleApps +========================== + +https://github.com/espruino/BangleApps?tab=readme-ov-file#getting-started +has some links to tutorials on developing for Bangle.js. + +Please check out the Wiki to get an idea what sort of things +we'd like to see for contributed apps: https://github.com/espruino/BangleApps/wiki/App-Contribution + diff --git a/README.md b/README.md index b3da9f685..b9b770b37 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ Bangle.js App Loader (and Apps) ================================ -[](https://app.travis-ci.com/github/espruino/BangleApps) +[](https://github.com/espruino/BangleApps/actions/workflows/nodejs.yml) * Try the **release version** at [banglejs.com/apps](https://banglejs.com/apps) * Try the **development version** at [espruino.github.io](https://espruino.github.io/BangleApps/) +The release version is manually refreshed with regular intervals while the development version is continuously updated as new code is committed to this repository. + **All software (including apps) in this repository is MIT Licensed - see [LICENSE](LICENSE)** By submitting code to this repository you confirm that you are happy with it being MIT licensed, and that it is not licensed in another way that would make this impossible. @@ -98,7 +100,7 @@ This is the best way to test... **Note:** It's a great idea to get a local copy of the repository on your PC, then run `bin/sanitycheck.js` - it'll run through a bunch of common issues -that there might be. +that there might be. To get the project running locally, you have to initialize and update the git submodules first: `git submodule update --init`. Be aware of the delay between commits and updates on github.io - it can take a few minutes (and a 'hard refresh' of your browser) for changes to take effect. @@ -191,7 +193,7 @@ widget bar at the top of the screen they can add themselves to the global ``` WIDGETS["mywidget"]={ - area:"tl", // tl (top left), tr (top right) + area:"tl", // tl (top left), tr (top right), bl (bottom left), br (bottom right) sortorder:0, // (Optional) determines order of widgets in the same corner width: 24, // how wide is the widget? You can change this and call Bangle.drawWidgets() to re-layout draw:draw // called to draw the widget @@ -251,12 +253,15 @@ and which gives information about the app for the Launcher. "description": "...", // long description (can contain markdown) "icon": "icon.png", // icon in apps/ "screenshots" : [ { "url":"screenshot.png" } ], // optional screenshot for app - "type":"...", // optional(if app) - + "type":"...", // optional(if app) - // 'app' - an application // 'clock' - a clock - required for clocks to automatically start // 'widget' - a widget + // 'module' - this provides a module that can be used with 'require'. + // 'provides_modules' should be used if type:module is specified // 'bootloader' - an app that at startup (app.boot.js) but doesn't have a launcher entry for 'app.js' // 'settings' - apps that appear in Settings->Apps (with appname.settings.js) but that have no 'app.js' + // 'clkinfo' - Provides a 'myapp.clkinfo.js' file that can be used to display info in clocks - see modules/clock_info.js // 'RAM' - code that runs and doesn't upload anything to storage // 'launch' - replacement 'Launcher' // 'textinput' - provides a 'textinput' library that allows text to be input on the Bangle @@ -265,11 +270,28 @@ and which gives information about the app for the Launcher. // 'notify' - provides 'notify' library for showing notifications // 'locale' - provides 'locale' library for language-specific date/distance/etc // (a version of 'locale' is included in the firmware) - "tags": "", // comma separated tag list for searching + // 'defaultconfig' - a set of apps that will can be installed and will wipe out all previously installed apps + "tags": "", // comma separated tag list for searching (don't include uppercase or spaces) + // common types are: + // 'clock' - it's a clock + // 'widget' - it is (or provides) a widget + // 'outdoors' - useful for outdoor activities + // 'tool' - a useful utility (timer, calculator, etc) + // 'game' - a game + // 'bluetooth' - uses Bluetooth LE + // 'system' - used by the system + // 'clkinfo' - provides or uses clock_info module for data on your clock face or clocks that support it (see apps/clock_info/README.md) + // 'health' - e.g. heart rate monitors or step counting "supports": ["BANGLEJS2"], // List of device IDs supported, either BANGLEJS or BANGLEJS2 "dependencies" : { "notify":"type" } // optional, app 'types' we depend on (see "type" above) "dependencies" : { "messages":"app" } // optional, depend on a specific app ID // for instance this will use notify/notifyfs is they exist, or will pull in 'notify' + "dependencies" : { "messageicons":"module" } // optional, depend on a specific library to be used with 'require' - see provides_modules + "dependencies" : { "message":"widget" } // optional, depend on a specific type of widget - see provides_widgets + "provides_modules" : ["messageicons"] // optional, this app provides a module that can be used with 'require' + "provides_widgets" : ["battery"] // optional, this app provides a type of widget - 'alarm/battery/bluetooth/pedometer/message' + "provides_features" : ["welcome"] // optional, this app provides some feature, used to ensure two aren't installed at once. Currently just 'welcome' + "default" : true, // set if an app is the default implementer of something (a widget/module/etc) "readme": "README.md", // if supplied, a link to a markdown-style text file // that contains more information about this app (usage, etc) // A 'Read more...' link will be added under the app @@ -282,7 +304,7 @@ and which gives information about the app for the Launcher. "customConnect": true, // if supplied, ensure we are connected to a device // before the "custom.html" iframe is loaded. An // onInit function in "custom.html" is then called - // with info on the currently connected device. + // with info on the currently connected device. "interface": "interface.html", // if supplied, apps/interface.html is loaded in an // iframe, and it may interact with the connected Bangle @@ -310,9 +332,9 @@ and which gives information about the app for the Launcher. {"name":"appid.data.json", // filename used in storage "storageFile":true // if supplied, file is treated as storageFile "url":"", // if supplied URL of file to load (currently relative to apps/) - "content":"...", // if supplied, this content is loaded directly + "content":"...", // if supplied, this content is loaded directly "evaluate":true, // if supplied, data isn't quoted into a String before upload - // (eg it's evaluated as JS) + // (eg it's evaluated as JS) }, {"wildcard":"appid.data.*" // wildcard of filenames used in storage }, // this is mutually exclusive with using "name" @@ -324,7 +346,7 @@ and which gives information about the app for the Launcher. ``` * name, icon and description present the app in the app loader. -* tags is used for grouping apps in the library, separate multiple entries by comma. Known tags are `tool`, `system`, `clock`, `game`, `sound`, `gps`, `widget`, `launcher` or empty. +* tags is used for grouping apps in the library, separate multiple entries by comma. Known tags are `tool`, `system`, `clock`, `game`, `sound`, `gps`, `widget`, `launcher`, `bluetooth` or empty. * storage is used to identify the app files and how to handle them * data is used to clean up files when the app is uninstalled @@ -385,7 +407,7 @@ in an iframe.
- +