Esprima get function and variable declarations - javascript

I want to get all function and variable declarations made in a Javascript code.
I use esprima and I wonder if there is script that I can use for my goal?
For example we have this code:
var myVar1;
var myVar2;
function myTestFunction(funcVar1, funcVar2) {
var myVar3;
}
What I except:
Array with variables
["myVar1", "myVar2"]
And an array with functions:
[{"name": "myTestFuncttion", "params":["funcVar1", "funcVar2"], "variables": ["myVar3"]}]
Any ideas how to achieve this?

Complete solution with fiddle:
Here is some JavaScript code for a test-run:
var hello = 41;
function aaaaa(p1, p2, p3){
var a1 = 7, a2 = 8;
var a3 = 9;
function bbbbb(q1, q2){
var b1 = 10, b2 = 11;
return 12;
}
var a4 = 99;
function ccccc(r1, r2, r3){
var c1 = 13;
var c2 = 14;
var c3 = 15, c4 = 16;
return 17;
}
var a5 = 88, a6 = 77;
function ddddd(s1){
return s1 === 18
? function (x){ return x+1; }
: function (y){ return 22; }
}
return p1 + a3 <= 42 ? 55 : ccc(p1, 0, 0);
}
var world = 42;
function xxxxx(x){
var z=0;
return 0;
}
I'm assuming that this is the desired output:
{
"vars": ["hello", "world" ],
"funcs": [
{
"name": "aaaaa",
"params": ["p1", "p2", "p3"],
"variables": ["a1","a2","a3","a4","a5","a6"]
},
{
"name": "bbbbb",
"params": ["q1","q2"],
"variables": ["b1","b2"]
},
{
"name": "ccccc",
"params": ["r1","r2","r3"],
"variables": ["c1","c2","c3","c4"]
},
{
"name": "ddddd",
"params": ["s1"],
"variables": []
},
{
"name": "xxxxx",
"params": ["x"],
"variables": ["z"]
}
]
}
The lists are flat and the anonymous functions within ddddd are being ignored (they are FunctionExpressions not FunctionDeclarations). Guessing that this is how you want it.
Here is the code - probably / hopefully easy to understand without further explanation:
function findDeclarations(code){
var ast = esprima.parse(code);
var funcDecls = [];
var globalVarDecls = [];
var funcStack = [];
function visitEachAstNode(root, enter, leave){
function visit(node){
function isSubNode(key){
var child = node[key];
if (child===null) return false;
var ty = typeof child;
if (ty!=='object') return false;
if (child.constructor===Array) return ( key!=='range' );
if (key==='loc') return false;
if ('type' in child){
if (child.type in esprima.Syntax) return true;
debugger; throw new Error('unexpected');
} else { return false; }
}
enter(node);
var keys = Object.keys(node);
var subNodeKeys = keys.filter(isSubNode);
for (var i=0; i<subNodeKeys.length; i++){
var key = subNodeKeys[i];
visit(node[key]);
}
leave(node);
}
visit(root);
}
function myEnter(node){
if (node.type==='FunctionDeclaration') {
var current = {
name : node.id.name,
params : node.params.map(function(p){return p.name;}),
variables : []
}
funcDecls.push(current);
funcStack.push(current);
}
if (node.type==='VariableDeclaration'){
var foundVarNames = node.declarations.map(function(d){ return d.id.name; });
if (funcStack.length===0){
globalVarDecls = globalVarDecls.concat(foundVarNames);
} else {
var onTopOfStack = funcStack[funcStack.length-1];
onTopOfStack.variables = onTopOfStack.variables.concat(foundVarNames);
}
}
}
function myLeave(node){
if (node.type==='FunctionDeclaration') {
funcStack.pop();
}
}
visitEachAstNode(ast, myEnter, myLeave);
return {
vars : globalVarDecls,
funcs : funcDecls
};
}
for testing, you can type
JSON.stringify(
findDeclarations(
'var hello=41;\n' +
aaaaa.toString() +
'var world=42;\n' +
xxxxx.toString()
),
null, 4
)
You can also use the estraverse package, it's available on github. Then, essentially, the function visitEachAstNode should be replaced by estraverse.traverse, and otherwise you can leave the code unchanged.
fiddle

Related

Filter though object array based on distance between GPS locations(javascript)

I have an array of location objects with GPS locations tied to the objects. I am wanting to filter through the array based on the users current location and compare the distance between the user location and location objects.
I have a current function that accomplishes this, but I know this is not efficient. I would prefer to filter the array than to create a temp variable and assign the temp variable to the array every time.
//sample data
public getLocation = [
{
"ID": "1",
"Name": "Test Location 1",
"Lat": "32.16347467",
"Lon": "-103.67178545"
}, {
"ID": "2",
"Name": "Test Location 2",
"Lat": "32.16347451",
"Lon": "-103.67178544"
}, {
"ID": "3",
"Name": "Test Location 3",
"Lat": "32.13559815",
"Lon": "-103.67544362"
}, {
"ID": "4",
"Name": "Test Location 4",
"Lat": "32.40144407",
"Lon": "-103.13168477"
}, {
"ID": "5",
"Name": "Test Location ",
"Lat": "32.14557039",
"Lon": "-103.67011361",
}
]
grabLocation(){
this.platform.ready().then(() => {
this.geolocation.getCurrentPosition().then((resp) => {
this.userLocation = [parseFloat(resp.coords.latitude.toFixed(4)),parseFloat(resp.coords.longitude.toFixed(4))];
this.userLocation = [resp.coords.latitude,resp.coords.longitude];
var getLocation
getLocation = this.asyncLocations.grabUserLoc(this.userLocation[0],this.userLocation[1]);
console.log(getLocation);
}).catch((error) => {
this.presentToast(error);
});
});
}
//asyncLocations.ts
grabUserLoc(lat,lon){
var tempLocation= [];
for(let i=0;i<this.getLocation.length;i++){
if((this.getLocation[i]['Lat']!="") && this.getLocation[i]['Lon']!=""){
let R = 6371;// km
let RinM = (R*0.621371);
let Lat1 = (parseFloat(lat.toFixed(5)));
let Lon1 = (parseFloat(lon.toFixed(5)));
let Lat2 = (parseFloat(this.getLocation[i]['Lat']));
let Lon2 = (parseFloat(this.getLocation[i]['Lon']));
let dLat = this.toRad(Lat2-Lat1);
let dLon = this.toRad(Lon2-Lon1);
let RLat1 = this.toRad(Lat1);
let RLat2 = this.toRad(Lat2);
let a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(RLat1) * Math.cos(RLat2);
let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
//let d = R * c;
let e = RinM * c;
if(e < 5){
tempLocation.push(this.getLocation[i]);
}
}
}
this.getLocation = tempLocation;
return this.getLocation;
}
// Converts numeric degrees to radians
toRad(Value)
{
return Value * Math.PI / 180;
}
I currently have the locations checking for a distance of 5 miles.
Any help would be appreciated.
don't store your lat/long values as strings - convert then to floating point at the earliest possible opportunity
separate out your Haversine calculation into its own function
consider using the Cosine variant of Haversine, and omitting the final acos step
refactor constant expressions outside of the loop
consider pre-calculating the radian equivalents for latitude and longitude
See also Quicker way to calculate geographic distance between two points
I recommend using a WebWorker so that the main UI thread isn't blocked for extended periods and a given event inspired search/filter can be interrupted of supplemented with more recent data: -
importScripts("Tier3Toolbox.js");
var currVintage = 0;
var inBounds = false;
var facFilter = [];
var imageProlog = "<div style='height:5em; width:5em; display:inline-block;vertical-align:middle;'>" +
"<img style='height:100%; width: 100%; max-height:100%; max-width:100%' src='";
var imageEpilog = "' ></div>";
var facilityTable, lineBreak;
self.addEventListener('message', function(e)
{
var data = e.data;
switch (data.cmd) {
case 'init':
initThread(data.load);
break;
case 'initFilter':
for (var i=0; i<data.filterTable.length; i++) {
facFilter[data.filterTable[i].locTypeId] = {'icon':data.filterTable[i].icon};
}
break;
case 'filter':
facFilter = [];
for (var i=0; i<data.filterTable.length; i++) {
if (data.filterTable[i].facSelected)
facFilter[data.filterTable[i].locTypeId] = {'icon':data.filterTable[i].icon};
}
break;
case 'search':
var searchVintage = ++currVintage;
var tableSearch = new searcher(searchVintage, data);
break;
case 'reset':
reset();
self.postMessage({'reset': true});
break;
case 'stop':
self.postMessage({'success' : true});
self.close();
break;
default:
self.postMessage({'success' : false, 'msg' : data.msg});
};
}, false);
function initThread(msg)
{
facilityTable = JSON.parse(msg);
reset();
self.postMessage({'success' : true,
'cnt' : facilityTable.length
});
}
function reset()
{
for (var i=0; i<facilityTable.length; i++) {
facilityTable[i].visible=false
}
currVintage = 0;
}
function searcher(searchVintage, msg)
{
var myVintage = searchVintage;
var facIndex = -1;
var msg = msg;
var checkLoop = function()
{
if (myVintage != currVintage)
return;
if (++facIndex == facilityTable.length)
return;
inBounds = geoFencer.call(this, msg);
if (inBounds) {
var facMatch = 0;
var bubbleHTML = "";
for (var i=0; i<facilityTable[facIndex].facilities.length; i++){
var currFac = facilityTable[facIndex].facilities[i];
if (facFilter[currFac.locTypeId] != undefined) {
if (facMatch != 0) {
lineBreak = (facMatch / 3);
if (lineBreak == lineBreak.toFixed(0)) {
bubbleHTML += "<br />";
}
}
facMatch++;
bubbleHTML += imageProlog + facFilter[currFac.locTypeId].icon + imageEpilog;
}
}
if (facMatch == 0) {
inBounds = false;
}
}
if (inBounds != facilityTable[facIndex].visible) {
self.postMessage({'match' : inBounds,
'facIndex' : facIndex,
'scopeVintage': msg.scopeVintage,
'bubbleHTML' : bubbleHTML,
'success' : true
});
facilityTable[facIndex].visible = inBounds;
}
setTimeout(checkLoop,0);
}
var circleCheck = function(msg)
{
var diff = Tier3Toolbox.calculateDistance(
msg.centerLat,
msg.centerLng,
facilityTable[facIndex].searchLat,
facilityTable[facIndex].searchLng);
if (msg.radius > diff)
return true;
return false;
}
var rectangleCheck = function(msg)
{
if (facilityTable[facIndex].searchLat > msg.SWLat &&
facilityTable[facIndex].searchLat < msg.NELat &&
facilityTable[facIndex].searchLng > msg.SWLng &&
facilityTable[facIndex].searchLng < msg.NELng)
return true;
return false;
}
var GEOFENCER = [circleCheck,rectangleCheck];
var geoFencer = GEOFENCER[msg.checker];
setTimeout(checkLoop,0);
return this;
}

