String.raw output "${" and bacticks - javascript

I am using String.raw to hold the contents to hold a regex that contains values like ${somevalue} in a RegExp I have. It works except there appears to be no way to escape ${} or backticks.
For example this doesn't work.
String.raw`${}` // error
String.raw`$\{}` // wrong output
String.raw`\${}` // wrong output
String.raw`\`` /wrong output
Unfortunately the best solution I can come up with is the following.
String.rawer= (s)=>{return s.raw[0].replace(/\\\{/g,"{").replace(/\\`/g,'`').replace(/\\\\$/,'\\')}
Is there a solution that is less ugly that doesn't require defining my own function and subsequent function calls?

I think this looks cleaner than what you have
console.log(String.raw`${"${}"}`)
You would have to put the ${} inside a ${} and put quotes around it inside. But this is an annoying issue that doesn't really have a simple solution to it, that I am aware of anyways.

Related

How does this line of code for checking whether a word is palindrome or not, work in JS?

So I was going through solutions to find the fastest way to perform the operation of checking whether a word is palindrome or not in Javascript. I came across this as one of the solutions listed and it works, but I have no clue why the `` is used and how exactly it works. A detailed explanation would be welcome.
The code is as follows,
p=s=>s==[...s].reverse().join``
p('racecar'); //true
The link for the original answer is,
https://stackoverflow.com/a/35789680/5898523
tagged template literals: without tagged template literals the sample would look like this:
p = s=>s==[...s].reverse().join('')
EDIT:
Looks like I answered before I read your question in full, sorry. Template literals allow for placeholders that look like ${placeholder}. ES6 runs the template through a built-in processor function to handle the placeholders, but you use your own custom function instead by using this 'tag' syntax:
tagFunction`literal ${placeholder} template`
The example code uses (abuses in my opinion) this functionality to save 2 characters by invoking the join method as a tag with an empty template.
JS interprets it as the first argument for the join function, as otherwise it would join the string with the default ",". The part ".join``" equates to ".join('')", without having to add the two extra chars for the parentheses.
As to why exactly only `` works for this and not "" or '', you would have to look up the ECMA Script documentation; I don't have an explanation offhand for you.

A way to automatically enclosure quotes inside string containing code (RegExp maybe?)

Is there a way to automatically enclosure all quotes inside the string of js-code which contains other strings by itself? I just failed to make a RegExp valuable to identify all the quotes properly. Because in some cases (blocks of code generated by script) there strings of code like:
$(".class1.class2:contains('text')").param(s1+s2+"-"+s3+"_"+i)...
var r=new RegExp("blabla[qwer]\\'\\w+\\d\\'");
//etc.
More complex actually and less readable =)
But anyways is there a way to get rid of constant http/ajax/json requests and make code to work without injection but via eval? It's not intended to be used in outer net so it's safe, dont tell me anything 'bout eval =) The main problem: how to make enclosurement of quotes inside the string...
Edit:
Sorry i just don't know how to say it in English, so by enclosurement i mean insertion of a specific symbol before char which has dual meaning to clarify it's definition for compiler or machine-interpreter.
Example1: ('first_part_of_string enclosured_quote=\' second_part_of_string')
Example2: `<- these symbols don't get interpreted as code-markers because of enclosurement ->`
Sure, here it is with single quotes:
'
$(".class1.class2:contains(\'text\')").param(s1+s2+"-"+s3+"_"+i)...
var r=new RegExp("blabla[qwer]\\\\\'\\\w+\\\d\\\\\'");
'
here it is with double quotes:
"
$(\".class1.class2:contains('text')\").param(s1+s2+\"-\"+s3+\"_\"+i)...
var r=new RegExp(\"blabla[qwer]\\\\'\\\\w+\\\\d\\\\'\");
"
You can use the Mega-String tool to do this automatically
I used the single / double quote option from the Other category..

g:message with arguments inside Javascript / jQuery not working as expected

I had an issue where String arguments were being truncated to the first character in our g:message tags (longs/integers seemed to be fine).
Ultimately, I figured out we were not calling g:message syntactically correct from within Javascript so some minor tweaks fixed the issue. Problem is - I don't understand why the former doesn't work.
Can anyone describe what was happening here?
jQuery("#myId").html("<g:message code='domain.message.path' args="${command?.foo?.name}"/>"); //incorrect, only displays first character of message
jQuery("#myId").html("${g.message(code: 'domain.message.path', args: [command?.foo?.name])}"); //correct, displays full string
I assume you're rendering this as part of a .gsp page? Here's the thing. In the first one, you're nesting quotes, essentially leaving the ${} section out of the string. Even Stackoverflow can tell; note how that part is a different color:
jQuery("#myId").html("<g:message code='domain.message.path' args="${command?.foo?.name}"/>");
See how the quote at the end of html( is ended by the quote before ${, leaving the ${command?.foo?.name} block outside the string? If command.foo.name was the string "bob", then when this rendered, you'd get:
jQuery("#myId").html("<g:message code='domain.message.path' args="bob"/>");
You might think this looks right, but javascript will handle this poorly.
If you used single quotes for the internal string, like you do with 'domain.message.path', it should work fine:
jQuery("#myId").html("<g:message code='domain.message.path' args='${command?.foo?.name}'/>");

regex replace on JSON is removing an Object from Array

I'm trying to improve my understanding of Regex, but this one has me quite mystified.
I started with some text defined as:
var txt = "{\"columns\":[{\"text\":\"A\",\"value\":80},{\"text\":\"B\",\"renderer\":\"gbpFormat\",\"value\":80},{\"text\":\"C\",\"value\":80}]}";
and do a replace as follows:
txt.replace(/\"renderer\"\:(.*)(?:,)/g,"\"renderer\"\:gbpFormat\,");
which results in:
"{"columns":[{"text":"A","value":80},{"text":"B","renderer":gbpFormat,"value":80}]}"
What I expected was for the renderer attribute value to have it's quotes removed; which has happened, but also the C column is completely missing! I'd really love for someone to explain how my Regex has removed column C?
As an extra bonus, if you could explain how to remove the quotes around any value for renderer (i.e. so I don't have to hard-code the value gbpFormat in the regex) that'd be fantastic.
You are using a greedy operator while you need a lazy one. Change this:
"renderer":(.*)(?:,)
^---- add here the '?' to make it lazy
To
"renderer":(.*?)(?:,)
Working demo
Your code should be:
txt.replace(/\"renderer\"\:(.*?)(?:,)/g,"\"renderer\"\:gbpFormat\,");
If you are learning regex, take a look at this documentation to know more about greedyness. A nice extract to understand this is:
Watch Out for The Greediness!
Suppose you want to use a regex to match an HTML tag. You know that
the input will be a valid HTML file, so the regular expression does
not need to exclude any invalid use of sharp brackets. If it sits
between sharp brackets, it is an HTML tag.
Most people new to regular expressions will attempt to use <.+>. They
will be surprised when they test it on a string like This is a
first test. You might expect the regex to match and when
continuing after that match, .
But it does not. The regex will match first. Obviously not
what we wanted. The reason is that the plus is greedy. That is, the
plus causes the regex engine to repeat the preceding token as often as
possible. Only if that causes the entire regex to fail, will the regex
engine backtrack. That is, it will go back to the plus, make it give
up the last iteration, and proceed with the remainder of the regex.
Like the plus, the star and the repetition using curly braces are
greedy.
Try like this:
txt = txt.replace(/"renderer":"(.*?)"/g,'"renderer":$1');
The issue in the expression you were using was this part:
(.*)(?:,)
By default, the * quantifier is greedy by default, which means that it gobbles up as much as it can, so it will run up to the last comma in your string. The easiest solution would be to turn that in to a non-greedy quantifier, by adding a question mark after the asterisk and change that part of your expression to look like this
(.*?)(?:,)
For the solution I proposed at the top of this answer, I also removed the part matching the comma, because I think it's easier just to match everything between quotes. As for your bonus question, to replace the matched value instead of having to hardcode gbpFormat, I used a backreference ($1), which will insert the first matched group into the replacement string.
Don't manipulate JSON with regexp. It's too likely that you will break it, as you have found, and more importantly there's no need to.
In addition, once you have changed
'{"columns": [..."renderer": "gbpFormat", ...]}'
into
'{"columns": [..."renderer": gbpFormat, ...]}' // remove quotes from gbpFormat
then this is no longer valid JSON. (JSON requires that property values be numbers, quoted strings, objects, or arrays.) So you will not be able to parse it, or send it anywhere and have it interpreted correctly.
Therefore you should parse it to start with, then manipulate the resulting actual JS object:
var object = JSON.parse(txt);
object.columns.forEach(function(column) {
column.renderer = ghpFormat;
});
If you want to replace any quoted value of the renderer property with the value itself, then you could try
column.renderer = window[column.renderer];
Assuming that the value is available in the global namespace.
This question falls into the category of "I need a regexp, or I wrote one and it's not working, and I'm not really sure why it has to be a regexp, but I heard they can do all kinds of things, so that's just what I imagined I must need." People use regexps to try to do far too many complex matching, splitting, scanning, replacement, and validation tasks, including on complex languages such as HTML, or in this case JSON. There is almost always a better way.
The only time I can imagine wanting to manipulate JSON with regexps is if the JSON is broken somehow, perhaps due to a bug in server code, and it needs to be fixed up in order to be parseable.

Passing bad string as javascript parameter

I'm having a problem passing parameters that I think I should be able to solve elegantly (with 1 line of code) but I can't seem to solve the issue. I have a link to delete items, like so:
<a href="javascript:confirmDelete('${result.headline}',${result.id});">
The problem arises when result.headline contains characters like ' or " or others that break the javascript call. I have tried ${fn:replace(result.headline,"'","")} which fixes issues for ' however I want to do some sort of URLEncode (I think) so that these characters dont break the javascript call. Any ideas on how to fix this without changing anything on the back-end?
Avoid putting inline JavaScript in elements, especially javascript: pseudo-URLs which (apart from being Evil that should never be used) are JavaScript-in-URL-in-HTML. You would have to take the headline and:
JavaScript string literal-encode it. (Replacing \, ', control characters and potentially Unicode characters, or just using a JSON encoder to do it for you.) Then,
URL-encode it. Then,
HTML-encode it.
Better to put the data in the markup where you only have to worry about simple HTML encoding in the way you do everywhere else to avoid cross-site-scripting:
Delete
and have the JavaScript extract them:
<script type="text/javascript">
for (var i= document.links.length; i-->0;) {
var link= document.links[i];
if (link.className.indexOf('confirmdelete-')===0) {
link.onclick= function() {
confirmDelete(this.title, this.className.substring(14));
return false;
};
}
}
</script>
(there are potentially simpler, shorter or cleaner ways of writing the above using utility functions or frameworks, and there's an argument to be had over whether a link is really the right markup for this kind of action, but that's the basic idea.)
As long as you can rely on the fact that the strings don't have newlines, all you need to do is double all backslashes and escape all single quotes.
For example:
replace(replace(result.headline, "\\", "\\\\"), "'", "\\'")
This might not be valid syntax in your server-side language; I don't recognize it.

Categories

Resources