How to write a simple script to read text from a file and compute the number of sentences, number of unique words and punctuation/symbols? (NodeJS)
Word count bug This line here:
const wordCount = (string) =&gt; string.split(&quot; &quot;).length;

will overcount the number of words if the input text happens to have multiple spaces in a row. For example:


const wordCount = (string) =&gt; string.split(" ").length;

console.log(wordCount(`
  foo        bar baz
`));



I'd use .match instead, and match contiguous non-space characters. (Can't use \w+, since that'd result in they're and similar being counted as 2 words, and since \w only works with English letters - matching non-spaces is easier than figuring out all the possibilities, and will work for any romance language)


const wordCount = (string) =&gt; (string.match(/\S+/g) || []).length;

console.log(wordCount(`
  foo        bar baz
`));



The .match(..) || [] is needed because .match will return null (and not the empty array) if no matches are found.
uniqueWords bug As noted above, \w+ won't be accurate given apostrophes and other punctuation marks that may be around or inside single words. (You also need to alternate the .match with [] as described above too)
paragraphCount issues
You have:
paragraphString = paragraphString.split(&quot;\n\n&quot;);

There are a few problems here:

The paragraphString is initially not the string of a paragraph, but a string containing the entire input text - better to call it something like inputText.
Then, the paragraphString becomes an array - but its name is paragraphString? Easy source of confusion.
You're unnecesarily reassigning the paragraphString variable - it may refer to one thing, or it may refer to another, depending on what point in the program you're examining it. Code is generally easiest to reason about when the contents of a given variable name doesn't change. Occasionally it's necessary (like with a counter), but often it isn't - better to put a new expression into a different variable rather than reassigning the old one, if possible.

Similarly:
let paragraphArray = paragraphString.length; // length of paragraph array

But the .length is a number, not an array. Giving variables understandable, precise variable names makes code easier to read and helps prevent bugs. I'd either call it paragraphIndex - or, even better, avoid manually iterating over the array entirely and use an array method instead, eg:
paragraphArray.forEach((paragraphString) =&gt; {
  // check paragraphString

Empty strings can have .replace called on them just fine, and it makes the code easier to read, so you can simplify the assignment of tmp to:
const paragraphString = paragraphStrings[paragraphIndex].replace(strip_whitespace,&quot;&quot;);

Or you could simplify the whole function here by filtering the array of paragraphs by those with a trimmed length:
const paragraphCount = inputText =&gt; inputText
  .split('\n\n')
  .filter(paragraphText =&gt; paragraphText.trim())
  .length;

You could also use .reduce to count up, instead of constructing an intermediate array that gets used only for its length, but the intent of this .reduce is probably a bit harder to recognize at a glance for some:
const paragraphCount = inputText =&gt; inputText
  .split('\n\n')
  .reduce((a, paragraphText) =&gt; a + paragraphText.trim() ? 1 : 0, 0)

\n\n might not be good enough, though - can you count on the file encoding using \ns only for newlines? Some files/OSs use \r\n. I'd use /\n\r?\n/ instead.
Punctuation count idea Rather than:
const punctuations = [&quot;.&quot;, &quot;,&quot;, &quot;!&quot;, &quot;?&quot;];
// const symbols = [&quot;~&quot;,&quot;`&quot;,&quot;!&quot;,&quot;@&quot;,&quot;#&quot;,&quot;$&quot;,&quot;%&quot;,&quot;^&quot;,&quot;&amp;&quot;,&quot;*&quot;,&quot;(&quot;,&quot;)&quot;,&quot;_&quot;,&quot;+&quot;,&quot;-&quot;,&quot;=&quot;,&quot;{&quot;,&quot;}&quot;,&quot;|&quot;,&quot;[&quot;,&quot;]&quot;,&quot;\&quot;,&quot;:&quot;,&quot;;&quot;,&quot;'&quot;,&quot;&lt;&quot;,&quot;&gt;&quot;,&quot;?&quot;,&quot;/&quot;,]

With a lot of punctuation, the above can be both hard to read and easy to make typos on. If you have more than a few, consider using a string that gets parsed into an array later:
const symbols = `\`~!@#$%^`.split(''); // and so on

You could even make it multiline or put it in a separate file if you wanted, then parse it as needed.
To reduce the computational complexity of the algorithm, make a Set of the punctuations in advance; Set.has is O(1), but Array.includes is O(n). With large files, this could make a big difference, especially if you wree using the large symbols array instead of the smaller punctuations array.
Constructing a regular expression that alternates between all punctuation characters might be even faster.