how to parse a .RC file using Javascript

I am trying to parse the data from a .RC (resource definition file) to JSON using js with simple fs.readFile function, however I am getting SyntaxError: Invalid or unexpected token. At the moment I've found no other solution to parse this type of file, pls provide me with inputs to do so. Below is .RC example.
#include "shapes.h"
ShapesCursor CURSOR SHAPES.CUR
ShapesIcon ICON SHAPES.ICO
ShapesMenu MENU
{
POPUP "&Shape"
{
MENUITEM "&Clear", ID_CLEAR
MENUITEM "&Rectangle", ID_RECT
}
}
I found a package in node called, 'Jison' which is an API for creating parsers in JavaScript similar to 'PegJS', however I couldn't figure out the grammer that needs to be written for my file type also if it would support the file type. The parsed structure could look similar to,
{
"directive": [
"include",
"shapes.h"
],
"data": [
{
"name": "ShapesCursor",
"values": [
"CURSOR",
"SHAPES.CUR"
],
"children": []
},
{
"name": "ShapesIcon",
"values": [
"CURSOR",
"SHAPES.ICO"
],
"children": []
},
{
"name": "POPUP",
"values": [
"&Shape"
],
"children": [
{
"name": "MENUITEM",
"values": [
"&Clear",
"ID_CLEAR"
],
"children": []
},
{
"name": "MENUITEM",
"values": [
"&Rectangle",
"ID_RECT"
],
"children": []
}
]
}
]
}
Below grammar can be used for parsing Resource Description files to a JSON.
{
var word_Obj = {};
var word_alnum_Obj = {};
var word_alnumsp_Obj = {};
var dir_Obj = {};
var valStateDec_Obj = {};
var stateName_Obj = {};
var valStateVal_Obj = {};
var word_Count = 0;
var word_alnum_Count = 0;
var word_alnumsp_Count = 0;
var dir_Count = -1;
var valStateDec_Count = 0;
var stateName_Count = -1;
var valStateVal_Count = -1;
var begin_Count = -1;
var end_Count = -1;
var child_Count = -1;
var children_Count = -1;
var flag = 0;
}
Expected = dir:directive * nl * states:state nl* Ending:EOL {if (begin_Count === end_Count) { return { Parsed_RC: { Directive_Obj: dir, States_Obj: states, ENDING: Ending } } } else { return "Incorrect .RC file" } }
directive = "#" d: word space* v:word_alnumsp nl+ { dir_Count++; dir_Obj = { ['Directive_' + dir_Count]: { "Dir": d, "_text": v } }; return dir_Obj;}
state = (valState looping)*
looping = (loopStart loopEnd*)*
loopStart = beg child: valState + { begin_Count++; children_Count++; child_Count++; return {['loopStart_' + begin_Count]: begin_Count, ['child_' + children_Count]: child } }
loopEnd = end {end_Count++; child_Count--; return { ['loopEnd_' + end_Count]: end_Count }; }
valState = stateName(valStateVal) * nl +
//valStateDec = space+ decState_val:word_alnumsp {valStateDec_Count++; valStateDec_Obj = {['ValStateDec_Obj'+valStateDec_Count]:decState_val}; return valStateDec_Obj;}
stateName = space * state_name:word_alnumsp {if (state_name === 'BEGIN') { begin_Count++; children_Count++; child_Count++; return { ['loopStart_' + begin_Count]: begin_Count } } if (state_name === 'END') { end_Count++; child_Count--; return { ['loopEnd_' + end_Count]: end_Count }; } if (child_Count < 0) { flag = 1; } stateName_Count++; stateName_Obj = { ['StateName_Obj' + stateName_Count]: state_name }; return stateName_Obj; }
valStateVal = space + valState_val:(word_alnumsp comma?)* { valStateVal_Count++; valStateVal_Obj = { ['_attributes_Obj' + valStateVal_Count]: valState_val }; return valStateVal_Obj}
word = wo:letter + { return wo.join("") }
word_alnum = al:alnum + { return al.join("") }
word_alnumsp = alsp:alnumsp + { return alsp.join("") }
beg = space * ([{]) space* nl +
end = space * ([}]) space* nl +
comma = space * [,] space* { return ","}
letter = [a - zA - Z]
alnum = [a - zA - Z0 - 9]
alnumsp = [a - zA - Z0 - 9"'&._()\\|+:]
space = " "
nl = '\n' {valStateVal_Count = -1; return "NL"}
EOL = !. {return "EOF"}

How the solve the equation in algebra in js

var Solver = (function () {
function Solver(equations) {
this.params = Object.keys(equations)
this.equations = this.parseEquations(equations)
}
Solver.prototype.parseEquations = function(equations){
var replacements = {
power : {
re: /([\w.]+)\^([\w.]+)/g,
res: 'Math.pow($1,$2)'
},
powerPython : {
re: /([\w.]+)\*\*([\w.]+)/g,
res: 'Math.pow($1,$2)'
},
}
for(var key in equations){
var eq = equations[key]
for(var re in replacements){
var repl = replacements[re]
eq = eq.replace(repl.re, repl.res)
}
equations[key] = eq
}
return equations;
}
Solver.prototype.solve = function solve(obj) {
var out = {},
nullCount = Object.keys(this.equations).length,
lastNull = 0;
for (var key = 0; key < this.params.length; key++) {
eval(this.params[key] + '=undefined')
}
for (var key in obj) {
if (this.params.indexOf(key) != -1 && (obj[key]==0 || obj[key])) {
eval(key + '=' + obj[key]),
out[key] = obj[key]
}
}
var equations = JSON.parse(JSON.stringify(this.equations))
while (lastNull !== nullCount) {
lastNull = nullCount;
for (var eq in equations) {
with(Math)
var result = eval(equations[eq]);
if (result) {
out[eq] = result;
equations[eq] = undefined;
}
}
nullCount = Object.keys(equations).length;
}
return out;
}
return Solver;
}());
if (typeof module !== 'undefined') module.exports = Solver;
<html>
<head>
<script src='js-solver.js'></script>//declare the js library file
</head>
<body>
<div id="res"></div>
<script>
var triangleSolver = new Solver({
area: 'base*h/2',
c: 'Math.sqrt(Math.pow(a,2)+Math.pow(b,2)) || base/2', //base/2 is an example of a dual-equation definition
a: 'Math.sqrt(Math.pow(c,2)-Math.pow(b,2))',
b: 'Math.sqrt(Math.pow(c,2)-Math.pow(a,2))',
h: 'area*2/base',
base: 'area*2/h'
})
triangleSolver.solve({
c: 5,
b: 3,
area: 50,
h: 10
})
document.getElementById("res").innerHTML = h;
</script>
</body>
</html>
I have some code in algebra in js-solver.I want to type the algebra equation in input field get the solution and steps for the equation but i try to use in algebra.js library but some long equation are not support so how to solve the equation please help me and correct my code. for example equation 1/4x2+5/4x = 3y - 12/5 how to solve .

Apparently assignment to proprierty of object does not work in javascript

Firs of all, I am newbie with Javascript and I think it is from about two hours that I am trying to understand this issue.
I have some objects (nested to one other object) where one property (called years) have this value: "1972-1974", for example. The value may change, but what remains the same is the presence of -. Object that have this property (year) with the value - need to be replicated, changing only year. If the value is "1972-1974" I want three object with value 1972, 1973 and 1974 in the year property (other property does not change).
Example of data structure.
{
"type": "FeatureCollection",
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
"features": [
{
"type": "Feature",
"properties": {
"years": "1972-1974",
}
},
This is my attempt to solve my requiriment:
function formatYears(data) {
data.forEach(
function(d, index) {
if(typeof d.properties.years === "string" && d.properties.years.includes("-")) {
var temp = d.properties.years.split("-");
var count = temp[temp.length - 1] - temp[0];
d.properties.years = parseInt(temp[0]);
for(var i = 0; i < count; i++) {
var newData = jQuery.extend({}, d);
newData.properties.years = parseInt(temp[0]) + i + 1;
data.push(newData);
}
}
}
)
}
I call this function with
formatYears(json.features);
where json store all data previusly loaded.
I do not know why but all new objects have as years property 1974, in our example.
I tried to debug it and newData.properties.years take the right value (1973 and then 1974), but newData after data.push(newData) does not hold 1973 and 1974, but always 1974.
UPDATE:
Add link to json.
UPDATE 2:
Solved.
function formatYears(data) {
data.forEach(
function(d, index) {
if(typeof d.properties.years === "string" && d.properties.years.includes("-")) {
var temp = d.properties.years.split("-");
var count = temp[temp.length - 1] - temp[0];
d.properties.years = parseInt(temp[0]);
for(var i = 0; i < count; i++) {
var newData = jQuery.extend(true, {}, d);
newData.properties.years = parseInt(temp[0]) + i + 1;
data.push(newData);
}
}
}
)
}
Why?
Simple for loop:
function formatYears(features) {
features.forEach(function(feature){
var fromto = feature.properties.years.split('-');
var years = [];
for (var y = +fromto[0]; y <= fromto[1]; ++y)
years.push(y);
feature.properties.years = years;
return years;
});
}
var f = [
{
"type": "Feature",
"properties": {
"years": "1972-1974",
}
},
{
"type": "Feature",
"properties": {
"years": "1975-1978",
}
}];
function formatYears(features) {
features.forEach(function(feature){
var fromto = feature.properties.years.split('-');
var years = [];
for (var y = +fromto[0]; y <= fromto[1]; ++y)
years.push(y);
feature.properties.years = years;
});
}
formatYears(f)
console.log(f.map(f => f.properties.years))
I have made some changes to your js code
function formatYears(data) {
var out = [];
data.forEach(
function(d, index) {
if(typeof d.properties.years === "string" && d.properties.years.includes("-")) {
var temp = d.properties.years.split("-");
var count = (parseInt(temp[1],10) - parseInt(temp[0],10)) + 1;
//d.properties.years = parseInt(temp[0]);
for(var i = 0; i < count; i++) {
var newData = jQuery.extend(true, {}, d);
newData.properties.years = parseInt(temp[0], 10) + i;
console.log(newData);
out.push(newData);
}
}
}
)
console.log(out);
}
and when I am calling this with a data like this
var data = {
"features": [
{
"type": "Feature",
"properties": {
"years": "1972-1974",
}
},
{
"type": "Feature",
"properties": {
"years": "2007-2008",
}
},
{
"type": "Feature",
"properties": {
"years": "2010-2011",
}
}
]
};
its working fine.
Solved.
function formatYears(data) {
data.forEach(
function(d, index) {
if(typeof d.properties.years === "string" && d.properties.years.includes("-")) {
var temp = d.properties.years.split("-");
var count = temp[temp.length - 1] - temp[0];
d.properties.years = parseInt(temp[0]);
for(var i = 0; i < count; i++) {
var newData = jQuery.extend(true, {}, d);
newData.properties.years = parseInt(temp[0]) + i + 1;
data.push(newData);
}
}
}
)
}

Adding a value to a jquery tree object

Suppose I have an object like that.
var t = {
"obj1": {
"obj1.1": "test",
"obj1.2": {
"obj1.1.1": null, // <-- "obj1.1.1" has to have a value.
"obj1.1.2": "test"
}
}
};
And a path to the node where I'd like to add a value, i.e.:
var path = ['obj1', 'obj1.1', 'test'];
How do I add the value programmatically?
Try this:
function setDeepValue(obj, value, path) {
if(path.length > 1){
var p=path.shift();
if(obj[p]==null || typeof obj[p]!== 'object'){
obj[p] = {};
}
setDeepValue(obj[p], value, path);
}else{
obj[path[0]] = value;
}
}
var obj = {};
var path = ['obj1', 'obj1.1'];
setDeepValue(obj, 'test', path);
console.log(obj); // {"obj1":{"obj1.1":"test"}}
You will however need to fix your object:
var t = {
"obj1": {
"obj1.1": "test",
"obj1.2": {
"obj1.1.1": null, // <-- "obj1.1.1" has to have a value.
"obj1.1.2": "test"
}
}
};
A object can't have a key without a value, so "obj1.1.1" will have to have a value, even if it's null.
Supposing this object
var obj = {
"obj1" : {
"obj1.1" : "",
"obj1.2" : {
"obj1.1.1" : "",
"obj1.1.2" : ""
}
}
}
var path = ['obj1', 'obj1.1', 'test'];
the algorithm is:
var el = obj;
for(var i = 0; i < path.length-2; i++) {
el = el[path[i]];
}
el[path[i]] = path[i+1];
or as function
function setpath(obj,path) {
var el = obj;
for(var i = 0; i < path.length-2; i++) {
console.log(i+"="+path[i]);
el = el[path[i]];
}
el[path[i]] = path[i+1];
console.log(el);
}
setpath(obj,['obj1', 'obj1.1', 'test']);
var tree = {
"obj1": {
"obj1.1": "test",
"obj1.2": {
"obj1.1.1": null,
"obj1.1.2": "test"
}
}
};
var path = ['obj1', 'obj1.1', 'test'];
A static way of setting 'test':
tree[path[0]][path[1]] = path[2];
A static way of replacing 'test' with newObj:
var newObj = { ... };
tree[path[0]][path[1]][path[2]] = newObj;

Categories