is there a way to use newlines in xdmp.eval() - javascript

Hi I want to write clean code that I can read and have a good overview.
So I wrote this:
var id = '12345';
var coll = ['scc-roles','scc-proj-' + id];
var spm = 'some-role';
var data = {role : spm, roleNames : 'sccss-user', collection : coll}
var spmRoleId = xdmp.eval('declareUpdate();
var sec = require("/MarkLogic/security.xqy");
var roleId = sec.createRole(role, "Generated project member", roleNames, null, collection,null,null);
var uri = "http://marklogic.com/xdmp/roles/" + roleId;
xdmp.documentAddCollections(uri,collection)',data,{"database" : xdmp.securityDatabase()})
But apparently a newline is not allowed in xdmp.eval() ?
[javascript] JS-JAVASCRIPT: + 'var sec = require("/MarkLogic/security.xqy"); -- Error running JavaScript request: SyntaxError: Unexpected token ILLEGAL
I tried using a '+' sign to generate a strng over more then one line, swapping single and double quotes but no luck.
Being able to test this code (copy paste) to the security database makes a lot of sense to me...
If I wrap it all in one unreadable line , it works ok.
hugo

The way to effectively create a new line in a JavaScrit string is to escape the new line char like this
var str = "I'm displayed\
in two line";
In the final file, you will see effectively a new line.
If you want see in the dist output the new line but not in your src string you could just insert the \n equivalent of a return to line.
var str = "I'm displayed\n in two line";
In es6 you will be able to use ` char to achieve the same thing without \
var str = `I'm displayed
in two line`;

Maybe you would like the strange, yet useful array-notation way of doing this:
var multiline1 = [
'the lazy fox',
'jumped over',
'the dead chicken',
].join('\n');
and the result:
the lazy fox
jumped over
the dead chicken

In general, you should avoid string concatenation to build code for eval. Strings make it difficult to spot bugs and are a great vector for injection attacks. Instead, I'd advise you to write a proper function in XQuery or JavaScript and use xdmp.invokeFunction to evaluate it. invokeFunction takes all of the same options as xdmp.eval.
Here's an example that gets roles in the context of a security database. The applyAs function returns a function that wraps the function provided by the caller, evaluating it with the eval options provided.
function applyAs(fct, options) {
return function() {
var params = Array.prototype.slice.call(arguments);
// Curry the function to include the params by closure.
// xdmp.invokeFunction requires that invoked functions have
// an arity of zero.
var f = (function() {
return fct.apply(null, params);
}).bind(this);
// Allow passing in user name, rather than id
if(options.user) { options.userId = xdmp.user(options.user); delete options.user; }
// Allow the functions themselves to declare their transaction mode
if(fct.transactionMode && !(options.transactionMode)) { options.transactionMode = fct.transactionMode; }
return xdmp.invokeFunction(f, options); // xdmp.invokeFunction returns a ValueIterator
}
}
/**
* Gets an Array of id-name Objects. Requires privileged access to security.
*
* #param names An optional Array of role IDs as strings used to filter
* #return An Array of Objects with role ID keys and role name values
*/
function getRoles(names) {
var sec = require('/MarkLogic/security.xqy');
var db = {database: xdmp.securityDatabase()};
var roleIDs = applyAs(sec.getRoleIds, db);
var rolesItr;
if(Array.isArray(names)) {
rolesItr = roleIDs(xdmp.arrayValues(names));
} else {
rolesItr = roleIDs();
}
var roleNames = applyAs(sec.getRoleNames, db)(rolesItr).toArray().map(function(el) { return el.textContent; });
var roles = [];
var i = 0;
for(var role of rolesItr) {
var r = {}
r[role.textContent] = roleNames[i++];
roles.push(r);
}
return roles;
}
getRoles();
Originally from a gist.

Related

Using str.replace for multiple words

I am creating a work tool for notepad abbreviations. As the company I work for is strict about downloading any external tools I've resorted to using Javascript and HTML built on notepad.
I've been able to replace single words such as when I type "Vacancy" it returns "VAC". Or when typing "Payment" it returns "PYMT". My issue is trying to replace multiple words into 1 small abbreviation. For instance "Follow Up" I want to return "F/U". With the spaces I'm finding it is not working.
Tried multiple ways but unable to figure this out.
Here is the code snippet that I've used
function myFunction() {
var str = document.getElementById("demo").value;
var mapObj = {
Payment:"PYMT",
Vacancy:"VAC",
str = str.replace(/Payment|Vacancy, fucntion(matched){
return mapObj[matched];
});
alert(str);
document.getElementById("demo").value = res;
}
What I would like to do is add my mabObj
so it would read
function myFunction() {
var str = document.getElementById("demo").value;
var mapObj = {
Follow Up:"F/U"
str = str.replace(/Follow Up|, fucntion(matched){
return mapObj[matched];
});
alert(str);
document.getElementById("demo").value = res;
}
JavaScript objects can have properties with spaces in them, but in order to do so, the property name needs to have quotes around it.
That said, I would suggest using a Map in this case, as it will allow you to match any string without worrying about naming collisions with properties from the object's prototype.
const abbreviation = new Map([
['Follow Up', 'F/U'],
['Payment', 'PYMT'],
['Vacancy', 'VAC']
]);
const input = 'Payment noise Vacancy noise Follow Up noise Vacancy';
const pattern = new RegExp(Array.from(abbreviation.keys()).join('|'),'g');
const result = input.replace(pattern, (matched) => {
return abbreviation.get(matched) || matched;
});
console.log(result); // 'PYMT noise VAC noise F/U noise VAC'
To include a key with a space in an object you can put it in brackets like {["Follow Up"]: "F/U"}
function replaceKeyWords(str) {
var mapObj = {
Payment:"PYMT",
Vacancy:"VAC",
["Follow Up"]:"F/U",
};
str = str.replace(/(Payment|Vacancy|Follow Up)/, function(matched){
return mapObj[matched];
});
return str;
}
console.log(replaceKeyWords("Payment"));
console.log(replaceKeyWords("Vacancy"));
console.log(replaceKeyWords("Follow Up"));

Modify specific text with value

I Read a text document with readFile method ,and I got the current string.
I need to modify some specific fields inside and save the file and keep the original format
in the read file I got the following "string"
\r\nAPP_HOST=mo-d6fa.corp\r\nAPP_PORT=5000\r\nINS_PORT=50100\r\nPORT=66000\r\n
and I need to change just the number for properties
PORT=4000
APP_PORT =4000
I use the fs.readFile(filePath, 'utf8') and the response is this file
You can modify it turning into an object, setting values and then get back to string using Array.prototype.reduce:
var rawValues = "\r\nAPP_HOST=mo-d6fa.corp\r\nAPP_PORT=5000\r\nINS_PORT=50100\r\nPORT=66000\r\n";
// #1 You need to turn raw string into an array using String.prototype.split
// #2 It's time to reduce the array into an object to be able to access
// config values as a key-value pair store
var values = rawValues.trim().split("\r\n").reduce(
function(result, next, index, sourceArray) {
var keyValuePair = sourceArray[index].split("=");
result[keyValuePair[0]] = keyValuePair[1];
return result;
}, {});
// Now you can alter config values like a dictionary:
values["PORT"] = "9995";
values["APP_PORT"] = "9999";
// or using dot syntax if possible settings have valid JavaScript
// variable names...
values.PORT = "9995";
values.APP_PORT = "9999";
// ...more settings...
// #3 Once you've edited your settings, it's time to reduce each property
// as part of a new raw string containing all configurations.
rawValues = Object.keys(values).reduce(function(previousValue, property, index) {
previousValue += property + "=" + values[property] + "\r\n";
return previousValue;
}, "");
// Now PORT and APP_PORT contain their new values...
document.getElementById("rawResult").textContent = JSON.stringify(rawValues);
<div id="rawResult"></div>
Suggestion
IMHO, if you can turn your configuration into a valid JSON life can be even easier.
For example, your raw config can be { "APP_HOST": "mo-d6fa.corp", "APP_PORT": 5000, "INS_PORT": 50100, "PORT": 66000 }. See how this simplifies your problem:
var rawConfig = '{ "APP_HOST": "mo-d6fa.corp", "APP_PORT": 5000, "INS_PORT": 50100, "PORT": 66000 }';
var config = JSON.parse(rawConfig);
config["APP_PORT"] = 6000;
config["PORT"] = 7000;
rawConfig = JSON.stringify(config);
document.getElementById("result").textContent = rawConfig;
<div id="result"></div>
Instead of rolling your own configuration parser, you can just use JSON which is a well-known pattern and it has a built-in, out-of-the-box parser as part of every Web browser in the earth, NodeJS and even non-JavaScript platforms like .NET, Java...
The regexes for both these will be pretty similar. Here's a stab:
var portRegex = /\nPORT=\d+/g;
var appPortRegex = /\nAPP_PORT=\d+/g;
var fileStr = fs.readFile(filePath, 'utf8');
fileStr = fileStr
.replace(portRegex, '\nPORT=' + 4000)
.replace(appPortRegex, '\nAPP_PORT=' + 4000);
The problem with finding the exact PORT entry can be resolved by matching it at the beginning of a line only with /m modifier (in a multiline mode) that forces ^ to match at the beginning of a line:
/^(PORT\s*=\s*)\d+/m
/^(APP_PORT\s*=\s*)\d+/m
var re = /^(APP_PORT\s*=\s*)\d+/m;
var re2 = /^(PORT\s*=\s*)\d+/m;
var str = 'APP_HOST=mo-d6fa.corp\nAPP_PORT=5000\nINS_PORT=50100\nPORT=66000';
var result = str.replace(re, '$1NEWVALUE').replace(re2, '$1ANOTHERVALUE');
document.write(result);

Storing functions within arrays

I'm having a issue with something very simple. I am just wondering as to I can store these functions within an array. Check out some of the code below. I am unsure as to if this is correct as to how I am storing these functions. I am unsure as to if these functions should be within a object literal or array.This is not necessarily for a project, just good practice. Thanks!
//declaring a function
function alert_name(){
//declaring variables within a function asking user their name.
var username = prompt("Hey there, what is your name."," ");
//generating user input
var chameleon = "Welcome " + username;
//combinators
//alert("Welcome " + chameleon+ ", This is 'the website");
};
// inserting quotes into a string that is being alerted from the browser.
function otherTHings(){
var single = 'He said \'RUN\' ever so softly.';
//alert(single);
};
//running these functions and actually carry out the operations
//that have actually been declared into code above.
//string operations
function string_opertaions(){
var complete = "Com" + "plete";
//alert(complete);
// using combinators to do the same thing.
var sentance1 = "My name is";
var sentance2 = "someone";
var totalsenatces = sentance1 += sentance2;
//alert(totalsenatces);
};
//Booleans or true false values
function booleanys(){
var lying = false;
var truthful = true;
};
//Arrays very important. very similar to a object literal but different.
//Arrays store information or values or varibales/data.
var rack = [];
rack[0] = alert_name();
rack[1] = otherTHings();
rack[2] = string_opertaions();
rack[3] = booleanys();
//alert_name();
//otherTHings();
//string_opertaions();
//booleanys();
You are invoking the function and storing the result!
var rack = [];
rack[0] = alert_name;
rack[1] = otherTHings;
rack[2] = string_opertaions;
rack[3] = booleanys;

javascript regular expression match only returning last match

I have a small node application that takes some input, applies a regular expression to extract some info and should return an array of matches. All of it it pretty straight forward but the behavior I am seeing is not expected. My understanding was that if I have input with multiple lines that match this regex then each line would be an element in the array that the match returns. Unfortunately it looks like the array only contains the match groups for the last line. Is there a way to rewrite this, without iterating through the input twice, so that I can populate a nested array with the matched data per line? It would be great to return the match groups as elements, but I need to do this for each line. The end goal is to turn all this into formatted JSON for a downstream application.
Thanks for taking a look...
Now the CODE
Also available for experimentation here in a cloud 9 ide.
var util = require('util');
var re = /(processed)(.*?)\((.*?)\)(.*?)([0-9]\.[0-9]+[0-9])/g;
var data;
var returnData = [];
var Parser = function(input) {
util.log("Instantiating Parser");
this.data = input;
};
Parser.prototype.parse = function(callback) {
util.log("In the parser");
this.returnData = re.exec(this.data);
callback(this.returnData);
}
exports.Parser = Parser;
And a test file:
var Parser = require("./parser.js").Parser;
var util = require('util');
var fs = require('fs');
var data = "worker[0] processed packet (0x2000000, 1200358, t) in 0.000021 seconds\n" +
"worker[0] processed packet (0x2000000, 400115, b) in 0.000030 seconds\n"+
" (0) Registration Stats: (1387305947, 0x3d00000a, 17024, 2504, 0, 400109, 400116, b)\n"+
"worker[0] processed packet (0x1000000, 400116, b) in 0.000045 seconds\n"+
"worker[0] processed packet (0x1000000, 1200369, t) in 0.000024 seconds\n";
util.log("creating new parser");
var Parser = new Parser(data);
util.log("calling parse");
Parser.parse(function(data) {
for (var i=0; i < data.length; i++)
util.log(data[i]);
});
Here is the debuggex for the regular expression.
re.exec only returns one match each time it is executed. If you want an array of all the matches, you need to do something like this:
var matchedData = [];
var match;
while (match = re.exec(this.data)) {
matchedData.push(match);
}

Get Query String with Dojo

Users will be hitting up against a URL that contains a query string called inquirytype. For a number of reasons, I need to read in this query string with javascript (Dojo) and save its value to a variable. I've done a fair amount of research trying to find how to do this, and I've discovered a few possibilities, but none of them seem to actually read in a query string that isn't hard-coded somewhere in the script.
You can access parameters from the url using location.search without Dojo Can a javascript attribute value be determined by a manual url parameter?
function getUrlParams() {
var paramMap = {};
if (location.search.length == 0) {
return paramMap;
}
var parts = location.search.substring(1).split("&");
for (var i = 0; i < parts.length; i ++) {
var component = parts[i].split("=");
paramMap [decodeURIComponent(component[0])] = decodeURIComponent(component[1]);
}
return paramMap;
}
Then you could do the following to extract id from the url /hello.php?id=5&name=value
var params = getUrlParams();
var id = params['id']; // or params.id
Dojo provides http://dojotoolkit.org/reference-guide/dojo/queryToObject.html which is a bit smarter than my simple implementation and creates arrays out of duplicated keys.
var uri = "http://some.server.org/somecontext/?foo=bar&foo=bar2&bit=byte";
var query = uri.substring(uri.indexOf("?") + 1, uri.length);
var queryObject = dojo.queryToObject(query);
//The structure of queryObject will be:
// {
// foo: ["bar", "bar2],
// bit: "byte"
// }
In new dojo it's accessed with io-query:
require([
"dojo/io-query",
], function (ioQuery) {
GET = ioQuery.queryToObject(decodeURIComponent(dojo.doc.location.search.slice(1)));
console.log(GET.id);
});
Since dojo 0.9, there is a better option, queryToObject.
dojo.queryToObject(query)
See this similar question with what I think is a cleaner answer.

Categories