diff --git a/typescript/generate.js b/typescript/generate.js new file mode 100644 index 000000000..ffa8d6bf2 --- /dev/null +++ b/typescript/generate.js @@ -0,0 +1,136 @@ +const fetch = (...args) => + import("node-fetch").then(({ default: fetch }) => fetch(...args)); +const fs = require("fs"); + +const TAKEN_IDENTIFIERS = ["ArrayBufferView", "crypto", "File", "Storage"]; + +function getType(type) { + if (type.startsWith("+")) type = type.substring(1); + if (TAKEN_IDENTIFIERS.includes(type)) return "Espruino" + type; + switch (type) { + case undefined: + case "?": + return "any"; + case "bool": + return "boolean"; + case "String": + return "string"; + case "Array": + return "any[]"; + case "Promise": + return "Promise"; + default: + return type; + } +} + +let indent = 0; +let topLevel = true; +let file = []; + +function add(text) { + if (text) + file = file.concat( + text.split("\n").map((line) => " ".repeat(indent) + line) + ); + else file.push(""); +} + +function get(key, obj, isGlobal) { + if (key.startsWith("!")) return; + if (key === "prototype") return; + if (key in global && isGlobal) return; + if (TAKEN_IDENTIFIERS.includes(key)) key = "Espruino" + key; + add( + "/**\n" + + (obj["!doc"] || "") + .split("\n") + .filter((line) => line) + .map((line) => line.replace(/^

(.*)<\/p>$/, "$1")) + .concat([`@url ${obj["!url"]}`]) + .map((line) => " * " + line) + .join("\n") + + "\n */" + ); + + const type = obj["!type"] || "?"; + const hasProperties = Object.keys(obj).filter( + (key) => !key.startsWith("!") && key !== "prototype" + ).length; + if (type.startsWith("fn(")) { + const returnType = getType( + type.includes("->") ? type.replace(/^.*-> (.*)$/, "$1") : "void" + ); + let args = type.replace(/^fn\((.*)\).*/, "$1"); + if (args) + args = args + .split(", ") + .map((argument) => { + const pair = argument.split(": "); + if (pair[0] === "function") pair[0] = "fn"; + if (pair[0] === "var") pair[0] = "variable"; + pair[1] = getType(pair[1]); + return pair.join(": "); + }) + .join(", "); + if (topLevel) { + add( + `${indent ? "" : "declare "}function ${key}(${args}): ${returnType};` + ); + } else { + add(`${key}: (${args}) => ${returnType};`); + } + + if (hasProperties) { + add(""); + add(`declare namespace ${key} {`); + indent += 2; + for (const key in obj) { + get(key, obj[key], true); + } + indent -= 2; + add("}"); + } + } else { + if (hasProperties) { + add(`${indent ? "" : "declare "}const ${key}: ${getType(type)} & {`); + indent += 2; + topLevel = false; + for (const key in obj) { + get(key, obj[key], true); + } + topLevel = true; + indent -= 2; + add("};"); + } else if (topLevel) { + add(`${indent ? "" : "declare "}const ${key}: ${getType(type)};`); + } else { + add(`${key}: ${getType(type)}`); + } + } + + if (obj.prototype) { + add(""); + add(`type ${key} = {`); + indent += 2; + topLevel = false; + for (const key in obj.prototype) { + get(key, obj.prototype[key], true); + } + topLevel = true; + indent -= 2; + add("}"); + } + + add(""); +} + +fetch("https://espruino.com/json/espruino.json") + .then((response) => response.json()) + .then((json) => { + add("/* Note: This file was automatically generated. */\n"); + for (const key in json) { + get(key, json[key], true); + } + fs.writeFileSync("types/main.d.ts", file.join("\n")); + }); diff --git a/typescript/types/main.d.ts b/typescript/types/main.d.ts index b299f1ea9..af6c8253a 100644 --- a/typescript/types/main.d.ts +++ b/typescript/types/main.d.ts @@ -1,50 +1,59 @@ /* Note: This file was automatically generated. */ -/* This library allows you to write to Neopixel/WS281x/APA10x/SK6812 LED strips +/** + * This library allows you to write to Neopixel/WS281x/APA10x/SK6812 LED strips *

These use a high speed single-wire protocol which needs platform-specific * implementation on some devices - hence this library to simplify things.

* @url http://www.espruino.com/Reference#l_neopixel_undefined */ declare function neopixel(): void; -/* This library provides TV out capability on the Espruino and Espruino Pico. +/** + * This library provides TV out capability on the Espruino and Espruino Pico. * See the Television page for more information. * @url http://www.espruino.com/Reference#l_tv_undefined */ declare function tv(): void; -/* The NRF class is for controlling functionality of the Nordic nRF51/nRF52 chips. +/** + * The NRF class is for controlling functionality of the Nordic nRF51/nRF52 chips. * Most functionality is related to Bluetooth Low Energy, however there are also some functions related to NFC that apply to NRF52-based devices. * @url http://www.espruino.com/Reference#NRF */ declare function NRF(): void; declare namespace NRF { - /* @url http://www.espruino.com/Reference#l_NRF_getSecurityStatus + /** + * @url http://www.espruino.com/Reference#l_NRF_getSecurityStatus */ function getSecurityStatus(): any; - /* Get this device's default Bluetooth MAC address. + /** + * Get this device's default Bluetooth MAC address. *

For Puck.js, the last 5 characters of this (eg. ee:ff) * are used in the device's advertised Bluetooth name.

* @url http://www.espruino.com/Reference#l_NRF_getAddress */ function getAddress(): any; - /* @url http://www.espruino.com/Reference#l_NRF_setServices + /** + * @url http://www.espruino.com/Reference#l_NRF_setServices */ function setServices(data: any, options: any): void; - /* @url http://www.espruino.com/Reference#l_NRF_setAdvertising + /** + * @url http://www.espruino.com/Reference#l_NRF_setAdvertising */ function setAdvertising(data: any, options: any): void; - /* If a device is connected to Espruino, disconnect from it. + /** + * If a device is connected to Espruino, disconnect from it. * @url http://www.espruino.com/Reference#l_NRF_disconnect */ function disconnect(): void; - /*

Disable Bluetooth advertising and disconnect from any device that + /** + *

Disable Bluetooth advertising and disconnect from any device that * connected to Puck.js as a peripheral (this won't affect any devices * that Puck.js initiated connections to).

* This makes Puck.js undiscoverable, so it can't be connected to. @@ -53,14 +62,16 @@ declare namespace NRF { */ function sleep(): void; - /*

Enable Bluetooth advertising (this is enabled by default), which + /** + *

Enable Bluetooth advertising (this is enabled by default), which * allows other devices to discover and connect to Puck.js.

* Use NRF.sleep() to disable advertising. * @url http://www.espruino.com/Reference#l_NRF_wake */ function wake(): void; - /*

Restart the Bluetooth softdevice (if there is currently a BLE connection, + /** + *

Restart the Bluetooth softdevice (if there is currently a BLE connection, * it will queue a restart to be done when the connection closes).

*

You shouldn't need to call this function in normal usage. However, Nordic's * BLE softdevice has some settings that cannot be reset. For example there @@ -70,25 +81,29 @@ declare namespace NRF { */ function restart(callback: any): void; - /* Get the battery level in volts (the voltage that the NRF chip is running off of). + /** + * Get the battery level in volts (the voltage that the NRF chip is running off of). *

This is the battery level of the device itself - it has nothing to with any * device that might be connected.

* @url http://www.espruino.com/Reference#l_NRF_getBattery */ function getBattery(): number; - /*

This is just like NRF.setAdvertising, except instead of advertising + /** + *

This is just like NRF.setAdvertising, except instead of advertising * the data, it returns the packet that would be advertised as an array.

* @url http://www.espruino.com/Reference#l_NRF_getAdvertisingData */ function getAdvertisingData(data: any, options: any): any; - /* Set the BLE radio transmit power. The default TX power is 0 dBm, and + /** + * Set the BLE radio transmit power. The default TX power is 0 dBm, and * @url http://www.espruino.com/Reference#l_NRF_setTxPower */ function setTxPower(power: number): void; - /*

THIS IS DEPRECATED - please use NRF.setConnectionInterval for + /** + *

THIS IS DEPRECATED - please use NRF.setConnectionInterval for * peripheral and NRF.connect(addr, options)/BluetoothRemoteGATTServer.connect(options) * for central connections.

*

This sets the connection parameters - these affect the transfer speed and @@ -106,32 +121,38 @@ declare namespace NRF { */ function setLowPowerConnection(lowPower: boolean): void; - /* Send a USB HID report. HID must first be enabled with NRF.setServices({}, {hid: hid_report}) + /** + * Send a USB HID report. HID must first be enabled with NRF.setServices({}, {hid: hid_report}) * @url http://www.espruino.com/Reference#l_NRF_sendHIDReport */ function sendHIDReport(data: any, callback: any): void; - /* Check if Apple Notification Center Service (ANCS) is currently active on the BLE connection + /** + * Check if Apple Notification Center Service (ANCS) is currently active on the BLE connection * @url http://www.espruino.com/Reference#l_NRF_ancsIsActive */ function ancsIsActive(): boolean; - /* Send an ANCS action for a specific Notification UID. Corresponds to posaction/negaction in the 'ANCS' event that was received + /** + * Send an ANCS action for a specific Notification UID. Corresponds to posaction/negaction in the 'ANCS' event that was received * @url http://www.espruino.com/Reference#l_NRF_ancsAction */ function ancsAction(uid: number, positive: boolean): void; - /* Get ANCS info for a notification, eg: + /** + * Get ANCS info for a notification, eg: * @url http://www.espruino.com/Reference#l_NRF_ancsGetNotificationInfo */ function ancsGetNotificationInfo(uid: number): Promise; - /* Check if Apple Media Service (AMS) is currently active on the BLE connection + /** + * Check if Apple Media Service (AMS) is currently active on the BLE connection * @url http://www.espruino.com/Reference#l_NRF_amsIsActive */ function amsIsActive(): boolean; - /*

Get Apple Media Service (AMS) info for the current media player. + /** + *

Get Apple Media Service (AMS) info for the current media player. * "playbackinfo" returns a concatenation of three comma-separated values:

*