2

I have a set of template files present in folder say /root/path/templates/ and corresponding input files at path say /root/path/inputs/<template_name>/. Here <template_name> indicates the folder name which holds all the input files for a given template.

Let's say template file contains v

  1. List item

alue as %1 %2 which are like place holders, where we need to replace the %n with the line number from input file line which are present in /root/path/inputs/<template_name>/.

For example:

template file name as `t1.template` and its content are `%1 %2`

Input files are `in1.input` and `in2.input` at path `/root/path/inputs/t1`.

The content for in1.input as:

First
Second

The content for in2.input is 

Third
Fourth

My expected output should be like this:

t1/in1.output
First Second
t1/in2.output
Third Fourth

Now the template file can have any characters say:
`This is a template file with %1 %2 fields. Also it has %%1 percenage`

Here the corresponding output should be :


t1/in1.output
This is a template file with First Second fields. Also it has %1 percenage
t1/in2.output
This is a template file with Third Fourth fields. Also it has %1 percenage

means only %1 and %2 placeholders should be replaced. If %%n then while generating result show it as %n, it is not treated as placeholder.

Now I am trying to implement this using JS and Node:

var fs = require('fs');
var arr = fs.readdirSync("/root/path/templates");
var response = "";
for(let i=0; i<arr.length; i++) {
    var item = arr[i];
    var hastemplate = item.indexOf(".template");
    if(hastemplate > -1) {
        var tempName = item.substring(0, hastemplate);
        var lineReader = require("readline").createInterface({
            input: fs.createReadStream("/root/path/inputs/"+tempName)
        });
        
        lineReader.on("line", function(line) {
            console.log(line + ' ' +tempName);
        });
    }
}

Input to this program:

/root/path/templates/t1.template
/root/path/inputs/t1/in1.input
/root/path/inputs/t1/in2.input
/root/path/templates/t2.template

When I try to print the file name in lineReader I am getting it as t2.template, i am not able to properly read the data from t1.template and its files in1.input and in2.input.

I also want to know how to read the input files and maintain the order for the output.

So got stuck here with my code incomplete.

learner
  • 6,062
  • 14
  • 79
  • 139
  • 1
    This is a scope problem (see [JavaScript closure inside loops – simple practical example](https://stackoverflow.com/q/750486/218196)). Use `let` instead of `var`. – Felix Kling Jul 30 '20 at 07:53
  • I also wonder where you get the variable `file` from in line `input: fs.createReadStream("/root/path/inputs/"+file)` – Andre Jul 30 '20 at 08:09
  • @Andre, it is actually `tempName`, I updated it – learner Jul 30 '20 at 17:40

1 Answers1

1

As @Felix Kling stated in the comments, it is a scope problem and it is triggered by the fact that lineReader.on("line", ...) is not synchronous.

Here is an example illustrating your bug in a shorter manner:

for (let i = 0; i < 3; i++) {
    var temp = i;
    setTimeout(() => console.log(i, temp), 1000);
}

Output:

0 2
1 2
2 2

The first time var temp is encountered, the variable temp is created, then every time the loop runs, the original variable is modified. As the loop ends before any of the setTimeout calls, all of them will "know" that temp = 2.

Using let or const would bind the variable to the context of each iteration, a new variable is created each time. I highly suggest using const to leverage some advantages of immutability too, when it is the case.

const fs = require('fs');
const arr = fs.readdirSync("/root/path/templates");
let response = "";
for(let i=0; i<arr.length; i++) {
   const item = arr[i];
   const hastemplate = item.indexOf(".template");
   if(hastemplate > -1) {
       const tempName = item.substring(0, hastemplate);
       const lineReader = require("readline").createInterface({
           input: fs.createReadStream("/root/path/inputs/"+tempName)
       });
       
       lineReader.on("line", function(line) {
           console.log(line + ' ' +tempName);
       });
   }
}
Mihail Feraru
  • 1,419
  • 9
  • 17
  • I am now stuck at how to read the corresponding input files and display the output message as per my post. – learner Aug 04 '20 at 14:23
  • @learner could you elaborate a little bit? I think you are having trouble understaing asynchronous programming, right? – Mihail Feraru Aug 04 '20 at 14:29
  • Once I read the template file, I need to get the input files from their specific folder if present and read and replace the data – learner Aug 04 '20 at 16:46
  • Ok, so the reading part is done. The replace could be done with builtin functions. So, where do you exactly struggle? – Mihail Feraru Aug 04 '20 at 19:39
  • I am able to read only the template file, but got stuck on how to read all the input files and maintain the output message as per my post as reading is asyncronous. – learner Aug 04 '20 at 21:09
  • @learner you can just save the lines in an array and trigger an event with all the results once you have the full list – Manolo Aug 09 '20 at 16:26