Description of the problem
The
template literals that appeared in ES6 (or template strings - template literals, template strings) in addition to the long-awaited interpolation of variables and expressions brought the ability to insert multi-line text without additional tweaks complicating the code.
However, what looks beautiful in a variety of examples on this topic, in real code, sometimes wraps itself in a new kind of disgrace.
However, the problems are visible, even if you look at examples. Take a
wonderful article about this innovation from the famous series “
ES6 In Depth ”.
')
See the annoying "pockmarks"? Light imbalances in symmetry and harmony?
Small examplevar text = ( `foo bar baz`)
Great example var html = `<article> <header> <h1>${title}</h1> </header> <section> <div>${teaser}</div> <div>${body}</div> </section> <footer> <ul> ${tags.map(tag => `<li>${tag}</li>`).join('\n ')} </ul> </footer> </article>`
Take some simple case and take a closer look at the problems.
const a = 1; const b = 2; console.log( `a = ${a}. b = ${b}.` );
1. The first quote distorts the harmony of the text, spoils the alignment of the lines.
2. Because of the mixture of literal elements and code, it automatically seems as if the quotes will fall into the output. We have to abstract away from them in order to imagine what the final result will look like.
3. The lines of the literal are flush with the function call, the usual structure of indents is broken.
You can do this:
const a = 1; const b = 2; console.log(` a = ${a}. b = ${b}. `);
This solves the problems mentioned: the alignment of lines is preserved, the elements of the code and the literal are spaced apart, the usual structure of indents improves readability, separates function and arguments more clearly.
But now we have extra line breaks and spaces. Sometimes you can put up with it, but do not pull on a universal solution.
Let's aggravate our example by introducing additional blocks and indents.
const verbose = true; if (verbose) { console.log( `const a is ${a}. const b is ${b}.` ); } else { console.log( `a = ${a}. b = ${b}.` ); }
Awful. Now the literal generally sticks out to the left, destroying the block structure.
You can fix it as described above:
if (verbose) { console.log(` const a is ${a}. const b is ${b}. `); } else { console.log(` a = ${a}. b = ${b}. `); }
It has become even more "service" gaps. And if you have to insert a literal at an even deeper level of nesting? All this will quickly get out of control.
Assigning variables or
console.log
calls can be replaced with functions for writing to files, the dilemma will remain the same - either an unreadable mess, or extra spaces and new lines:
fs.writeFileSync('log.txt', `a = ${a}. b = ${b}.`, 'ascii');
or
fs.writeFileSync('log.txt', ` a = ${a}. b = ${b}. `, 'ascii');
I found a way out for myself that I decided to share. Not so much because I took the risk of counting it as generally useful, but rather in order to start a discussion: it is likely that other ways have already been found, and everyone will be able to distribute them.
Possible Solution
It lies in the area of ​​the same innovation, namely in the functional called "tagged templates". In the already mentioned article there is a section dedicated to this mechanism and “chewing” the algorithm of its work to a considerable clarity: “
Demystifying Tagged Templates ”.
The “skeletons” of the functions that process template literals cited by the author prompted me to use something similar to remove all service spaces and line breaks from multiline literals. It turned out this function:
As you can see, the function removes one initial and final newline from the final result, and also removes all leading spaces in the lines (without affecting the interpolated variables and expressions). At the same time, she tries to preserve the internal indentation of deeper investments: the first line defines the service indent in the code and removes only an equal number of spaces - this way it becomes possible to save structures like the large example given above with the HTML code.
Now you can safely use our more readable options, with a small, barely noticeable addition, which does not spoil the type of code (however, the function can be called somehow - longer, shorter, using different versions of visibility, intuitive clarity, etc.):
const a = 1; const b = 2; console.log(xs` a = ${a}. b = ${b}. `); const verbose = true; if (verbose) { console.log(xs` const a is ${a}. const b is ${b}. `); } else { console.log(xs` a = ${a}. b = ${b}. `); }
Now the code has become clearer, and nothing extra falls into the output.
I hope this is only the first test case, and other ideas will emerge that differ more or less radically. It is possible that unobvious obstacles to the use of such solutions will also be found, unnoticed errors will be corrected, and unaccounted use cases that violate the function will be indicated.
PS About a simple library that solves similar problems.PPS Updated function to save indents.