G2A Many GEOs
SHARE
TWEET

testing/learning utility library for node.js

mvaganov Mar 10th, 2015 177 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  * Custom functionality written by Michael Vaganov, while learning Node.js and JavaScript
  3.  * MIT License.
  4.  * @module mvaganov
  5.  */
  6.  
  7. var url = require("url");
  8.  
  9. /**
  10.  * add functionality to the String implementation.... pretty sweet that JavaScript can do this
  11.  */
  12. function addToStrings()
  13. {       "use strict";
  14.         if (typeof String.prototype.startsWith !== 'function')
  15.         {
  16.                 String.prototype.startsWith = function (str){
  17.                         return this.substring(0, str.length) === str; //this.slice(0, str.length) === str;
  18.                 }
  19.         }
  20.         if (typeof String.prototype.replaceAll !== 'function')
  21.         {
  22.                 /**
  23.                  * @param {string} str1
  24.                  * @param {string} str2
  25.                  * @param {(boolean|null)} ignore ignore case?
  26.                  * @return {string} a new string, a copy of this one, with all instances of str1 replaced with str2.
  27.                  */
  28.                 String.prototype.replaceAll = function(str1, str2, ignore)
  29.                 {
  30.                         return this.replace(new RegExp(
  31.                                 str1.replace(
  32.                                         /([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g, "\\$&"
  33.                                 ),
  34.                                 (ignore?"gi":"g")),
  35.                                 (typeof(str2)=="string")?str2.replace(/\$/g,"$$$$"):str2
  36.                         );
  37.                 }
  38.         }
  39.         if (typeof String.prototype.indexOfOneOfThese !== 'function')
  40.         {
  41.                 /**
  42.                  * @param {Array<String>} listOfDelimeters possible string delimeters that are being sought after
  43.                  * @param {number=} start where to start looking in the string
  44.                  * @return {Array<number>} [index that has one of these first, which delimeter was actually found here].
  45.                  * if none of these exist, returns [this.length, -1]
  46.                  * return[0] is the index
  47.                  * return[1] is the index of the delimeter that was found
  48.                  */
  49.                 String.prototype.indexOfOneOfThese = function (listOfDelimeters, start)
  50.                 {
  51.                         var bestIndex = this.length;
  52.                         var foundDelimeter = -1;
  53.                         if(start == null) start = 0;
  54.                         for(var i = 0; i < listOfDelimeters.length; ++i)
  55.                         {
  56.                                 var index = this.indexOf(listOfDelimeters[i], start);
  57.                                 if(index >= 0 && index < bestIndex)
  58.                                 {
  59.                                         foundDelimeter  = i;
  60.                                         bestIndex = index;
  61.                                 }
  62.                         }
  63.                         return [bestIndex, foundDelimeter];
  64.                 }
  65.         }
  66.         if (typeof String.prototype.splitByOneOfThese !== 'function')
  67.         {
  68.                 /**
  69.                  * @param {Array<String>} listOfDelimeters possible string delimeters that are being sought after
  70.                  * @param {Number} maxSplits how many times to split. will split from left to right. -1 means no limit
  71.                  * @return {Array<String>} as split, except with multiple delimeter tokens
  72.                  */
  73.                 String.prototype.splitByOneOfThese = function (listOfDelimeters, maxSplits)
  74.                 {
  75.                         if(maxSplits == null) maxSplits = -1;
  76.                         var splitted = [], index = 0, whereToSplit, segment, splitCount = 0;
  77.                         for(var i = 0; index < this.length; ++i)
  78.                         {
  79.                                 if(maxSplits >= 0 && splitCount >= maxSplits)
  80.                                 {
  81.                                         whereToSplit = [this.length, -1];
  82.                                 }
  83.                                 else
  84.                                 {
  85.                                         whereToSplit = this.indexOfOneOfThese(listOfDelimeters, index);
  86.                                 }
  87.                                 segment = this.slice(index, whereToSplit[0]);
  88.                                 //console.log("("+index+", "+whereToSplit[0]+"... "+whereToSplit[1]+") ="+segment);
  89.                                 splitCount++;
  90.                                 if(segment.length > 0)
  91.                                 {
  92.                                         splitted.push(segment);
  93.                                 }
  94.                                 index = whereToSplit[0];
  95.                                 if(whereToSplit[1] != -1)
  96.                                 {
  97.                                         index += listOfDelimeters[whereToSplit[1]].length;
  98.                                 }
  99.                         }
  100.                         return splitted;
  101.                 }
  102.         }
  103.         if (typeof String.prototype.splitIntoTable !== 'function')
  104.         {
  105.                 /**
  106.                  * @param {Array<String>} listOfEntryDelimeters example: {@code ["{", "}", ","]}
  107.                  * @param {Array<String>} listOfAssignmentDelimeters example: {@code ["=",":"]}
  108.                  * @return {Object<String,String>} a key/value pair table. see {@link String#prototype#parseCookies} as an example
  109.                  */
  110.                 String.prototype.splitIntoTable = function (listOfEntryDelimeters, listOfAssignmentDelimeters)
  111.                 {
  112.                         // first, split by entry delimeters
  113.                         var entries = this.splitByOneOfThese(listOfEntryDelimeters);
  114.                         // then split in half by the assignment delimeter
  115.                         var table = {};
  116.                         for(var i = 0; i < entries.length; ++i)
  117.                         {
  118.                                 var pair = entries[i].splitByOneOfThese(listOfAssignmentDelimeters, 1);
  119.                                 if(pair.length > 1)
  120.                                 {
  121.                                         table[pair[0]] = pair[1];
  122.                                 }
  123.                                 else
  124.                                 {
  125.                                         table[pair[0]] = null;
  126.                                 }
  127.                         }
  128.                         return table;
  129.                 }
  130.         }
  131.         if (typeof String.prototype.parseCookies !== 'function')
  132.         {
  133.                 /**
  134.                  * @return {Map<String,String>} a table of cookies parameters, assuming this is formatted like an html cookie.
  135.                  */
  136.                 String.prototype.parseCookies = function ()
  137.                 {
  138.                         return this.splitIntoTable([";", " "], ["=", ":"]);
  139.                 }
  140.         }
  141.         if (typeof ObjectId.prototype.getTimestamp !== 'function')
  142.         {
  143.                 ObjectId.prototype.getTimestamp = function()
  144.                 {
  145.                         return new Date(parseInt(this.toString().slice(0,8), 16)*1000);
  146.                 }
  147.         }
  148. }
  149. addToStrings();
  150.  
  151. /** a list of all of the modules this machine can access, built by the command line "npm ls --json" */
  152. var npmListing = null;
  153. var processStarted = false;
  154. function gatherNpmListing() {
  155.         if(processStarted) return;
  156.         processStarted = true;
  157.         // try to get other installed modules from the npm command line tool
  158.         require("child_process").exec("npm ls --json",
  159.                 function(err, stdout, stderr) {
  160.                         if (err) return console.log(err)
  161.                         npmListing = JSON.parse(stdout);
  162.                         // add the libraries to the npmListing
  163.                         function addTheModuleToThisListing(npmListing, moduleName)
  164.                         {
  165.                                 console.log(moduleName);
  166.                                 if(moduleName != null)
  167.                                 {
  168.                                         try{
  169.                                                 npmListing["module"] = require(moduleName);
  170.                                         }catch(err){
  171.                                                 npmListing["module"] = err;
  172.                                                 //console.log("couldn't load "+moduleName);
  173.                                         }
  174.                                 }
  175.                                 if(npmListing["dependencies"])
  176.                                 {
  177.                                         for(var d in npmListing.dependencies)
  178.                                         {
  179.                                                 addTheModuleToThisListing(npmListing.dependencies[d], d);
  180.                                         }
  181.                                 }
  182.                                 // after the root is done, print.
  183.                                 if(moduleName == null)
  184.                                 {
  185.                                         printReflectionInConsole(npmListing, "npmListing", 3);
  186.                                 }
  187.                         }(npmListing); // call the function right after defining it
  188.                 }
  189.         );
  190. }
  191.  
  192. /** @param {Object} obj print an object as a JSON string, including function code */
  193. function toJSONWithFuncs(obj)
  194. {
  195.         Object.prototype.toJSON = function()
  196.         {
  197.                 var sobj = {}, i;
  198.                 for (i in this)
  199.                         if (this.hasOwnProperty(i))
  200.                                 sobj[i] = typeof this[i] == 'function' ? this[i].toString() : this[i];
  201.                 return sobj;
  202.         };
  203.         var str = JSON.stringify(obj);
  204.         delete Object.prototype.toJSON;
  205.         return str;
  206. }
  207.  
  208. /** how deep a tree to show when including the HTML traversal of JavaScriptObjects @type Number */
  209. var maxIndentLevel = 0;
  210. /** if true, will spam the server's console whenever {@link #createReflectedHtmlForJso} is called @type Boolean */
  211. var printInConsole = false;//true;
  212. var showPrivateVariables = true;
  213. var javaScriptObjectTraversalParameter = "jso";
  214.  
  215. /**
  216.  * creates a simple directory traversal interface using anchor tags
  217.  * @param {?} obj which object is being traversed (can be any type, including null)
  218.  * @param {?String=} pathStr the path (through parent objects) taken to get here (optional, can be null)
  219.  * @param {Number=} indentLevel used to properly indent, and prevent infinite recursion. limited by {@link #maxIndentLevel} (optional)
  220.  * @return {String} the HTML script that will allow traversal. the key parameter is {@link javaScriptObjectTraversalParameter}
  221.  */
  222. function createReflectedHtmlForJso(obj, pathStr, indentLevel)
  223. {       "use strict";
  224.         var indentation = "", i = 0, j = 0, props = [], functions = [], childText = [], nChildTexts = 0, key, strResult = "";
  225.         // default arguments
  226.         if ( typeof pathStr === 'undefined')            pathStr = "";
  227.         if ( typeof indentLevel === 'undefined')        indentLevel = 0;
  228.         // write the "path" at the top
  229.         if(indentLevel == 0)
  230.         {
  231.                 strResult = "\n<h1>@ ";
  232.                 var arr = pathStr.split(".");
  233.                 for(i = 0; i < arr.length; ++i)
  234.                 {
  235.                         if(i > 0) strResult += ".";
  236.                         strResult += "<a href=\"/?"+javaScriptObjectTraversalParameter+"=";
  237.                         for(j = 0; j < i; ++j)
  238.                         {
  239.                                 strResult += arr[j] + ".";
  240.                         }
  241.                         strResult += arr[i] + "\">"+arr[i]+"</a>";
  242.                 }
  243.                 strResult += "</h1>\n";
  244.         }
  245.         // for debug output in the console...
  246.         if(printInConsole)
  247.                 for(i=0; i < indentLevel; i++)
  248.                         indentation = indentation.concat("    ");
  249.         // reflect a JS functions
  250.         if(typeof obj === 'function')
  251.         {
  252.                 strResult += "<pre>"+obj.toString()+"</pre>";
  253.                 if(printInConsole) console.log(obj.toString());
  254.         }
  255.         // reflect simple types
  256.         else if(typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean')
  257.         {
  258.                 strResult += "<b>"+(typeof obj)+"</b> = "+obj+"\n";
  259.                 if(printInConsole) console.log((typeof obj)+" = "+obj);
  260.         }
  261.         // reflect objects
  262.         else if(typeof obj === 'object')
  263.         {
  264.                 // null objects don't need all of this processing
  265.                 if(obj != null)
  266.                 {
  267.                         // asks an object for all of it's members
  268.                         for(key in obj)
  269.                         {
  270.                                 if(obj.hasOwnProperty(key) && (showPrivateVariables || !key.startsWith('_')))
  271.                                 {
  272.                                         if(typeof obj[key] !== 'function')
  273.                                         {
  274.                                                 if(printInConsole) console.log(indentation+key+" : "+typeof obj[key]+" = "+obj[key]);
  275.                                                 props.push(key);
  276.                                                 if(typeof obj[key] === 'object'
  277.                                                 && indentLevel < maxIndentLevel)
  278.                                                 {
  279.                                                         var childStr;
  280.                                                         if(obj[key] == null)
  281.                                                                 childStr = "";
  282.                                                         else
  283.                                                                 childStr = createReflectedHtmlForJso(obj[key], pathStr+"."+key, indentLevel+1);
  284.                                                         if(indentLevel < maxIndentLevel)
  285.                                                         {
  286.                                                                 childText[nChildTexts] = childStr;
  287.                                                                 nChildTexts += 1;
  288.                                                         }
  289.                                                 }
  290.                                         }
  291.                                         else
  292.                                         {
  293.                                                 functions.push(key);
  294.                                         }
  295.                                 }
  296.                         }
  297.                         strResult += "<ul>"
  298.                         j = 0;
  299.                         // print child elements
  300.                         for(i = 0; i < props.length; ++i)
  301.                         {
  302.                                 key = props[i];
  303.                                 strResult += "<li><a href=\"/?"+javaScriptObjectTraversalParameter+"="+pathStr+"."+key+"\">"+key+"</a> : <b>"+(typeof obj[key])+"</b> = <i>"+obj[key]+"</i>";
  304.                                 // include members from the first tier of child objects
  305.                                 if(typeof obj[key] === 'object' && obj[key] != null)
  306.                                 {
  307.                                         strResult += "["+Object.keys(obj[key]).length+"]";
  308.                                         if(indentLevel < maxIndentLevel)
  309.                                         {
  310.                                                 strResult += childText[j];
  311.                                                 j++;
  312.                                         }
  313.                                 }
  314.                                 strResult += "\n";
  315.                         }
  316.                         for(i = 0; i < functions.length; ++i)
  317.                         {
  318.                                 key = functions[i];
  319.                                 var codestr = obj[key].toString();
  320.                                 codestr = codestr.slice(0, codestr.indexOf('{'));
  321.                                 if(printInConsole) console.log(indentation+key+" : "+typeof obj[key]+" = "+codestr);
  322.                                 codestr = codestr.replaceAll(" ", "&nbsp");
  323.                                 codestr = codestr.replaceAll("\n", "<br>");
  324.                                 strResult += "<li><a href=\"/?"+javaScriptObjectTraversalParameter+"="+pathStr+"."+key+"\">"+key+"</a> : <font face=\"courier\">"+codestr+"</font>\n";
  325.                         }
  326.                         strResult += "</ul>";
  327.                 }
  328.                 else
  329.                 {
  330.                         strResult += "<b>null</b>";
  331.                 }
  332.         }
  333.         else
  334.         {
  335.                 strResult += "unknown JavaScriptObject<pre>"+obj+"</pre>";
  336.                 if(printInConsole) console.log("unknown type ("+(typeof obj)+"): "+obj);
  337.         }
  338.         return strResult;
  339. }
  340.  
  341. /**
  342.  * @nosideeffects
  343.  * @param {?Object=} obj what object to print out
  344.  * @param {?String=} name how to label this object when printing in the console
  345.  * @param {Number=} depth how many children deep to print out. if null, {@link #maxIndentLevel} is used.
  346.  */
  347.  function printReflectionInConsole(obj, name, depth)
  348. {
  349.         if(name != null)
  350.         {
  351.                 console.log("[["+name+"]]");
  352.         }
  353.         var oldMax = maxIndentLevel;
  354.         if(depth != null)
  355.         {
  356.                 maxIndentLevel = depth;
  357.         }
  358.         printInConsole = true;
  359.         createReflectedHtmlForJso(obj);
  360.         printInConsole = false;
  361.         if(oldMax != maxIndentLevel)
  362.         {
  363.                 maxIndentLevel = oldMax;
  364.         }
  365. }
  366.  
  367. function jsoNavigation(nameToEvaluate, localVariables)
  368. {
  369.         var whatObjectToLookAt = null;
  370.         var explicitlyNull = false;
  371.         var strOutput = "";
  372.         var jso = localVariables;
  373.         if(nameToEvaluate != null && nameToEvaluate !== "")
  374.         {
  375.                 try{
  376.                         //whatObjectToLookAt = eval(nameToEvaluate); // breaks if member has a strange character in the name
  377.                         var p = nameToEvaluate.split('.');
  378.                         var cursor = eval(p[0]);
  379.                         for(var i = 1; i < p.length; ++i)
  380.                         {
  381.                                 cursor = cursor[p[i]];
  382.                         }
  383.                         whatObjectToLookAt = cursor;
  384.                         //console.log("found <"+nameToEvaluate+">");
  385.                         explicitlyNull = true;
  386.                 }catch(err){
  387.                         console.log("couldn't parse \""+nameToEvaluate+"\" : "+err);
  388.                 }
  389.         }
  390.         //console.log(whatObjectToLookAt+" "+explicitlyNull)
  391.         if(whatObjectToLookAt == null && !explicitlyNull)
  392.         {
  393.                 strOutput += "<a href=\"/?"+javaScriptObjectTraversalParameter+
  394.                         "=jso\">jso</a><br>\n";
  395.                 //console.log(strOutput);
  396.         }
  397.         else
  398.         {
  399.                 var reflectedString = createReflectedHtmlForJso(whatObjectToLookAt, nameToEvaluate);
  400.                 strOutput += reflectedString;
  401.         }
  402.         return strOutput;
  403. }
  404.  
  405.  /**
  406.  * @param request {HTTPRequest} the HTTP request
  407.  * @param request {HTTPResponse} the HTTP response
  408.  */
  409.  function jsoNavHtml(request, response)
  410. {
  411.         extraVariables = ["./mvaganov", "./router", "./helloserver", "./requesthandler", "./db",
  412.                 // "formidable", "express"
  413.                 // "http", "fs", "sys", "util", "querystring" // these are in process.moduleLoadList
  414.                 ];
  415.         // get native modules from 'process'
  416.         var i;
  417.         var loadListModules = process.moduleLoadList;
  418.         var nativeModleLabel = "NativeModule ";
  419.         var entry;
  420.         for(i = 0; i < loadListModules.length; ++i)
  421.         {
  422.                 entry = loadListModules[i];
  423.                 if(entry.startsWith(nativeModleLabel))
  424.                 {
  425.                         extraVariables.push(entry.slice(nativeModleLabel.length, entry.length));
  426.                 }
  427.         }
  428.         // load the basic (known) modules up...
  429.         var localVariables = [];
  430.         for(i = 0; i < extraVariables.length; ++i)
  431.         {
  432.                 var str = extraVariables[i];
  433.                 var name = str;
  434.                 if(name.startsWith("./"))
  435.                 {
  436.                         name = name.slice(2, name.length);
  437.                 }
  438.                 var loadedModule;
  439.                 try
  440.                 {
  441.                         loadedModule = require(str);
  442.                 }
  443.                 catch(err)
  444.                 {
  445.                         loadedModule = "ERROR: could not load module."
  446.                 }
  447.                 localVariables[name] = loadedModule;
  448.         }
  449.         // add the global process, and the request/response of this HTTP event
  450.         localVariables["process"] = process;
  451.         localVariables["request"] = request;
  452.         localVariables["response"] = response;
  453.         // try to get other installed modules from the npm command line tool
  454.         gatherNpmListing();
  455.         if(npmListing != null)
  456.         {
  457.                 localVariables["npmListing"] = npmListing;
  458.         }
  459.  
  460.         //var q = querystring.parse(request.url);
  461.         var parsedURL = url.parse(request.url);
  462.         var fullpath = parsedURL.path;
  463.         var argsIndex = fullpath.indexOfOneOfThese(['?', '&'])[0];
  464.         //var pathname = fullpath.slice(0, argsIndex);
  465.         var pathargs = fullpath.slice(argsIndex+1, fullpath.length);
  466.         var arguments = pathargs.splitIntoTable(["&", "?"], ["="]);
  467.         //printReflectionInConsole(arguments, "---ARGUMENTS---");
  468.         var nameToEvaluate = arguments[javaScriptObjectTraversalParameter];
  469.         if(nameToEvaluate != null)
  470.         {
  471.                 return jsoNavigation(nameToEvaluate, localVariables);
  472.         }
  473.         return "";
  474. }
  475.  
  476. function jsoNav(request, response, next)
  477. {
  478.         var htmlOutput = jsoNavHtml(request, response);
  479.         if(htmlOutput && htmlOutput.length > 0)
  480.         {
  481.                 response.setHeader("Content-Type", "text/html");
  482.                 response.write(htmlOutput);
  483.                 response.end();
  484.         }
  485.         else
  486.         {
  487.                 next();
  488.         }
  489. }
  490.  
  491. /** TODO reasearch the following
  492.  
  493. * for a game loop on the server: http://nodejs.org/api/globals.html#globals_settimeout_cb_ms
  494.  
  495. * for heavy lifty C code, call exec:
  496. function execCbPageTest()
  497. {
  498.         var exec = require("child_process").exec;
  499.         exec("dir",
  500.                 function resultCallBack(error, stdout, stderr)
  501.                 {
  502.                         if (error !== null) {
  503.                                 console.log('exec error: ' + error);
  504.                         }
  505.                         stdout = stdout.toString();
  506.                         stdout = stdout.replaceAll("<", "&lt");
  507.                         stdout = stdout.replaceAll(">", "&gt");
  508.                         response.writeHead(200, {"Content-Type": "text/html"});
  509.                         response.write("<pre>"+stdout+"</pre>");
  510.                         router.writeHtmlComponents(response, htmlComponentsToAdd);
  511.                         response.end();
  512.                 }
  513.         );
  514. }
  515.  
  516. * learn more about Express via this tutorial: http://expressjs.com/guide.html
  517.  
  518. * define object prototypes by using the prototype keyword, or __proto__ (would that work?)
  519.  
  520. * events, and event emitters http://www.sitepoint.com/nodejs-events-and-eventemitter/
  521.  
  522. * https://npmjs.org/browse/keyword/middleware/0/
  523.   * gauth Middleware component to authenticate users through their Google account
  524.   * authenticated ensure a request is authenticated
  525.  
  526. * JSDocs used by Google:
  527.   https://developers.google.com/closure/compiler/docs/js-for-compiler#tags
  528.   http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Comments#Comments
  529.  
  530.  
  531. * modules to check out
  532.   socket.io - real-time network communication
  533.   request - simplified http reqeust client. has authentication, and other cool stuff?
  534.   grunt - large scale automation
  535.   mocha - testing framework
  536.   async - more powerful asynchronous tools & structures for node.js
  537.   mongoose - ORM (object relational managed) database
  538.   passport - simple authentication for node.js
  539.  
  540. * modules that seem bad
  541.   redis - big fancy data structure store... like a global variables crutch?
  542. */
  543. exports.jsoNav = jsoNav;
  544. exports.jsoNavHtml = jsoNavHtml;
  545. exports.printReflectionInConsole = printReflectionInConsole;
  546. exports.logjso = printReflectionInConsole;
  547. exports.toJSONWithFuncs = toJSONWithFuncs;
RAW Paste Data
Ledger Nano X - The secure hardware wallet
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top