0

If I have a JavaScript expression and I want to replace all instances of a particular property with a function instead. For example:

foo => getFoo()
a.b.foo => getFoo(a.b)
a.foo.b => getFoo(a).b
a.foo.foo => getFoo(getFoo(a))
a.foo.b.foo => getFoo(getFoo(a).b)
a.foo+b.foo||c.foo => getFoo(a)+getFoo(b)||getFoo(c)
a(b.foo) => a(foo(b))

I will need to have a check for the characters which would mean the end or start of a particular variable which are ' ', '|', '&', '(', ')', ',', '+', '-', '=', '<', '>'

If I get to the string 'foo' I then need to move everything from the character after one of those listed above to the inside of getFoo().

Not sure how this can be implemented or if another method other than regex would be a better approach?

user2802557
  • 747
  • 1
  • 9
  • 19
  • why you want to do this ? – pirs Jul 11 '17 at 09:43
  • because I need to input some logic into the getFoo() function and it will then only return foo if some criteria passes, otherwise return something else. – user2802557 Jul 11 '17 at 09:45
  • why you dont create a getFoo object and extend it (shallow copy for ex, or prototyting..) – pirs Jul 11 '17 at 09:46
  • Do you mean using Object.defineProperty to add another 'getFoo' property on where I have my check. I don't want to be adding this property on for all objects when it mostly won't come up – user2802557 Jul 11 '17 at 09:51

2 Answers2

1

You can do a recusrive find & replace like:

function replacer(match, params) {                   // the match could be 'a.foo.b.c.foo' and params is then 'a.foo.b.c.'
  if(params) params = params.slice(0, -1);           // if there is params, then cut the last '.' out
  return "getFoo(" + parse(params) + ")";            // the parsed version of params wrapped in a getFoo call
}

function parse(text) {
  if(!text) return "";                               // if text is empty or undefined then return the empty string
  return text.replace(/((?:\w+\.)*)foo/g, replacer); // otherwise match all text before before (a sequence of identifier followed by '.') 'foo' ('a.foo.b.c.foo' the group will be 'a.foo.b.c.') and then use the replacer function to replace the match
}

[
  "foo",
  "a.b.foo",
  "a.foo.b",
  "a.foo.foo",
  "a.foo.b.foo",
  "a.foo+b.foo||c.foo",
  "a(b.foo)",
].forEach(function(t) {
  console.log(t, "=>", parse(t));
});

Update: 16/09/2017

I have changed the regex from: /(\w+\.)*foo/g to: /((?:\w+\.)*)foo/g as the first has a problem matching the group: It will match only the last \w\. but not all the \w\.\w\.\w\..... It seemed to have worked when I first posted the answer. I didn't notice it when I posted the answer. Further reading about this problem here.

ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73
0

Try an other approach with a basic prototyping, you could create some prototypes to "mix" your function each other like you want, it should be cleaner to do a couple of prototypes (js prototype) than transform your string in a function (js string to function) :

function Toolbox(name){

  this.name = "im "+name;



  this.a = function(){
    return 1;
  }

  this.b = function(){
    return 2;
  }

  this.c = function(){
    return this.a + this.b;
  }

}

// create a new Toolbox
var uniqToolbox = new Toolbox("Julien");

// extend
uniqToolbox.d = function(){ 
  return true;
}

alert(uniqToolbox.name);
pirs
  • 2,410
  • 2
  • 18
  • 25
  • 1
    Instead of just writing a code, try to explain what it does. Furthermore I don't get how it is related to the question – Mistalis Jul 11 '17 at 10:07