JavaScript Promise Method not returning any data - javascript

I am creating a react native application.
I have a back button that fires the function findItem. findItem the uses async method searchJson. searchJson searches recursive json to find parent object based on id. However it never returns any results.
findItem:
findItem() {
//Pass null so top level json will be pulled
let result = this.searchJson(null).done();
let abv = 2;
// this.setState(previousState => {
// return {
// data: result,
// parentID: result.parentid
// };
// });
}
searchJson:
async searchJson(object) {
return new Promise(resolve => {
//use object or pull from porp - all data
let theObject = object == null ? this.props.data : object;
var result = null;
if (theObject instanceof Array) {
for (var i = 0; i < theObject.length; i++) {
result = this.searchJson(theObject[i]);
if (result) {
break;
}
}
}
else {
for (var prop in theObject) {
console.log(prop + ': ' + theObject[prop]);
if (prop == 'id') {
if (theObject[prop] == this.state.parentID) {
return theObject;
}
}
if (theObject[prop] instanceof Object || theObject[prop] instanceof Array) {
result = this.searchJson(theObject[prop]);
if (result) {
break;
}
}
}
}
if(result != null)
resolve(result);
});
}
Any help will be greatly appreciated.

Ok so I never got this to work but my workaround was this.
I Modified the findItem method:
findItem() {
let FinNode = null;
for (var node in this.props.data) {
FinNode = this.searchJson(this.state.parentID, this.props.data, this.props.data[node].book);
if (FinNode != null) {
this.setState(previousState => {
return {
data: FinNode[0].book.parentid == "" ? null : FinNode,
parentID: FinNode[0].book.parentid
};
});
break;
}
}
}
And then the searchJson:
searchJson(id, parentArray, currentNode) {
if (id == currentNode.id) {
return parentArray;
} else {
var result;
for (var index in currentNode.books) {
var node = currentNode.books[index].book;
if (node.id == id)
return currentNode.books;
this.searchJson(id, currentNode.books, node);
}
return null;
}
}
This allowed for all my nodes to be searched and the for loop made so that there is no need for async. This does have some drawbacks but seems to work decently without any massive performance issues.

Related

Why is this async function failing to return any data?

So, a quick overview, this function is part of a larger app that ingests JSON data and prepares it to be rendered by Handlebars, which is then used for generating a PDF. This particular function has been giving me grief, as from my understanding of how async/await works, the data should be returned by the return returnArray at the bottom of the function. This however does not happen, and instead the empty array is returned. Could anyone offer insight as to why this is? (N.B. I've checked the data is present in iarr when it gets pushed, it's as though the return statement gets fired before the for loop has started.)
async function getPackageItem(item) {
try {
let returnArray = []
if (fs.existsSync(__dirname + "/../json/" + item.sku + ".json")) {
var file = fs.readFileSync(__dirname + "/../json/" + item.sku + ".json")
} else {
var file = fs.readFileSync(__dirname + "/../json/box.json")
}
const tb = JSON.parse(file);
for (var a = 0; a < item.quantity; a++) {
let iarr = [];
if (tb) {
tb.forEach(function(entry) {
ShopifyAuth.get('/admin/products/' + entry.product_id + '.json', (err, productData) => {
if (!err) {
ShopifyAuth.get('/admin/products/' + entry.product_id + '/metafields.json', (err, metafieldData) => {
if (!err) {
var itemObject = {};
var metaCounter = 0;
metafieldData.metafields.forEach(function(metadata) {
switch(metadata.key) {
case "notes": {
itemObject.wm_notes = metadata.value;
metaCounter++
break;
}
case "title": {
itemObject.title = metadata.value;
metaCounter++
break;
}
case "vintage": {
itemObject.year = metadata.value;
metaCounter++;
break;
}
case "shelfid": {
itemObject.shelf_id = metadata.value;
metaCounter++;
break;
}
case "bottleprice": {
itemObject.bottle_price = metadata.value;
metaCounter++;
break;
}
default: {
metaCounter++;
break;
}
}
if(metaCounter === metafieldData.metafields.length) {
itemObject.vendor = productData.product.vendor;
if (itemObject.title == undefined) {
itemObject.title = productData.product.title
}
if (itemObject.wm_notes == undefined) {
itemObject.wm_notes = " "
}
if (itemObject.year == undefined) {
itemObject.year = "Unspecified"
}
if (itemObject.shelf_id == undefined) {
itemObject.shelf_id = "N/A"
}
if (productData.product.images[1] == undefined) {
if (productData.product.images[0]) {
itemObject.logo = productData.product.images[0].src;
} else {
itemObject.logo = '';
};
} else {
itemObject.logo = productData.product.images[1].src;
}
itemObject.quantity = item.quantity;
iarr.push(itemObject)
if(iarr.length == tb.length) {
returnArray.push(iarr);
}
}
});
} else {
throw Error('Error retrieving product metadata');
}
})
} else {
throw Error('Error retrieving product data');
}
})
})
} else {
throw Error('Error loading JSON for specified box');
}
}
return returnArray;
} catch (e) {
console.log(e)
}
}
Edit: That's what I get for writing code at 3am, not sure how I missed that. Thanks for your feedback.
You marked your function async but you're not using await anywhere inside of it so you're not getting any of the benefits of using async. It doesn't make your function magically synchronous, you still have to manage asynchronicity carefully.
If ShopifyAuth.get supports returning a promise then await on the result instead of passing callbacks and your code will work, otherwise construct a Promise, do the async stuff in the promise, and return the promise from the function.
async function getPackageItem(item) {
let result = new Promise((resolve, reject) => {
// all your ShopifyAuth stuff here
if (err) {
reject(err);
}
resolve(returnArray);
});
return result;
}

