1

I'm reading a file using Node's fs.readFileSync(file). I need to find the index of the last occurrence of an import statement.

The js file that I'm reading will look something like:

import React from 'react';
import { FlowRouter } from 'meteor/kadira:flow-router';
import { mount } from 'react-mounter';
import { AppLayout } from '../../ui/layouts/AppLayout';
import HomePage from '../../ui/pages/HomePage';

FlowRouter.route('/', {
  name: 'home',
  action() {
    mount(AppLayout, {
      content: (<HomePage />)
    });
  }
});

So in this particular case, I would need to find the index of the semi-colon for this import statement: import HomePage from '../../ui/pages/HomePage'; since it's the last one.

I've looked into str.lastIndexOf(searchValue[, fromIndex]) but it takes a string as the searchValue, and in this case I need to pass in a regex.

It seems like I need a regex that will lookup in reverse.

How do I match and get the index of the last occurrence of import?

Scott
  • 1,322
  • 4
  • 23
  • 37
  • Match all of them and get the last item: `input.match(/^import .*/gm).pop()` - https://jsfiddle.net/f6szkm3m/ – Wiktor Stribiżew Jul 15 '16 at 16:46
  • I did not pay attention: you need the index of the last `import` - what about https://jsfiddle.net/f6szkm3m/1/? Or `var m = input.match(/^([\s\S]*\n)?import .*/); if (m){ document.body.innerHTML = m.index + (m[1] ? m[1].length : 0); }` – Wiktor Stribiżew Jul 15 '16 at 17:21
  • (Fiddle #2 - https://jsfiddle.net/f6szkm3m/2/) – Wiktor Stribiżew Jul 15 '16 at 17:26
  • So close @WiktorStribiżew! Check this out and open the console: https://jsfiddle.net/0x2pjfom/. You see how it's adding that new import before the last one? I'm trying to add it after the last one – Scott Jul 15 '16 at 18:31
  • So, you need to add another `Import` after the last one, right? See https://jsfiddle.net/0x2pjfom/1/. – Wiktor Stribiżew Jul 15 '16 at 18:38

1 Answers1

1

I think what you want to find is the last line starting with import and insert another line after it. There are several ways.

Splice & indexOf:

// splice code from http://stackoverflow.com/a/4314050/3832970
String.prototype.splice = function(idx, rem, str) {
    return this.slice(0, idx) + str + this.slice(idx + Math.abs(rem));
};
var input = "import React from 'react';\nimport { FlowRouter } from 'meteor/kadira:flow-router';\nimport { mount } from 'react-mounter';\nimport { AppLayout } from '../../ui/layouts/AppLayout';\nimport HomePage from '../../ui/pages/HomePage';\n\nFlowRouter.route('/', {\n  name: 'home',\n  action() {\n    mount(AppLayout, {\n      content: (<HomePage />)\n    });\n  }\n});";
var strt = input.lastIndexOf("\nimport ");
strt = input.indexOf("\n", strt+1);
document.body.innerHTML = "<pre>" +  input.splice(strt+1, 0, "import Example from \'../../example\';\n") + "</pre>";

Here, strt = input.lastIndexOf("\nimport ") finds the last import after a newline and that is followed with a space. Then, the next newline is found and position is incremented with strt = input.indexOf("\n", strt+1);. Then we just insert the string with splice.

Regex:

var input = "import React from 'react';\nimport { FlowRouter } from 'meteor/kadira:flow-router';\nimport { mount } from 'react-mounter';\nimport { AppLayout } from '../../ui/layouts/AppLayout';\nimport HomePage from '../../ui/pages/HomePage';\n\nFlowRouter.route('/', {\n  name: 'home',\n  action() {\n    mount(AppLayout, {\n      content: (<HomePage />)\n    });\n  }\n});";
document.body.innerHTML = "<pre>"
   + input.replace(/^(?:[\s\S]*\n)?import .*(?:\r?\n|\r)/, 
     '$&import Example from \'../../example\';\n')
   + "</pre>";

Here, the regex matches:

  • ^ - start of string
  • (?:[\s\S]*\n)? - an optional sequence of 0+ any characters as many as possible, getting to the last
  • import - literal string import with a space
  • .* - followed with 0+ any chars other than a newline (to match the rest of the line)
  • (?:\r?\n|\r) - matches a linebreak. You may add ? after this to make sure we match the last line in the string.

In the replacement, I am using $&, the backreference to the whole match (it inserts the whole match into the resulting string).

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563