/*JSON{ "type" : "method", "class" : "Object", "name" : "removeAllListeners", "generate" : "jswrap_object_removeAllListeners", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"] ] } Removes all listeners, or those of the specified event. */ void jswrap_object_removeAllListeners(JsVar *parent, JsVar *event) { if (!jsvHasChildren(parent)) { jsWarn("Parent must be an object - not a String, Integer, etc."); return; } if (jsvIsString(event)) { // remove the whole child containing listeners JsVar *eventName = jsvVarPrintf(JS_EVENT_PREFIX"%s",event); if (!eventName) return; // no memory JsVar *eventList = jsvFindChildFromVar(parent, eventName, true); jsvUnLock(eventName); if (eventList) { jsvRemoveChild(parent, eventList); jsvUnLock(eventList); } } else if (jsvIsUndefined(event)) { // Eep. We must remove everything beginning with '#on' (JS_EVENT_PREFIX) JsvObjectIterator it; jsvObjectIteratorNew(&it, parent); while (jsvObjectIteratorHasValue(&it)) { JsVar *key = jsvObjectIteratorGetKey(&it); jsvObjectIteratorNext(&it); if (jsvIsStringEqualOrStartsWith(key, JS_EVENT_PREFIX, true)) { // begins with #on - we must kill it jsvRemoveChild(parent, key); } jsvUnLock(key); } jsvObjectIteratorFree(&it); } else { jsWarn("First argument to EventEmitter.removeAllListeners(..) must be a string, or undefined"); return; } }
/*JSON{ "type" : "function", "name" : "clearTimeout", "generate" : "jswrap_interface_clearTimeout", "params" : [ ["id","JsVar","The id returned by a previous call to setTimeout"] ] } Clear the Timeout that was created with setTimeout, for example: ```var id = setTimeout(function () { print('foo'); }, 1000);``` ```clearTimeout(id);``` If no argument is supplied, all timers and intervals are stopped */ void _jswrap_interface_clearTimeoutOrInterval(JsVar *idVar, bool isTimeout) { JsVar *timerArrayPtr = jsvLock(timerArray); if (jsvIsUndefined(idVar)) { /* Delete all timers EXCEPT those with a 'watch' field, as those were generated by jsinteractive.c for debouncing watches */ JsvObjectIterator it; jsvObjectIteratorNew(&it, timerArrayPtr); while (jsvObjectIteratorHasValue(&it)) { JsVar *timerPtr = jsvObjectIteratorGetValue(&it); JsVar *watchPtr = jsvObjectGetChild(timerPtr, "watch", 0); if (!watchPtr) jsvObjectIteratorRemoveAndGotoNext(&it, timerArrayPtr); else jsvObjectIteratorNext(&it); jsvUnLock2(watchPtr, timerPtr); } jsvObjectIteratorFree(&it); } else { JsVar *child = jsvIsBasic(idVar) ? jsvFindChildFromVar(timerArrayPtr, idVar, false) : 0; if (child) { JsVar *timerArrayPtr = jsvLock(timerArray); jsvRemoveChild(timerArrayPtr, child); jsvUnLock2(child, timerArrayPtr); } else { if (isTimeout) jsExceptionHere(JSET_ERROR, "Unknown Timeout"); else jsExceptionHere(JSET_ERROR, "Unknown Interval"); } } jsvUnLock(timerArrayPtr); jsiTimersChanged(); // mark timers as changed }
/*JSON{ "type" : "method", "class" : "Object", "name" : "removeListener", "generate" : "jswrap_object_removeListener", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"], ["listener","JsVar","The listener to remove"] ] } Removes the specified event listener. ``` function foo(d) { console.log(d); } Serial1.on("data", foo); Serial1.removeListener("data", foo); ``` */ void jswrap_object_removeListener(JsVar *parent, JsVar *event, JsVar *callback) { if (!jsvHasChildren(parent)) { jsWarn("Parent must be an object - not a String, Integer, etc."); return; } if (jsvIsString(event)) { // remove the whole child containing listeners JsVar *eventName = jsvVarPrintf(JS_EVENT_PREFIX"%s",event); if (!eventName) return; // no memory JsVar *eventListName = jsvFindChildFromVar(parent, eventName, true); jsvUnLock(eventName); JsVar *eventList = jsvSkipName(eventListName); if (eventList) { if (eventList == callback) { // there's no array, it was a single item jsvRemoveChild(parent, eventListName); } else if (jsvIsArray(eventList)) { // it's an array, search for the index JsVar *idx = jsvGetArrayIndexOf(eventList, callback, true); if (idx) { jsvRemoveChild(eventList, idx); jsvUnLock(idx); } } jsvUnLock(eventList); } jsvUnLock(eventListName); } else { jsWarn("First argument to EventEmitter.removeListener(..) must be a string"); return; } }
/*JSON{ "type" : "method", "class" : "Object", "name" : "hasOwnProperty", "generate" : "jswrap_object_hasOwnProperty", "params" : [ ["name","JsVar","The name of the property to search for"] ], "return" : ["bool","True if it exists, false if it doesn't"] } Return true if the object (not its prototype) has the given property. NOTE: This currently returns false-positives for built-in functions in prototypes */ bool jswrap_object_hasOwnProperty(JsVar *parent, JsVar *name) { JsVar *propName = jsvAsArrayIndex(name); bool contains = false; if (jsvHasChildren(parent)) { JsVar *foundVar = jsvFindChildFromVar(parent, propName, false); if (foundVar) { contains = true; jsvUnLock(foundVar); } } if (!contains && !jsvIsObject(parent)) { /* search builtin symbol table, but not for Objects, as these * are descended from Objects but do not themselves contain * an Object's properties */ const JswSymList *symbols = jswGetSymbolListForObject(parent); if (symbols) { char str[32]; jsvGetString(propName, str, sizeof(str)); JsVar *v = jswBinarySearch(symbols, parent, str); if (v) contains = true; jsvUnLock(v); } } jsvUnLock(propName); return contains; }
/*JSON{ "type":"function", "name" : "require", "description" : "Load the given module, and return the exported functions", "generate" : "jswrap_require", "params" : [ [ "moduleName", "JsVar", "A String containing the name of the given module"] ], "return" : ["JsVar", "The result of evaluating the string"] }*/ JsVar *jswrap_require(JsVar *moduleName) { if (!jsvIsString(moduleName)) { jsWarn("Expecting a module name as a string, but got %t", moduleName); return 0; } // Search to see if we have already loaded this module JsVar *moduleList = jswrap_modules_getModuleList(); if (!moduleList) return 0; // out of memory JsVar *moduleExportName = jsvFindChildFromVar(moduleList, moduleName, true); jsvUnLock(moduleList); if (!moduleExportName) return 0; // out of memory JsVar *moduleExport = jsvSkipName(moduleExportName); if (moduleExport) { // Found the module! jsvUnLock(moduleExportName); return moduleExport; } // Now check if it is built-in char moduleNameBuf[32]; jsvGetString(moduleName, moduleNameBuf, sizeof(moduleNameBuf)); if (jswIsBuiltInLibrary(moduleNameBuf)) { // create a 'fake' module that Espruino can use to map its built-in functions against moduleExport = jspNewBuiltin(moduleNameBuf); } else { // Now try and load it JsVar *fileContents = 0; //if (jsvIsStringEqual(moduleName,"http")) {} //if (jsvIsStringEqual(moduleName,"fs")) {} #ifdef USE_FILESYSTEM JsVar *modulePath = jsvNewFromString( #ifdef LINUX "node_modules/" #else "NODE_M~1/" #endif ); if (!modulePath) { jsvUnLock(moduleExportName); return 0; } // out of memory jsvAppendStringVarComplete(modulePath, moduleName); jsvAppendString(modulePath,".js"); fileContents = wrap_fat_readFile(modulePath); jsvUnLock(modulePath); #endif if (!fileContents || jsvIsStringEqual(fileContents,"")) { jsvUnLock(moduleExportName); jsvUnLock(fileContents); jsWarn("Module not found"); return 0; } moduleExport = jspEvaluateModule(jsiGetParser(), fileContents); jsvUnLock(fileContents); } assert(moduleExport); jsvSetValueOfName(moduleExportName, moduleExport); // save in cache jsvUnLock(moduleExportName); return moduleExport; }
/*JSON{ "type":"function", "name" : "edit", "description" : ["Fill the console with the contents of the given function, so you can edit it.", "NOTE: This is a convenience function - it will not edit 'inner functions'. For that, you must edit the 'outer function' and re-execute it."], "generate" : "jswrap_interface_edit", "params" : [ [ "funcName", "JsVar", "The name of the function to edit (either a string or just the unquoted name)"] ] }*/ void jswrap_interface_edit(JsVar *funcName) { JsVar *func = 0; if (jsvIsString(funcName)) { funcName = jsvLockAgain(funcName); func = jsvSkipNameAndUnLock(jsvFindChildFromVar(execInfo.root, funcName, 0)); } else { func = funcName; funcName = jsvGetPathTo(execInfo.root, func, 2); } if (jsvIsString(funcName)) { if (jsvIsFunction(func)) { JsVar *scopeVar = jsvFindChildFromString(func, JSPARSE_FUNCTION_SCOPE_NAME, false); JsVar *inRoot = jsvGetArrayIndexOf(execInfo.root, func, true); bool normalDecl = scopeVar==0 && inRoot!=0; jsvUnLock(inRoot); jsvUnLock(scopeVar); JsVar *newLine = jsvNewFromEmptyString(); if (newLine) { // could be out of memory /* normalDecl: * * function foo() { ... } * * NOT normalDecl: * * foo.replaceWith(function() { ... }); * */ JsVar *funcData = jsvAsString(func, false); if (normalDecl) { jsvAppendString(newLine, "function "); jsvAppendStringVarComplete(newLine, funcName); jsvAppendStringVar(newLine, funcData, 9, JSVAPPENDSTRINGVAR_MAXLENGTH); } else { jsvAppendStringVarComplete(newLine, funcName); jsvAppendString(newLine, ".replaceWith("); jsvAppendStringVarComplete(newLine, funcData); jsvAppendString(newLine, ");"); } jsvUnLock(funcData); jsiReplaceInputLine(newLine); jsvUnLock(newLine); } } else { jsError("Edit should be called with the name of a function"); } } else { jsError("Edit should be called with edit(funcName) or edit('funcName')"); } jsvUnLock(func); jsvUnLock(funcName); }
/*JSON{ "type" : "method", "class" : "Object", "name" : "on", "generate" : "jswrap_object_on", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"], ["listener","JsVar","The listener to call when this event is received"] ] } Register an event listener for this object, for instance ```http.on('data', function(d) {...})```. See Node.js's EventEmitter. */ void jswrap_object_on(JsVar *parent, JsVar *event, JsVar *listener) { if (!jsvHasChildren(parent)) { jsWarn("Parent must be an object - not a String, Integer, etc."); return; } if (!jsvIsString(event)) { jsWarn("First argument to EventEmitter.on(..) must be a string"); return; } if (!jsvIsFunction(listener) && !jsvIsString(listener)) { jsWarn("Second argument to EventEmitter.on(..) must be a function or a String (containing code)"); return; } JsVar *eventName = jsvVarPrintf(JS_EVENT_PREFIX"%s",event); if (!eventName) return; // no memory JsVar *eventList = jsvFindChildFromVar(parent, eventName, true); jsvUnLock(eventName); JsVar *eventListeners = jsvSkipName(eventList); if (jsvIsUndefined(eventListeners)) { // just add jsvSetValueOfName(eventList, listener); } else { if (jsvIsArray(eventListeners)) { // we already have an array, just add to it jsvArrayPush(eventListeners, listener); } else { // not an array - we need to make it an array JsVar *arr = jsvNewEmptyArray(); jsvArrayPush(arr, eventListeners); jsvArrayPush(arr, listener); jsvSetValueOfName(eventList, arr); jsvUnLock(arr); } } jsvUnLock2(eventListeners, eventList); /* Special case if we're a data listener and data has already arrived then * we queue an event immediately. */ if (jsvIsStringEqual(event, "data")) { JsVar *buf = jsvObjectGetChild(parent, STREAM_BUFFER_NAME, 0); if (jsvIsString(buf)) { jsiQueueObjectCallbacks(parent, STREAM_CALLBACK_NAME, &buf, 1); jsvRemoveNamedChild(parent, STREAM_BUFFER_NAME); } jsvUnLock(buf); } }
/*JSON{ "type" : "function", "name" : "clearTimeout", "generate" : "jswrap_interface_clearTimeout", "params" : [ ["id","JsVar","The id returned by a previous call to setTimeout"] ] } Clear the Timeout that was created with setTimeout, for example: ```var id = setTimeout(function () { print('foo'); }, 1000);``` ```clearTimeout(id);``` If no argument is supplied, all timers and intervals are stopped */ void _jswrap_interface_clearTimeoutOrInterval(JsVar *idVar, bool isTimeout) { JsVar *timerArrayPtr = jsvLock(timerArray); if (jsvIsUndefined(idVar)) { jsvRemoveAllChildren(timerArrayPtr); } else { JsVar *child = jsvIsBasic(idVar) ? jsvFindChildFromVar(timerArrayPtr, idVar, false) : 0; if (child) { JsVar *timerArrayPtr = jsvLock(timerArray); jsvRemoveChild(timerArrayPtr, child); jsvUnLock2(child, timerArrayPtr); } else { jsExceptionHere(JSET_ERROR, isTimeout ? "Unknown Timeout" : "Unknown Interval"); } } jsvUnLock(timerArrayPtr); jsiTimersChanged(); // mark timers as changed }
/*JSON{ "type":"function", "name" : "clearTimeout", "description" : ["Clear the Timeout that was created with setTimeout, for example:", "```var id = setTimeout(function () { print('foo'); }, 1000);```", "```clearTimeout(id);```", "If no argument is supplied, all timers and intervals are stopped" ], "generate" : "jswrap_interface_clearTimeout", "params" : [ [ "id", "JsVar", "The id returned by a previous call to setTimeout"] ] }*/ void _jswrap_interface_clearTimeoutOrInterval(JsVar *idVar, bool isTimeout) { JsVar *timerArrayPtr = jsvLock(timerArray); if (jsvIsUndefined(idVar)) { jsvRemoveAllChildren(timerArrayPtr); } else { JsVar *child = jsvIsBasic(idVar) ? jsvFindChildFromVar(timerArrayPtr, idVar, false) : 0; if (child) { JsVar *timerArrayPtr = jsvLock(timerArray); jsvRemoveChild(timerArrayPtr, child); jsvUnLock(child); jsvUnLock(timerArrayPtr); } else { jsError(isTimeout ? "Unknown Timeout" : "Unknown Interval"); } } jsvUnLock(timerArrayPtr); }
/*JSON{ "type":"staticmethod", "class" : "Modules", "name" : "removeCached", "description" : "Remove the given module from the list of cached modules", "generate" : "jswrap_modules_removeCached", "params" : [ [ "id", "JsVar", "The module name to remove"] ] }*/ void jswrap_modules_removeCached(JsVar *id) { if (!jsvIsString(id)) { jsExceptionHere(JSET_ERROR, "The argument to removeCached must be a string"); return; } JsVar *moduleList = jswrap_modules_getModuleList(); if (!moduleList) return; // out of memory JsVar *moduleExportName = jsvFindChildFromVar(moduleList, id, false); if (!moduleExportName) { jsWarn("Module not found"); } else { jsvRemoveChild(moduleList, moduleExportName); jsvUnLock(moduleExportName); } jsvUnLock(moduleList); }
/*JSON{ "type" : "function", "name" : "changeInterval", "generate" : "jswrap_interface_changeInterval", "params" : [ ["id","JsVar","The id returned by a previous call to setInterval"], ["time","float","The new time period in ms"] ] } Change the Interval on a callback created with setInterval, for example: ```var id = setInterval(function () { print('foo'); }, 1000); // every second``` ```changeInterval(id, 1500); // now runs every 1.5 seconds``` This takes effect the next time the callback is called (so it is not immediate). */ void jswrap_interface_changeInterval(JsVar *idVar, JsVarFloat interval) { JsVar *timerArrayPtr = jsvLock(timerArray); if (interval<TIMER_MIN_INTERVAL) interval=TIMER_MIN_INTERVAL; JsVar *timerName = jsvIsBasic(idVar) ? jsvFindChildFromVar(timerArrayPtr, idVar, false) : 0; if (timerName) { JsVar *timer = jsvSkipNameAndUnLock(timerName); JsVar *v; JsVarInt intervalInt = (JsVarInt)jshGetTimeFromMilliseconds(interval); v = jsvNewFromInteger(intervalInt); jsvUnLock2(jsvSetNamedChild(timer, v, "interval"), v); v = jsvNewFromInteger((JsVarInt)(jshGetSystemTime()-jsiLastIdleTime) + intervalInt); jsvUnLock3(jsvSetNamedChild(timer, v, "time"), v, timer); // timerName already unlocked jsiTimersChanged(); // mark timers as changed } else { jsExceptionHere(JSET_ERROR, "Unknown Interval"); } jsvUnLock(timerArrayPtr); }
/*JSON{ "type" : "staticmethod", "class" : "Object", "name" : "defineProperty", "generate" : "jswrap_object_defineProperty", "params" : [ ["obj","JsVar","An object"], ["name","JsVar","The name of the property"], ["desc","JsVar","The property descriptor"] ], "return" : ["JsVar","The object, obj."] } Add a new property to the Object. 'Desc' is an object with the following fields: * `configurable` (bool = false) - can this property be changed/deleted * `enumerable` (bool = false) - can this property be enumerated * `value` (anything) - the value of this property * `writable` (bool = false) - can the value be changed with the assignment operator? * `get` (function) - the getter function, or undefined if no getter * `set` (function) - the setter function, or undefined if no setter * **Note:** `configurable`, `enumerable`, `writable`, `get`, and `set` are not implemented and will be ignored. */ JsVar *jswrap_object_defineProperty(JsVar *parent, JsVar *propName, JsVar *desc) { if (!jsvIsObject(parent)) { jsExceptionHere(JSET_ERROR, "First argument must be an object, got %t", parent); return 0; } if (!jsvIsObject(desc)) { jsExceptionHere(JSET_ERROR, "Property description must be an object, got %t", desc); return 0; } JsVar *name = jsvAsArrayIndex(propName); JsVar *value = jsvObjectGetChild(desc, "value", 0); JsVar *property = jsvFindChildFromVar(parent, name, true); jsvUnLock(name); if (property && value) jsvSetValueOfName(property, value); jsvUnLock2(property, value); return jsvLockAgain(parent); }
/*JSON{ "type":"staticmethod", "class" : "Modules", "name" : "addCached", "description" : "Add the given module to the cache", "generate" : "jswrap_modules_addCached", "params" : [ [ "id", "JsVar", "The module name to add" ], [ "sourcecode", "JsVar", "The module's sourcecode" ] ] }*/ void jswrap_modules_addCached(JsVar *id, JsVar *sourceCode) { if (!jsvIsString(id) || !jsvIsString(sourceCode)) { jsError("Both arguments to addCached must be strings"); return; } JsVar *moduleList = jswrap_modules_getModuleList(); if (!moduleList) return; // out of memory JsVar *moduleExport = jspEvaluateModule(jsiGetParser(), sourceCode); if (!moduleExport) { jsWarn("Unable to load module"); } else { JsVar *moduleName = jsvFindChildFromVar(moduleList, id, true); if (moduleName) jsvSetValueOfName(moduleName, moduleExport); jsvUnLock(moduleExport); } jsvUnLock(moduleList); }
/*JSON{ "type":"function", "name" : "changeInterval", "description" : ["Change the Interval on a callback created with setInterval, for example:", "```var id = setInterval(function () { print('foo'); }, 1000); // every second```", "```changeInterval(id, 1500); // now runs every 1.5 seconds```", "This takes effect the text time the callback is called (so it is not immediate)."], "generate" : "jswrap_interface_changeInterval", "params" : [ [ "id", "JsVar", "The id returned by a previous call to setInterval"], [ "time","float","The new time period in ms" ] ] }*/ void jswrap_interface_changeInterval(JsVar *idVar, JsVarFloat interval) { JsVar *timerArrayPtr = jsvLock(timerArray); if (interval<TIMER_MIN_INTERVAL) interval=TIMER_MIN_INTERVAL; JsVar *timerName = jsvIsBasic(idVar) ? jsvFindChildFromVar(timerArrayPtr, idVar, false) : 0; if (timerName) { JsVar *timer = jsvSkipNameAndUnLock(timerName); JsVar *v; v = jsvNewFromInteger(jshGetTimeFromMilliseconds(interval)); jsvUnLock(jsvSetNamedChild(timer, v, "interval")); jsvUnLock(v); v = jsvNewFromInteger(jshGetSystemTime() + jshGetTimeFromMilliseconds(interval)); jsvUnLock(jsvSetNamedChild(timer, v, "time")); jsvUnLock(v); jsvUnLock(timer); // timerName already unlocked } else { jsError("Unknown Interval"); } jsvUnLock(timerArrayPtr); }
/*JSON{ "type":"function", "name" : "edit", "description" : ["Fill the console with the contents of the given function, so you can edit it.", "NOTE: This is a convenience function - it will not edit 'inner functions'. For that, you must edit the 'outer function' and re-execute it."], "generate" : "jswrap_interface_edit", "params" : [ [ "funcName", "JsVarName", "The name of the function to edit (either a string or just the unquoted name)"] ] }*/ void jswrap_interface_edit(JsVar *funcName) { if (jsvIsString(funcName)) { JsVar *func = 0; if (jsvIsName(funcName)) func = jsvSkipName(funcName); else func = jsvSkipNameAndUnLock(jsvFindChildFromVar(jsiGetParser()->root, funcName, 0)); if (jsvIsFunction(func)) { JsVar *scopeVar = jsvFindChildFromString(func, JSPARSE_FUNCTION_SCOPE_NAME, false); JsVarRef scope = jsvGetRef(scopeVar); jsvUnLock(scopeVar); JsVar *newLine = jsvNewFromEmptyString(); if (newLine) { // could be out of memory jsvAppendStringVarComplete(newLine, funcName); if (scope) { // If we have a scope, it's an internal function so we will need to write different code jsvAppendString(newLine, ".replaceWith("); } else { jsvAppendString(newLine, " = "); } JsVar *funcData = jsvAsString(func, false); if (funcData) jsvAppendStringVarComplete(newLine, funcData); jsvUnLock(funcData); if (scope) { jsvAppendString(newLine, ");"); } else { jsvAppendString(newLine, ";"); } jsiReplaceInputLine(newLine); jsvUnLock(newLine); } } else { jsError("Edit should be called with the name of a function"); } jsvUnLock(func); } else { jsError("Edit should be called with edit(funcName) or edit('funcName')"); } }
/*JSON{ "type" : "method", "class" : "Object", "name" : "emit", "generate" : "jswrap_object_emit", "params" : [ ["event","JsVar","The name of the event, for instance 'data'"], ["args","JsVarArray","Optional arguments"] ] } Call the event listeners for this object, for instance ```http.emit('data', 'Foo')```. See Node.js's EventEmitter. */ void jswrap_object_emit(JsVar *parent, JsVar *event, JsVar *argArray) { if (!jsvHasChildren(parent)) { jsWarn("Parent must be an object - not a String, Integer, etc."); return; } if (!jsvIsString(event)) { jsWarn("First argument to EventEmitter.emit(..) must be a string"); return; } JsVar *eventName = jsvVarPrintf(JS_EVENT_PREFIX"%s",event); if (!eventName) return; // no memory // extract data const unsigned int MAX_ARGS = 4; JsVar *args[MAX_ARGS]; unsigned int n = 0; JsvObjectIterator it; jsvObjectIteratorNew(&it, argArray); while (jsvObjectIteratorHasValue(&it)) { if (n>=MAX_ARGS) { jsWarn("Too many arguments"); break; } args[n++] = jsvObjectIteratorGetValue(&it); jsvObjectIteratorNext(&it); } jsvObjectIteratorFree(&it); JsVar *callback = jsvSkipNameAndUnLock(jsvFindChildFromVar(parent, eventName, 0)); jsvUnLock(eventName); if (callback) jsiQueueEvents(parent, callback, args, (int)n); jsvUnLock(callback); // unlock jsvUnLockMany(n, args); }