Skip to content

Instantly share code, notes, and snippets.

@zenparsing
Last active April 25, 2023 22:16
Show Gist options
  • Star 38 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save zenparsing/5dffde82d9acef19e43c to your computer and use it in GitHub Desktop.
Save zenparsing/5dffde82d9acef19e43c to your computer and use it in GitHub Desktop.
Dedenting Template Strings
function dedent(callSite, ...args) {
function format(str) {
let size = -1;
return str.replace(/\n(\s+)/g, (m, m1) => {
if (size < 0)
size = m1.replace(/\t/g, " ").length;
return "\n" + m1.slice(Math.min(m1.length, size));
});
}
if (typeof callSite === "string")
return format(callSite);
if (typeof callSite === "function")
return (...args) => format(callSite(...args));
let output = callSite
.slice(0, args.length + 1)
.map((text, i) => (i === 0 ? "" : args[i - 1]) + text)
.join("");
return format(output);
}
let output;
console.log("=== As a string function ===");
output = dedent(`
this
is
the ${ "end" }
my only
friend
the end
`);
console.log(output);
console.log("=== As a template tag ===");
output = dedent`
this
is
the ${ "end" }
my only
friend
the end
`;
console.log(output);
console.log("=== As a higher-order template tag ===");
output = dedent(String.raw)`
this
is
the ${ "end" }
my only
friend
the \end
`;
console.log(output);
@simevidas
Copy link

Could you explain the backslash in line 66 (the \end)?

@mathiasbynens
Copy link

@simevidas It’s there to demonstrate that String.raw still works as expected.

@jedwards1211
Copy link

Now we need to make a babel plugin to do the dedent at compile time...

@jedwards1211
Copy link

@rimiti
Copy link

rimiti commented Apr 25, 2019

@mathiasbynens Thanks !

@leonardochaia
Copy link

+1 for Jim Morrison

@RayDeanTech
Copy link

RayDeanTech commented Aug 20, 2021

This is a fantastic utility! Any recommendation on how to get a hard return (\n and maybe \r\n) between two sets of de-dented content?

I'm creating a string for an *.eml file, and it's VERY finicky. I must supply a \n before the html section (see screenshot).

Although my output technically works, it would be cool to eliminate the 4 spaces ahead of <html>. But, I admit, it's probably a bit pedantic.

What I tried: I attempted to separate the header and body, and then recombine them with a \n via a template literal string, but it didn't work... actually it would not respect that \n at all.

structuredEmail = `${header}\n${body}
//new line not in output  ----->>>> now that I think of it, it should probably be two: \n\n

image

==== UPDATE: A FEW MOMENTS LATER ====

Okay, I fixed it this way:

  const structuredEmail = dedent(`To:
    Subject: ${subject}
    X-Unsent: 1
    Content-Type: text/html
    \n<html>
    <body>
    <h2>Job Description</h2>
    ${JobDescription}
    <h2>Qualifications</h2>
    ${Qualifications}
    </body>
    </html>
  `);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment