Intellij Javascript multiline structural search and replace - javascript

In our project a lot of angular unit tests contain following syntax:
inject(['dependency1', 'dependency2', function(_dependency1_, _dependency2_) {
dependency1 = _dependency1_;
dependency2 = _dependency2_;
}]);
In tests the array which lists the dependencies with string values is obsolete, since this is only useful when using minification. So we issued a coding convention to change this syntax to:
inject(function(_dependency1_, _dependency2_) {
dependency1 = _dependency1_;
dependency2 = _dependency2_;
});
Now I've been replacing a couple of these in existing code when I came across them, but I've gotten really tired of doing this manually. So I'm trying to solve this in IntelliJ by using structural search and replace. This is my search template so far:
inject([$injection$, function($argument$) {
$statement$;
}]);
with occurrences:
$injection$: 1 to infinite
$argument$: 1 to infinite
$statement$: 1 to infinite
The replace template is defined as follows:
inject(function($argument$) {
$statement$;
});
This does not work for the example I defined in the beginning however, it only matches and replaces correctly for a single line statement in the function body, so following example is replaced correctly:
inject(['dependency1', 'dependency2', function(_dependency1_, _dependency2_) {
dependency1 = _dependency1_;
}]);
Am I missing something? When I check out the simple if-else example on the Jetbrains website I get the feeling that this should work.
I have tried removing the semicolon behind the $statement$ variable, this didn't match multiple lines and resulted in the semicolons being removed after replacement. I've also tried applying a regex expressions to the $statement$ variable, but these didn't help either.
((.*)=(.*);\n)+
didn't match, probably because the semicolon is filtered out by the IntelliJ structural search before the actual regex matching is performed.
(.*)=(.*)
matched, but it replaced with the same behaviour as without the regex.

Matching multiple statements with a variable in JavaScript is currently broken because of a bug.

Related

Regex - extract all headers from markdown string