How to avoid long if else statements using RxJS

I'm trying to use RxJS to replace the next piece of code(jsbin):
function parseRequestUrl(url) {
var newUrl;
if ((newUrl = testThatUrlIsOrigin1(url)) !== url) {
return doSomething(newUrl);
}
if ((newUrl = testThatUrlIsOrigin2(url)) !== url) {
return doSomething(newUrl);
}
if ((newUrl = testThatUrlIsOrigin3(url)) !== url) {
return doSomething(newUrl);
}
}
Something i was able to achieve using RxJS(jsbin) but in that case i needed to call a function twice for which "filter expression" is true
function parseRequestUrl(url) {
var newUrl = url;
var observer = Rx.Observable.of(testThatUrlIsOrigin1, testThatUrlIsOrigin2, testThatUrlIsOrigin3);
observer.first(getUrlFunc => getUrlFunc(url) !== url).map(getUrlFunc => getUrlFunc(url)).subscribe(createdUrl => newUrl = createdUrl)
return doSomething(newUrl);
// And so on
}
Can RxJS suit my requirements ?
I don't think that RxJs is the right tool for the job. It is best suited for processing asynchronous streams of data. I think that a better approach would be to just put all of your test functions in an array and loop over them. Something like this:
const tests = [testThatUrlIsOrigin1, testThatUrlIsOrigin2, testThatUrlIsOrigin3];
function parseRequestUrl(url) {
for (const test of tests) {
const newUrl = test(url);
if (newUrl === url) continue;
return newUrl;
}
}
function testThatUrlIsOrigin1(url) {
console.log("try testThatUrlIsOrigin1");
if (url === 'origin1') {
console.log("Pass testThatUrlIsOrigin1");
return "First If";
}
return url;
}
function testThatUrlIsOrigin2(url) {
console.log("try testThatUrlIsOrigin2");
if (url === 'origin2') {
console.log("Pass testThatUrlIsOrigin2");
return "Second If";
}
return url;
}
function testThatUrlIsOrigin3(url) {
console.log("try testThatUrlIsOrigin3");
if (url === 'origin3') {
console.log("Pass testThatUrlIsOrigin3");
return "Third If";
}
return url;
}
parseRequestUrl('origin2')
You could also implement the Chain of Responsibility design pattern if you wanted to get all OO on it.
EDIT
Since you want to see how to do it in RxJs, here is a simplified version:
function test(a, b) {
return a === b ? `${a} test` : b;
}
const tests = [
test.bind(null, 1),
test.bind(null, 2),
test.bind(null, 3),
];
const value = 2;
Rx.Observable.from(tests)
.map(x => x(value))
.filter(x => x !== value)
.take(1)
.subscribe(
x => { console.log(x); },
null,
() => { console.log('completed'); }
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.5/Rx.min.js"></script>

AngularJS Pass variables into looped asynchronous callback

I have a function that loops through in indeterminate number of items and does an asynchronous call on each one to get additional data (the content of html template files). The callback does some checking. The resulting function should be thenable. $q is injected earlier, this code is part of a factory.
function searchHelpTopics(topics, searchPhrase) {
if (topics == null || topics.length == 0) return "No search results";
var results = [];
var promises = [];
for (var i = 0; i < topics.length; i++) {
var templateURL = topics[i].URL;
var topic = topics[i];
if (topics[i].HelpTopicId != "Search") {
var promise = $templateRequest(templateURL).then(function (template) {
var text = HTMLToText(template, true);
// do the search
if (text.indexOf(searchPhrase) > -1) {
if (text.length > 50) text = text.substring(0, 50);
var result = {};
result.title = topic.Title;
result.excerpt = text;
result.helpID = topic.HelpTopicID;
results.push(result);
}
});
promises.push(promise);
}
}
return $q.all(promises).then(function () {
return results;
})
The problem here is that the for loop does not wait for the callbacks obviously and so the topic being used by the callback is not the correct one. I need a way to pass topic into the callback on each loop.
Because JS has only function scope you can rewrite your code to use function instead of 'for' loop (which is usually better).
To do that you can use JS built-in forEach (which is available starting from version 1.6 so almost for all browsers) or good functional style libraries like underscore.js or lodash.js.
Or even better - to use Array.map and Array.filter - see the code
function processTemplate(topic, template) {
var text = HTMLToText(template, true);
// do the search
if (text.indexOf(searchPhrase) < 0) {
return;
}
if (text.length > 50) {
text = text.substring(0, 50);
}
return {
title: topic.Title,
excerpt: text,
helpID: topic.HelpTopicID
};
}
function searchHelpTopics(topics, searchPhrase) {
if (!topics || topics.length === 0) {
return "No search results";
}
var promises = topics
.filter(function(topic) { return topic.HelpTopicId !== "Search"; })
.map(function(topic) {
return $templateRequest(topic.URL).then(processTemplate);
});
return $q.all(promises)
.then(function (results) {
return results.filter(function (result) {
return result; // filters out 'undefined'
});
});
}
The is not a complete solution but enough to indicate how it works
somefactory.getHelpTopics().then(function (topics) {
somefactory.searchHelpTopics(topics, searchText).then(function (searchResults) {
vm.searchResults = searchResults;
vm.helpID = "Search";
});
});
--- some factory functions ----
function searchHelpTopics(topics, searchPhrase) {
if (!topics || topics.length === 0) return "No search results";
var promises = topics
.filter(function (topic) { return topic.HelpTopicId !== "Search"; })
.map(function (topic) {
return $templateRequest(topic.URL).then(function (template) {
return searchHelpTemplate(template, topic, searchPhrase);
});
});
return $q.all(promises).then(function (results) {
return results.filter(function (result) {
return result; // filters out 'undefined'
});
});
}
function searchHelpTemplate(template, topic, searchPhrase) {
var text = HTMLToText(template, true);
// do the search
if (text.indexOf(searchPhrase) < 0 && topic.Title.indexOf(searchPhrase) < 0) {
return;
}
if (text.length > 50) {
text = text.substring(0, 50);
}
return {
title: topic.Title,
excerpt: text,
helpID: topic.HelpTopicId
};
}

How to stop executing Javascript function containing infinite loop after some time

Suppose I have following piece of code that contains an infinite loop:
function infiniteLoop() {
while(true) {
//do something, eg.
document.getElementById("someID").innerHTML = "Blah";
}
}
If we execute this code in an online compiler, browser will crash. I want to prevent that from happening. So I tried following code following this answer:
function willNotCrash() {
myVar = setInterval(infiniteLoop, 5000);
setTimeout(function(){
clearInterval(myVar);
}, 4000);
}
This code doesn't make the browser to crash, because I am stopping the execution before infiniteLoop() gets called by clearInterval(myVar).
My question is how do I stop executing such functions if they don't response within some period of time (eg. after 5 seconds or before the browser is crashed).
For example, if we copy paste following java code in https://www.compilejava.net/
public class HelloWorld {
public static void main(String[] args) {
while(true) {
System.out.println("Blah");
}
}
}
we get a nice output saying,
Script was taking longer than 5 seconds to execute so it was killed.
Here is my current code: http://js.do/code/106546
This is a bit tricky but perfectly doable. You need to tokenize the script and then rebuild it but insert a counter increment in every loop and function call. If the counter goes above some threshold, then bomb out. I did it here: https://littleminigames.com/
You can see the source at https://bitbucket.org/cskilbeck/littleminigames/src
The interesting bits are in wrapper.js (https://bitbucket.org/cskilbeck/littleminigames/src/ac29d0d0787abe93c75b88520050a6792c04d34d/public_html/static/js/wrapper.js?at=master&fileviewer=file-view-default)
Google escodegen, estraverse and esprima
I relied heavily on this: https://github.com/CodeCosmos/codecosmos/blob/master/www/js/sandbox.js
wrapper.js, as requested:
// Don't obfuscate this file! We depend on the toString() of functions!
// this was all nicked from https://github.com/CodeCosmos/codecosmos/blob/master/www/js/sandbox.js
(function(mainApp) {
'use strict';
var esprima = window.esprima,
estraverse = window.estraverse,
escodegen = window.escodegen,
errors = [],
eng,
Syntax = estraverse.Syntax;
// This implements the jankiest possible "source map", where we keep an array
// of [generatedLine, knownSourceLine]. Seems to essentially work.
function SourceNode(line, col, _sourceMap, generated) {
this.line = line;
this.col = col;
this.generated = generated;
}
SourceNode.prototype.toStringWithSourceMap = function toStringWithSourceMap() {
var code = [];
var mapLines = {};
var map = [];
// assumes that wrapCode adds two lines
var line = 3;
var lastMapLine = null;
function walk(node) {
if (typeof(node) === "string") {
if (node) {
code.push(node);
var matches = node.match(/\n/g);
if (matches !== null) {
line += matches.length;
}
}
} else if (node instanceof SourceNode) {
if (node.line !== null) {
if (!mapLines[line]) {
map.push([line, node.line]);
mapLines[line] = node.line;
}
}
walk(node.generated);
} else {
node.forEach(walk);
}
}
walk(this);
return {
code: code.join(''),
map: map
};
};
SourceNode.prototype.toString = function toString() {
return this.toStringWithSourceMap().code;
};
// This is used by escodegen
window.sourceMap = {
SourceNode: SourceNode
};
// TODO (chs): add in all the things that need to be masked
function runWrapper($userCode, __sys) {
var clear = __sys.clear,
setpixel = __sys.setpixel,
rectangle = __sys.rectangle,
box = __sys.box,
line = __sys.line,
getpixel = __sys.getpixel,
getpixeli = __sys.getpixeli,
keypress = __sys.keypress,
keyrelease = __sys.keyrelease,
keyheld = __sys.keyheld,
reset = __sys.reset;
__sys.userFunction = __sys.catchErrors($userCode);
}
function extractCode(fn) {
var code = fn.toString();
return code.substring(code.indexOf('{') + 1, code.lastIndexOf('}'));
}
function makeOneLine(code) {
return code.replace(/(\/\/[^\n]+|\n\s|\r\n\s*)/g, '');
}
var runTemplate = makeOneLine(extractCode(runWrapper));
function wrapCode(code, template, functionName, postCode) {
// avoid interpretation of the replacement string by using a fun.
// otherwise mo' $ mo problems.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter
return ("'use strict';" + template.replace(/\$userCode/, function() {
return 'function ' + functionName + '() {\n' + code + postCode + '\n}';
}));
}
var injectStatement = esprima.parse("if (++__sys.ctr >= __sys.maxctr) throw new Error('Script halted - infinite loop?');").body[0];
var injectElseStatement = esprima.parse("if (++__sys.ctr >= __sys.maxctr) throw new Error('Script halted - infinite loop?'); else ;").body[0];
function CallExpression(callee, args) {
this.callee = callee;
this.arguments = args;
}
CallExpression.prototype.type = Syntax.CallExpression;
function Identifier(name) {
this.name = name;
}
Identifier.prototype.type = Syntax.Identifier;
function BlockStatement(body) {
this.body = body;
}
BlockStatement.prototype.type = Syntax.BlockStatement;
function ReturnStatement(argument) {
this.argument = argument;
}
ReturnStatement.prototype.type = Syntax.ReturnStatement;
function FunctionExpression(id, params, body) {
this.id = id;
this.params = params;
this.body = body;
this.defaults = [];
this.expression = false;
this.generator = false;
this.rest = null;
}
FunctionExpression.prototype.type = Syntax.FunctionExpression;
function wrapId(node, defaultName) {
if (node.loc) {
var id = (node.id || {
name: null,
loc: null
});
var loc = id.loc || node.loc;
var name = id.name || defaultName;
return new Identifier(name + '$' + loc.start.line);
} else {
return node.id;
}
}
function instrumentAST(ast) {
var identifierStack = [];
function pushIdentifier(s) {
identifierStack[identifierStack.length - 1].push(s);
}
function popIdentifierStack() {
identifierStack.pop();
}
function pushIdentifierStack() {
identifierStack.push([]);
}
function peekLastIdentifier() {
var lastStackIdx = identifierStack.length - 1;
if (lastStackIdx >= 0) {
var stack = identifierStack[lastStackIdx];
if (stack.length) {
return stack[stack.length - 1];
}
}
return '';
}
pushIdentifierStack();
return estraverse.replace(ast, {
enter: function enterAST(node) {
switch (node.type) {
case Syntax.VariableDeclarator:
if (node.id.type === Syntax.Identifier) {
pushIdentifier(node.id.name);
}
break;
case Syntax.MemberExpression:
if (node.object.type === Syntax.Identifier) {
var id = node.object.name;
if (node.property.type === Syntax.Identifier) {
id += '__dot__' + node.property.name; // huh? why mangle these?
// console.log(id);
}
pushIdentifier(id);
} else if (node.property.type === Syntax.Identifier) {
pushIdentifier(node.property.name);
}
break;
case Syntax.FunctionDeclaration:
pushIdentifierStack();
break;
case Syntax.FunctionExpression:
pushIdentifierStack();
break;
default:
break;
}
return node;
},
leave: function leaveAST(node) {
switch (node.type) {
case Syntax.DoWhileStatement:
break;
case Syntax.ForStatement:
break;
case Syntax.FunctionDeclaration:
break;
case Syntax.FunctionExpression:
break;
case Syntax.WhileStatement:
break;
default:
return estraverse.SKIP;
}
// modify the BlockStatement in-place to inject the instruction counter
if(node.body.body === undefined) {
// they have used a non-block statement as the body of a function or loop construct
// not allowed for function declarations - should never get here
if(node.type === Syntax.FunctionDeclaration) {
errors.push({
message: "Missing {",
line: node.loc.start.line,
column: node.loc.start.column
});
}
else {
// otherwise insert the test
var newBody = angular.copy(injectElseStatement);
newBody.alternate = node.body;
node.body = newBody;
}
return estraverse.SKIP;
}
node.body.body.unshift(injectStatement);
if (node.type === Syntax.FunctionExpression) {
popIdentifierStack();
// __catchErrors(node)
node.id = wrapId(node, peekLastIdentifier());
return new CallExpression(
new Identifier("__sys.catchErrors"), [node]);
}
if (node.type === Syntax.FunctionDeclaration) {
popIdentifierStack();
// modify the BlockStatement in-place to be
// return __catchErrors(function id() { body });
var funBody = node.body;
node.body = new BlockStatement([
new ReturnStatement(
new CallExpression(
new CallExpression(
new Identifier("__sys.catchErrors"), [new FunctionExpression(
wrapId(node, peekLastIdentifier()), [],
funBody)]), []))
]);
}
return node;
}
});
}
// mainApp.sandbox('var a = 1; function update(frame) { clear(0); }').code
// give it the source code as a string
mainApp.sandbox = function(code) {
var rc = {};
this.errors = [];
try {
this.ast = instrumentAST(esprima.parse(code, { range: true, loc: true }));
this.map = escodegen.generate(this.ast, { sourceMap: true, sourceMapWithCode: true });
this.code = wrapCode(this.map.code, runTemplate, '', ';\n__sys.updateFunction = (typeof update === "function") ? update : null;');
}
catch(e) {
this.errors.push({
message: e.description,
line: e.lineNumber,
column: e.column
});
}
if(this.code) {
this.code = "eng.clientFunction = function(__sys) {" + this.code + "};";
}
};
mainApp.sandbox.prototype.searchMap = function(needle) {
// binary search
var lo = 0;
var hi = this.map.map.length;
var mid, here;
while (true) {
mid = lo + ((hi - lo) >> 1);
here = this.map.map[mid];
if (mid === lo || here[0] === needle) {
return here[1];
} else if (here[0] > needle) {
hi = mid;
} else {
lo = mid;
}
}
};
})(mainApp);
Typically all JavaScript runs in one thread, so it is impossible to run any JavaScript that could stop your loop while your loop is running. Using HTML5 web workers, you can run the infinite loop in a separate thread, and then you can terminate it:
var myWorker = new Worker( '/infinite.js ');
setTimeout( function ( ) {
myWorker.terminate( );
}, 5000 );
However your web worker won't have access to the DOM, so the contents of your infinite loop would need to be different that what you have in your question.
I found exactly what I was looking for in Bergi's comment,
Alternatively, place a if (Date.now() > dateAtStartOfExecution+5000) return; in every loop body.
So now my code looks like:
function infiniteLoop() {
dateAtStartOfExecution = Date.now();
while(true) {
//do something
document.getElementById("someID").innerHTML = "Blah";
if (Date.now() > dateAtStartOfExecution+5000) {
alert("Taking too much time. Killing.");
return;
}
}
}
If I run this code after 5 seconds I will get an alert and the execution will stop. Try this:
http://js.do/code/106565

Doubts about NodeJS Module Development

I'm trying to code my very first NodeJS module, but I'm having trouble grasping some concepts.
Here's the code that I currently have (a genexer counter/generator):
"use strict";
var ret = require('ret');
module.exports = function (regex) {
if (Object.prototype.toString.call(regex) === '[object RegExp]') {
regex = regex.source;
}
else if (typeof regex !== 'string') {
regex = String(regex);
}
try {
var tokens = ret(regex);
}
catch (exception) {
return false;
}
return {
charset: '',
reference: [],
count: function (token) {
var result = 0;
if ((token.type === ret.types.ROOT) || (token.type === ret.types.GROUP)) {
if (token.hasOwnProperty('stack') === true) {
result = 1;
token.stack.forEach(function (node) {
result *= count(node);
});
}
else if (token.hasOwnProperty('options') === true) {
var options = [];
token.options.forEach(function (stack, i) {
options[i] = 1;
stack.forEach(function (node) {
options[i] *= count(node);
});
});
options.forEach(function (option) {
result += option;
});
}
if ((token.type === ret.types.GROUP) && (token.remember === true)) {
reference.push(token);
}
}
else if (token.type === ret.types.POSITION) {
}
else if (token.type === ret.types.SET) {
token.set.forEach(function (node) {
if (token.not === true) {
if ((node.type === ret.types.CHAR) && (node.value === 10)) {
}
}
result += count(node);
});
}
else if (token.type === ret.types.RANGE) {
result = (token.to - token.from + 1);
}
else if (token.type === ret.types.REPETITION) {
if (isFinite(token.max) !== true) {
return Infinity;
}
token.value = count(token.value);
for (var i = token.min; i <= token.max; ++i) {
result += Math.pow(token.value, i);
}
}
else if (token.type === ret.types.REFERENCE) {
if (reference.hasOwnProperty(token.value - 1) === true) {
result = 1;
}
}
else if (token.type === ret.types.CHAR) {
result = 1;
}
return result;
}(tokens),
generate: function () {
return false;
},
};
};
Questions:
am I calling count correctly on my first iteration? count: function (token) {}(tokens)?
how can I recursively call the count method? I get a "ReferenceError: count is not defined"
is this the correct (or best-practice) approach of defining a small module with several methods?
Forgive me for not posting 3 different questions, but I'm not very familiar with all the terminology yet.
The convention for immediately invoked closures is count: (function(args) {return function() {}})(args) but your way will also work in all environments.
You can't because count is a closure unfortunately - see 3.
If you want to use methods on your module inside your module I would declare the module outside of the return statement. If you want a good example of this see underscore/lodash source code.
So you can define your module using a declaration like the skeleton below
module.exports = function (regex) {
//...
var count = function(tokens) {
//...
return function() {
//...
var ret *= count(node);
return ret;
}
}
var mymod = {
count: count(tokens)
//...
};
//...
return mymod;
};

Categories

Resources