This is somewhat similar to python or java's ability to use triple-quotes to represent literal strings without lots of escape characters, something I think could be useful is the following extension to backticked template literals:
Allow specifying triple- (or maybe quintuple-, or septuple-, or any-odd-number-uple-) backticked literals, which behave almost the same as a regular backticked template literal, with a few key differences:
- The string is automatically "dedented", along the lines of what the dedent library does. A simple algorithm would be:
- ignore the first line
- calculate the "indent" using the whitespace at the beginning of the first line
- remove that indent from every line
- The string would be automatically trimmed
- (maybe) backticks inside the string don't need to be escaped
it would look something like this:
console.log(``` yaml: is: supported: nicely ```)
This would calculate that the "indent" is two spaces (from the first line, " yaml:
...") and would print out:
yaml: is: supported: nicely
To achieve the same thing with an existing template literal makes code quite hard to read, especially when the literal is defined somewhere indented:
class MyClass { printYaml() { console.log(` yaml: is: supported: in a very ugly way `) } }
vs in the new world:
class MyClass { printYaml() { console.log(``` yaml: is: supported: nicely ```) } }
There are a variety of inconsistent ways to deal with this right now:
- use
dedent
or similar. This makes what could be pure data have a dependency and reduces its portability. You can no longer copy-paste snippets, you have to copy-paste snippets, install an npm package, maybe install the types too, import it and then use it. This solution also cannot be used in ecmascript-compatible data formats like json5 - do this automatically at runtime. This is what jest inline snapshots do - they ignore indents when comparing objects to snapshots. This works ok, but looks wrong if the call sites are moved around.
The above approaches also require teaching formatters like prettier to detect when they can safely adjust the indent to make code look better. e.g.
gql`...`where whitespace is insignificant; or
dedent`...`or
.toMatchInlineSnapshot(`...`)where it'll be "fixed" at runtime. This isn't easy to maintain, since the formatter needs to be tightly coupled to the code, and will never be able to fully understand the context.
With this proposal, formatters would be able to confidently sync template indentation with the code the literal is found in without worrying about the runtime behaviour of dedent, graphql-tag, jest, etc.
This could be implemented without any syntax changes, since it's already valid syntax:
var s = ``` abc ```
is equivalent to:
var s = (``)(` abc `)(``)
i.e. when run, this code will try to use the empty string
(``)as an es string tag, passing in
'\n abc\n'
, the return value of which is then used as another es string tag which receives the empty string. Obviously, none of that will currently work at runtime, because an empty string is not a function. But without any syntax/parser changes, strings could be overloaded as functions to allow this behaviour, with whatever cleverness is required internally to make it work as documented.
The alternative would be to make a breaking syntax change (in all likelihood, breaking no functional code), which would allow using backticks unescaped inside a triple-quoted literal. This would be very useful for things like js code examples within code.
Either approach should be easy enough to shim in preprocessors like typescript or babel for forwards-compatibility.
I'd be interested to read people's thoughts on this, and start a discussion about prior art, implementations in other languages, backwards-compatible runtime changes vs breaking syntax changes, etc.