I am using gray-matter in order to parse .MD files from the file system into a string. The result the parser produces is a string like this:
\n# Clean-er ReactJS Code - Conditional Rendering\n\n## TL;DR\n\nMove render conditions into appropriately named variables. Abstract the condition logic into a function. This makes the render function code a lot easier to understand, refactor, reuse, test, and think about.\n\n## Introduction\n\nConditional rendering is when a logical operator determines what will be rendered. The following code is from the examples in the official ReactJS documentation. It is one of the simplest examples of conditional rendering that I can think of.\n\n
I am now trying to write a regular expression that would extract all the heading text from the string. Headers in markdown start with a # (there can be from 1-6), and in my case always end with a new line.
I've tried using the following regular expression but calling it on my test string returns nothing:
const testString = "\n# Clean-er ReactJS Code - Conditional Rendering\n\n## TL;DR\n\nMove render conditions into appropriately named variables. Abstract the condition logic into a function. This makes the render function code a lot easier to understand, refactor, reuse, test, and think about.\n\n## Introduction\n\nConditional rendering is when a logical operator determines what will be rendered. The following code is from the examples in the official ReactJS documentation. It is one of the simplest examples of conditional rendering that I can think of.\n\n"
const HEADING_R = /(?<!#)#{1,6} (.*?)(\\r(?:\\n)?|\\n)/gm;
const headings = HEADING_R.exec(content);
console.log('headings: ', headings);
This console logs headings as null (no matches found). The result that I am looking for would be: ["# Clean-er ReactJS Code - Conditional Rendering", "## TL;DR", "## Introduction"].
I believe the regular expression is wrong, but have no idea why.
/#{1,6}.+(?=\n)/g
#{1,6} ... matches the character # at least once or as sequence of maximum 6 equal characters.
.+ matches any character (except for line terminators) at least once and as many times as possible (greedy)
does so until the positive lookahead (?=\n) matches ...
which is ... \n ... a newline / line-feed.
uses the global modifier which does match everything.
Edit
Having mentioned
"matches any character (except for line terminators)"
thus a regex like ... /#{1,6}.+/g ... should already do the job (no need for a positive lookahead) for the OP's use case which is ...
"Headers in markdown start with a # (there can be from 1-6), and in my case always end with a new line."
The result that I am looking for would be: ["# Clean-er ReactJS Code - Conditional Rendering", "## TL;DR", "## Introduction"].
const testString = `\n# Clean-er ReactJS Code - Conditional Rendering\n\n## TL;DR\n\nMove render conditions into appropriately named variables. Abstract the condition logic into a function. This makes the render function code a lot easier to understand, refactor, reuse, test, and think about.\n\n## Introduction\n\nConditional rendering is when a logical operator determines what will be rendered. The following code is from the examples in the official ReactJS documentation. It is one of the simplest examples of conditional rendering that I can think of.\n\n`;
// see...[https://regex101.com/r/n6XQub/2]
const regXHeader = /#{1,6}.+/g
console.log(
testString.match(regXHeader)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Bonus
Refactoring the above regex into e.g. /(?<flag>#{1,6})\s+(?<content>.+)/g by utilizing named capturing groups alongside with matchAll and a mapping task, one could achieve a result like computed by the next provided example code ...
const testString = `\n# Clean-er ReactJS Code - Conditional Rendering\n\n## TL;DR\n\nMove render conditions into appropriately named variables. Abstract the condition logic into a function. This makes the render function code a lot easier to understand, refactor, reuse, test, and think about.\n\n## Introduction\n\nConditional rendering is when a logical operator determines what will be rendered. The following code is from the examples in the official ReactJS documentation. It is one of the simplest examples of conditional rendering that I can think of.\n\n`;
// see...[https://regex101.com/r/n6XQub/4]
const regXHeader = /(?<flag>#{1,6})\s+(?<content>.+)/g
console.log(
Array
.from(
testString.matchAll(regXHeader)
)
.map(({ groups: { flag, content } }) => ({
heading: `h${ flag.length }`,
content,
}))
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
The issue is that you are using a literal for the regex and should not double escape the backslash, so you can write it as (?<!#)#{1,6} (.*?)(\r(?:\n)?|\n)
You can shorten the pattern capturing what you want and match the trailing newline instead of using a lookbehind assertion.
(#{1,6} .*)\r?\n
Retrieving all capture group 1 values:
const testString = "\n# Clean-er ReactJS Code - Conditional Rendering\n\n## TL;DR\n\nMove render conditions into appropriately named variables. Abstract the condition logic into a function. This makes the render function code a lot easier to understand, refactor, reuse, test, and think about.\n\n## Introduction\n\nConditional rendering is when a logical operator determines what will be rendered. The following code is from the examples in the official ReactJS documentation. It is one of the simplest examples of conditional rendering that I can think of.\n\n"
const HEADING_R = /(#{1,6} .*)\r?\n/g;
const headings = Array.from(testString.matchAll(HEADING_R), m => m[1]);
console.log('headings: ', headings);

Extract function names in python code using javascript regex

I am using prism.js to highlight python code but for some reasons it is not highlighting function names which are called for example deep_flatten() or flatten([1,2,3]) or flatten(list(map(lambda x: x*2,[1,2,3]))).
So made the following code to overcome this problem
[...document.getElementsByClassName('code')].forEach(x => {
x.innerText = x.innerText.replace(/(\w+)\([^\(\)]*\)/gi,match=>{
if(match.match(/^\d/)){
return match
}
else {
return `<span class="called-function">${match}</span>`
}
}
})
It works fine for the first two ones but fails for the other two ones.
On doing google search I found that this is called something recursive and can be done only with parsers. On searching for python parsers in javscript I found a lot of them but they are very big and for parsing whole code.
How can I make a parser/regex which extracts all function names and encloses them within span tags.
I don't want the specific code just some psuedo-code or algorithm as to how to proceed.
The default re package in std libs can't handle recursive regexes, however seems the regex package can
/(\w+)\([^\(\)]*\)/gi
can be changed to
/(\w+)(\((?:[^\(\)]|(?2))*\))/gi

Understanding which line break to target for replace() [duplicate]

I have a very specific problem concerning a regular expression matching in Javascript. I'm trying to match a piece of source code, more specifically a portion here:
<TD WIDTH=100% ALIGN=right>World Boards | Olympa - Trade | <b>Bump when Yasir...</b></TD>
The part I'm trying to match is boardid=106121">Olympa - Trade</a>, the part I actually need is "Olympa". So I use the following line of JS code to get a match and have "Olympa" returned:
var world = document.documentElement.innerHTML.match('/boardid=[0-9]+">([A-Z][a-z]+)( - Trade){0,1}<\/a>/i')[1];
the ( - Trade) part is optional in my problem, hence the {0,1} in the regex.
There's also no easier way to narrow down the code by e.g. getElementsByTagName, so searching the complete source code is my only option.
Now here's the funny thing. I have used two online regex matchers (of which one was for JS-regex specifically) to test my regex against the complete source code. Both times, it had a match and returned "Olympa" exactly as it should have. However, when I have Chrome include the script on the actual page, it gives the following error:
Error in event handler for 'undefined': Cannot read property '1' of null TypeError: Cannot read property '1' of null
Obviously, the first part of my line returns "null" because it does not find a match, and taking [1] of "null" doesn't work.
I figured I might not be doing the match on the source code, but when I let the script output document.documentElement.innerHTML to the console, it outputs the complete source code.
I see no reason why this regex fails, so I must be overlooking something very silly. Does anyone else see the problem?
All help appreciated,
Kenneth
You're putting your regular expression inside a string. It should not be inside a string.
var world = document.documentElement.innerHTML.match(/boardid=[0-9]+">([A-Z][a-z]+)( - Trade){0,1}<\/a>/i)[1];
Another thing — it appears you have a document object, in which case all this HTML is already parsed for you, and you can take advantage of that instead of reinventing a fragile wheel.
var element = document.querySelector('a[href*="boardid="]');
var world = element.textContent;
(This assumes that you don't need <=IE8 support. If you do, there remains a better way, though.)
(P.S. ? is shorthand for {0,1}.)

Unexpected behavior with function composition

I'm writing a little utility function to convert strings from one word separation scheme to another. The overall project is using lodash, which I know comes with stuff like _.camelCase, but I felt it was more extensible to not leverage those scheme-conversion helpers.
The idea is that other developers can easily add their own scheme definition to the ones I already have:
const CASES = [
{name: 'lower_kebab', pattern: /^[a-z]+(_[a-z]+)*$/g,
to_arr: w=> w.split('_'),
to_str: a=> a.map(w=>w.toLowerCase()).join('_')},
{name: 'UpperCamel', pattern: /^([A-Z][a-z]*)+$/g,
to_arr: w=> w.match(/[A-Z][a-z]*/g),
to_str: a=> a.map(_.capitalize).join('')},
//...
];
So each Case needs a pattern to determine if a string is of that scheme, a to_arr to split the string approprioately, and a to_str to join an array of words into a string of that scheme (name is optional, but it's good to be descriptive). I've included those two becuase it's in the conversion from lower_kebab to UpperCamel where I'm getting some unexpected behavior.
I've implemented the actual conversion function like so:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/lodash/4.17.3/lodash.min.js"></script>
<script src="https://cdn.jsdelivr.net/lodash/4.17.3/lodash.fp.min.js"></script>
<script>
$(document).ready(()=>{
var CASES = [
{ name: 'lower_kebab', pattern: /^[a-z]+(_[a-z]+)*$/g,
to_arr: w=> w.split('_'),
to_str: a=> a.map(w=>w.toLowerCase()).join('_')
},
{ name: 'UpperCamel', pattern: /^([A-Z][a-z]*)+$/g,
to_arr: w=> w.match(/[A-Z][a-z]*/g),
to_str: a=> a.map(_.capitalize).join('')
},
//...
];
function convert_to(target_scheme_example){
return _.compose(
CASES.find(c=>c.pattern.test(target_scheme_example)).to_str
, str=> CASES.find(c=>c.pattern.test(str)).to_arr(str) );
}
$('#go').on('click', ()=> $('#result').text(
convert_to( $('#dst').val() )( $('#src').val() )
));
});
</script>
<p>Try "<strong>UpperCamel</strong>" to "<strong>lower_kebab</strong>" and vice-versa.</p>
<input id="dst" value="UpperCamel" placeholder="Example of target scheme">
<input id="src" value="lower_kebab" placeholder="String to convert">
<button id="go">Convert</button>
<div>
<p><strong>Result:</strong></p>
<p id="result"></p>
</div>
The "real" version lives strictly in server-side code, so all that DOM-related stuff in the snippet is purely for demonstration purposes (the "real" version also does a little error checking using _.get which I excluded here for brevity).
Here's where things get weird.
On the server side, the problem manifests as convert_to('UpCa')('activity_template') evaluating to things like "Activity_template" and "activity template". In the demo snippet, I believe the same issue is manifesting as only being able click "Convert" only once without throwing an exception.
Any thoughts? Are my RegExs a little off? Have I misunderstood how to use _.compose? If the tool were just broken, that'd be one thing, but it's really throwing me off how it works for many cases, but not all.
From the documentation on RegExp#test:
test() called multiple times on the same global regular expression instance will advance past the previous match.
This is the reason why it only works the first time: the regular expression object (pattern) maintains state resulting from the previous execution of the test method on it.
To avoid this behaviour, you could do one of the following:
Remove the g modifiers from the pattern regular expressions, since they are not necessary for the kind of matching you are trying to do, or
Use the String#match method instead, swapping the position of the string and the regular expression:
return _.compose(
CASES.find(c=>target_scheme_example.match(c.pattern)).to_str
, str=> CASES.find(c=>str.match(c.pattern)).to_arr(str) );
}

AngularJs Web Components using special characters

as Web Components, I mean AngularJs's directives here.
I am trying to use special characters as a tag's name, especially asiatic ones (korean even more specifically).
Here's a plunker so you'll get a better grasp on what I try to achieve.
// library
(function (angular) {
angular.module('molecules', [])
.directive('헐', function () { return {
template: 'ㅎㅓㄹ'
}});
})(window.angular);
// main module
(function (angular) {
angular.module('lab', ['molecules']);
})(window.angular);
<div ng-controller="monitor1">
<헐></헐>
</div>
It seems to have to do with how the browser is interpreting the DOM. If you append an alphabet character to the foreign character (in the directive and the start and end tags), it works as expected i.e.
<a헐></a헐>
Note - check out the DOM while you are at it (I was checking in IE11) - notice that the tag is closed with . With <헐> notice that the IE has taken it upon itself to make some modifications. There is also the console error HTML1407: Invalid tag name. First character should match [a-zA-Z].

Categories

Resources