gkz / grasp

JavaScript structural search, replace, and refactor
http://graspjs.com
MIT License
1.28k stars 33 forks source link

Please allow filters passed as a structure and not string only :) #112

Open kristianmandrup opened 7 years ago

kristianmandrup commented 7 years ago

For using grasp as a library and not simply for command line, it would be super useful if the following logic was changed:

replacer = (input, node, query-engine) ->
  (, replacement-arg) ->
    if /^\s*\|\s+/.test replacement-arg
      orig-results = [node]
      [, ...filters] = " #{ replacement-arg.trim! }".split filter-regex # prepend space so regex works
    else
      [selector, ...filters] = replacement-arg.trim!.split filter-regex
      if node._named?[selector]
        orig-results = [].concat that
      else
        try
          orig-results = query-engine.query selector, node
        catch
          orig-results = query-engine.query replacement-arg, node
          filters := []

PS: Super ugly/confusing code IMO, with all these nested if's and try/catch. Please let's improve the code!

Could we place make it into something like

    (, replacement-arg, filter-arg) ->
    filter-arg = filter-arg || replacement-arg
    if /^\s*\|\s+/.test filter-arg
      orig-results = [node]
      [, ...filters] = " #{ filter-arg.trim! }".split filter-regex # prepend space so regex works
    else
      [selector, ...filters] = filter-arg.trim!.split filter-regex
      if node._named?[selector]
        orig-results = [].concat that
      else

And then if filters-arg is defined, iterate/extract each filter the Array of the form:

filters = [{
    action: 'append',
    value: `hello() { }`
  },
  {
    action: 'prepend',
    value: `before() { }`
  }
]

Use filters as is (Array) if passed as such via filter-arg

    if Array.isArray filter-arg
      filters = filter-arg

Would be so much easier to reason about than the current approach. Then you could also use the filter-regex and split etc. to generate such a filter structure to iterate instead...

Some initial ideas for refactoring this huge mess... way too many variables and too few functions. Never have 100 line long deeply nested functions with dozens of local variables!! :O

get-args = (filters)
  args-str = filters.shift!.trim!
  args-str += filters.shift! # extra
  levn.parse 'Array', args-str

...
      while filters.length
        filter-name = filters.shift!
        args = get-args filters
query-results = (query-engine, node, selector, replacement-arg) ->
  try
    query-engine.query selector, node
  catch
    query-engine.query replacement-arg, node

get-orig-results = (node, hasFilter)
  [node] if hasFilter
  orig-results = if node._named?[selector]
    [].concat that
  else
    query-results query-engine, node, selector, replacement-arg

# TODO: refactor this sucky code!!!
if /^\s*\|\s+/.test filter-arg
  orig-results = [node]
  [, ...filters] = " #{ filter-arg.trim! }".split filter-regex # prepend space so regex works
else
  [selector, ...filters] = filter-arg.trim!.split filter-regex

replacer = (input, node, query-engine) ->
  (, replacement-arg, filter-arg) ->
    filter-arg = filter-arg || replacement-arg
    if typeof filter-arg
      if /^\s*\|\s+/.test filter-arg
        filters = " #{ filter-arg.trim! }".split filter-regex # prepend space so regex works
      else
        # ...

    if Array.isArray filter-arg
      filters = filter-arg

    if orig-results.length
      # TODO: put in a record (Object) WTF
      results = orig-results
      raw-prepend = ''
      raw-append = ''
      join = null
      text-operations = []