I'm writing some code that rips string literals out of Typescript/JavaScript source as the first stage of a localisation toolchain I have planned.
The fly in the ointment is string interpolation.
I was on the verge of writing a function to transform an interpolation string into a function call that rips the expressions and then replaces the interpolation string with a function call that takes the expressions as parameters.
const a = 5;
const b = 7;
const foo = `first value is ${a + b}, second value is ${a * b}`;
becomes
import { interpolate } from "./my-support-code";
...
const a = 5;
const b = 7;
const foo = interpolate("first value is ${0}, second value is ${1}", [a + b, a * b]);
with the interpolate function working through the array values and replacing strings generated from the ordinal position
function interpolate(template: string, expressions: Array<any>): string {
for (let i = 0; i < expressions.length; i++) {
template = template.replace("${" + i + "}", expressions[i].toString());
}
return template;
}
This will probably work (not yet tried) but it occurred to me that this is probably a thoroughly invented wheel. The question is basically is there a well-established package that does a comprehensive job of this?
I know the above doesn't localise anything. The point is to be rid of interpolation strings so the substitution mechanism can assume that all strings are simple literals. The base language string taken from the above would be "first value is ${0}, second value is ${1}" and translators would be expected to place the tokens appropriately in whatever string they produce.
If you're going to tackle this on a non-trivial sized code base, the best you can really do is:
Write a regular expression to identify common types of localization targets and identify them, probably by file + line number.
Add comments to your code in these locations using a keyword that's easy to git grep for, or even something that can be added to your editor's syntax highlighting rules. Personally I use things like // LOCALIZE.
If you're feeling ambitious, you could implement a rewriter that attempts to convert from template form to your localization's template requirements. Each conversion can be individually inspected, altered as required, and introduced. Hopefully you have test coverage to verify your code still works after this.
I searched for how to shuffle a deck of cards that I made and I found these lines but I can't understand...
is (this) that is written in the second line a js keyword or it't just a given name
how does m stores deck.length + i
what does m-- means at the end of the sixth line
what is the function of line no.8
shuffle() {
const { deck } = this;
let m = deck.length, i;
while (m) {
i = Math.floor(Math.random() * m--);
[deck[m], deck[i]] = [deck[i], deck[m]];
}
return this;
}
I know it's a lot to ask but I would appreciate your help
is (this) that is written in the second line a js keyword or it't just a given name
Yes, this is a keyword in JavaScript. I strongly suggest you google "this javascript" to learn how this works. It will take some time to get your head around.
how does m stores deck.length + i
I assume you are asking about let m = deck.length, i;. Notice there is a ,, not a +. m only stores deck.length. i is a separate variable that is declared on this line. I suggest you use the Chrome or Firefox developer tools to step through the code to inspect the value of m. If you are unfamiliar with these tools, you definitely need to learn about them and how to use them effectively, especially to debug your code.
what does m-- means at the end of the sixth line
-- is the post-increment operator. It decreases the value of m by 1 and stores that new value in m. The result after the subtraction is used in the rest of the expression. You can experiment with this operator in your own code or in the JavaScript console.
what is the function of line no.8
[deck[m], deck[i]] = [deck[i], deck[m]]; uses destructuring syntax to swap two values in the array. Again, you can use the debugger in the browser's developer tools to inspect the values of the variables to see what happens.
const and this are keywords
const and let are similar to var, except const cannot be assigned after initialization.
m stores only deck.length. i is another variable, declared by the let
m-- means decrementation, i.e. same as m = m-1 and it gives value of m after that calculation.
On line no.8 You can see destructuring assignment.
I am trying my hand a reversing a malicious js script to find out what it does. the script is really long but there is one part I dont fully understand and hope you can help. I will only show a small part of the script with the relevant parts to help with this problem so as to avoid anyone accidentally running it.
The following line calls the function UU multiple times:
ib[0] = O(Arw,UU(1017-980)+UU(19+81)+UU(32*3)+UU(51+25)+UU(4508/98+0)+UU(671-606)+UU(1677/43+0)+UU(631-522)+UU(5*23)+UU(7719/83-0)+UU(6+93)+UU(4*23));
The function UU has the following setup:
function UU(s)
{
var Ea = ",!)Q ;Zrvz2^#HgS{I~1(O`ba'&l%$mqVCXG9#w0]d.-8W_34[kA5<n/RBDLsFN\\tpY6E7fy?oi|+\"xJ>ThUc=uKjeM:}*P";
var h=30090;
var yz=h+29060;
var mm=yz/650;
var PF=mm-60; 31
var i = Ea[L(s)](s-PF);
return i;
}
Part of the operation to get the return value "i" calls the function L:
function L(R)
{
return "\x63\x68\x61\x72A\x74";
}
Question: what is function L returning?
I believe the function L is trying to obfuscate its return value so as to make analysis harder. I am not sure if I need to convert this to ASCII or Decimal in order to accurately complete the string lookup in function UU
Those are escape characters. It is fairly easy to look up the values in the ASCII table, but you can also console.log the string to see the resulting value.
console.log("\x63\x68\x61\x72A\x74");
It evaluates to charAt.
I am looking at the source of pace.js and it has a pretty long source code of about a thousand lines. You can view the source here.
I need to debug this code. Is there any tool or method in JavaScript using which one can identify how many unique functions are there in a given plugin? I found one way which is:
Paste the code in a text editor
Identify each function individually
Paste a console.log("i am so and so function").
Run the script and copy paste the result from the console in a text editor
Count the number of functions
Is there a easier way to do this?
This approach first finds all the functions in the window object. Then passes those function references to 'getInnerFunction()' which matches the function against a regular expression to detect any inner functions. Finally the count of functions is returned.
However it will not be able to detect inner functions of native function present in the browser, since they return
function FUNCTION NAME {
[native code]
}
this as the to string output.
For other cases this should work. Just call fnCount() and you will receive the number of functions present (subtract 2 from the result to exclude these 2 functions).
** Please correct me if there is any problem with the function matching regular expression.
function fnCount(){
var keys = Object.keys(window);
var property;
var count = 0;
for(var i=0;i<keys.length; i++){
property = window[keys[i]];
if(typeof(property) === 'function'){
count += getInnerFunction(property);
}
}
return count;
}
function getInnerFunction(property){
var fn = property.toString();
var fnCount = fn.match(/function.*\(.*\).*{.*/g).length;
return fnCount;
}
Open notepad++, press CTRL+F, type function, click Find all...
In Javascript what is the best way to handle scenarios when you have a set of arrays to perform tasks on sets of data and sometimes you do not want to include all of the arrays but instead a combination.
My arrays are labeled in this small snippet L,C,H,V,B,A,S and to put things into perspective the code is around 2500 lines like this. (I have removed code notes from this post)
if(C[0].length>0){
L=L[1].concat(+(MIN.apply(this,L[0])).toFixed(7));
C=C[1].concat(C[0][0]);
H=H[1].concat(+(MAX.apply(this,H[0])).toFixed(7));
V=V[1].concat((V[0].reduce(function(a,b){return a+b}))/(V[0].length));
B=B[1].concat((MAX.apply(this,B[0])-MIN.apply(this,B[0]))/2);
A=A[1].concat((MAX.apply(this,A[0])-MIN.apply(this,A[0]))/2);
D=D[1].concat((D[0].reduce(function(a,b){return a+b}))/(D[0].length));
S=S[1].concat((S[0].reduce(function(a,b){return a+b}))/(S[0].length));
}
It would seem counter-productive in this case to litter the code with tones of bool conditions asking on each loop or code section if an array was included in the task and even more silly to ask inside each loop iteration with say an inline condition as these would also slow down the processing and also make the code look like a maze or rabbit hole.
Is there a logical method / library to ignore instruction or skip if an option was set to false
All I have come up with so far is kind of pointless inline thing
var op=[0,1,1,0,0,0,0,0]; //options
var L=[],C=[],H=[],V=[],B=[],A=[],D=[],S=[];
op[0]&&[L[0]=1];
op[1]&&[C[0]=1,console.log('test, do more than one thing')];
op[2]&&[H[0]=1];
op[3]&&[V[0]=1];
op[4]&&[B[0]=1];
op[5]&&[A[0]=1];
op[6]&&[A[0]=1];
It works in that it sets only C[0] and H[0] to 1 as the options require, but it fails as it needs to ask seven questions per iteration of a loop as it may be done inside a loop. Rather than make seven versions of the the loop or code section, and rather than asking questions inside each loop is there another style / method?
I have also noticed that if I create an array then at some point make it equal to NaN rather than undefined or null the console does not complain
var L=[],C=[],H=[],V=[],B=[],A=[],D=[],S=[];
L=NaN;
L[0]=1;
//1
console.log(L); //NaN
L=undefined;
L[0]=1
//TypeError: Cannot set property '0' of undefined
L=null
L[0]=1
//TypeError: Cannot set property '0' of null
Am I getting warmer? I would assume that if I performed some math on L[0] when isNaN(L)===true that the math is being done but not stored so the line isn't being ignored really..
If I understand what you want I would do something like this.
var op = [...],
opchoice = {
//these can return nothing, no operation, or a new value.
'true': function(val){ /*operation do if true*/ },
'false': function(val){ /*operation do if false*/ },
//add more operations here.
//keys must be strings, or transformed into strings with operation method.
operation: function(val){
//make the boolean a string key.
return this[''+(val == 'something')](val);
}
};
var endop = [];//need this to prevent infinite recursion(loop).
var val;
while(val = op.shift()){
//a queue operation.
endop.push(opchoice.operation(val));
}
I'm sure this is not exactly what you want, but it's close to fulfilling the want of not having a ton of conditions every where.
Your other option is on every line do this.
A = isNaN(A) ? A.concat(...) : A;
Personally I prefer the other method.
It looks like you repeat many of the operations. These operations should be functions so at least you do not redefine the same function over and over again (it is also an optimization to do so).
function get_min(x)
{
return +(MIN.apply(this, a[0])).toFixed(7);
}
function get_max(x)
{
return +(MAX.apply(this, a[0])).toFixed(7);
}
function get_average(x)
{
return (x[0].reduce(function(a, b) {return a + b})) / (x[0].length);
}
function get_mean(x)
{
return (MAX.apply(this, x[0]) - MIN.apply(this, x[0])) / 2;
}
if(C[0].length > 0)
{
L = L[1].concat(get_min(L));
C = C[1].concat(C[0][0]);
H = H[1].concat(get_max(H));
V = V[1].concat(get_average(V));
B = B[1].concat(get_mean(B));
A = A[1].concat(get_mean(A);
D = D[1].concat(get_average(D));
S = S[1].concat(get_average(S));
}
You could also define an object with prototype functions, but it is not clear whether it would be useful (outside of putting those functions in a namespace).
In regard to the idea/concept of having a test, what you've found is probably the best way in JavaScript.
op[0] && S = S[1].concat(get_average(S));
And if you want to apply multiple operators when op[0] is true, use parenthesis and commas:
op[3] && (V = V[1].concat(get_average(V)),
B = B[1].concat(get_mean(B)),
A = A[1].concat(get_mean(A));
op[0] && (D = D[1].concat(get_average(D)),
S = S[1].concat(get_average(S)));
However, this is not any clearer, to a programmer, than an if() block as shown in your question. (Actually, many programmers may have to read it 2 or 3 times before getting it.)
Yet, there is another solution which is to use another function layer. In that last example, you would do something like this:
function VBA()
{
V = V[1].concat(get_average(V));
B = B[1].concat(get_mean(B));
A = A[1].concat(get_mean(A));
}
function DS()
{
D = D[1].concat(get_average(D));
S = S[1].concat(get_average(S));
}
op = [DS,null,null,VBA,null,null,...];
for(key in op)
{
// optional: if(op[key].hasOwnProperty(key)) ... -- verify that we defined that key
if(op[key])
{
op[key](); // call function
}
}
So in other words you have an array of functions and can use a for() loop to go through the various items and if defined, call the function.
All of that will very much depend on the number of combinations you have. You mentioned 2,500 lines of code, but the number of permutations may be such that writing it one way or the other will possibly not reduce the total number of lines, but it will make it easier to maintain because many lines are moved to much smaller code snippet making the overall program easier to understand.
P.S. To make it easier to read and debug later, I strongly suggest you put more spaces everywhere, as shown above. If you want to save space, use a compressor (minimizer), Google or Yahoo! both have one that do a really good job. No need to write your code pre-compressed.