Commit 1c638bd1 authored by Alejandro Celaya's avatar Alejandro Celaya Committed by Alejandro Celaya

Convert trimAndDedent in a tag function

parent 7db92f0c
...@@ -2,10 +2,10 @@ import { trimAndDedent } from '../trim-and-dedent'; ...@@ -2,10 +2,10 @@ import { trimAndDedent } from '../trim-and-dedent';
describe('trimAndDedent', () => { describe('trimAndDedent', () => {
[ [
['Foo', 'Foo'], [() => trimAndDedent`Foo`, 'Foo'],
[' Foo', 'Foo'], [() => trimAndDedent` Foo`, 'Foo'],
[ [
`First line () => trimAndDedent`First line
Second line Second line
Third line`, Third line`,
`First line `First line
...@@ -13,7 +13,7 @@ describe('trimAndDedent', () => { ...@@ -13,7 +13,7 @@ describe('trimAndDedent', () => {
Third line`, Third line`,
], ],
[ [
` () => trimAndDedent`
Hello, Jane! Hello, Jane!
Indented line Indented line
...@@ -24,10 +24,38 @@ describe('trimAndDedent', () => { ...@@ -24,10 +24,38 @@ describe('trimAndDedent', () => {
Indented line Indented line
Goodbye, John!`, Goodbye, John!`,
], ],
].forEach(([str, expectedResult]) => { [
() => {
const firstVar = ` very indented`;
const secondVar = `
multiple
lines
with no indentation
`;
return trimAndDedent`
Hello, Jane!
${firstVar}
Indented line
Goodbye, John!
${secondVar}
`;
},
`Hello, Jane!
very indented
Indented line
Goodbye, John!
multiple
lines
with no indentation
`,
],
].forEach(([getResult, expectedResult]) => {
it('normalizes strings with multiple lines', () => { it('normalizes strings with multiple lines', () => {
const result = trimAndDedent(str); assert.equal(getResult(), expectedResult);
assert.equal(result, expectedResult);
}); });
}); });
}); });
function trimLeadingEmptyLines(str: string): string {
return str.replace(/^\s*\n/g, '');
}
function trimTrailingEmptyLines(str: string): string {
return str.replace(/\n\s*$/g, '');
}
/** /**
* Remove leading and trailing empty lines from a string. * Remove specified indentation from each line of a string.
*/ */
function trimEmptyLines(str: string): string { function dedentStr(str: string, indent: number) {
return str.replace(/^\s*\n|\n\s*$/g, ''); const indentRegexp = new RegExp(`^ {${indent}}`, 'gm');
return str.replace(indentRegexp, '');
} }
/** /**
* Remove common indentation from each line of a string. * Remove common indentation from each line of every string, then interpolate
* params verbatim.
*/ */
function dedent(str: string) { function dedent(strings: string[], ...params: any[]) {
// Match the smallest indentation // Match the smallest indentation among all strings
const match = str.match(/^[ \t]*(?=\S)/gm); const indents = strings
const indent = match && Math.min(...match.map(el => el.length)); .map(str => {
const match = str.match(/^[ \t]*(?=\S)/gm);
if (indent) { return match ? Math.min(...match.map(el => el.length)) : -1;
const regexp = new RegExp(`^ {${indent}}`, 'gm'); })
return str.replace(regexp, ''); // Exclude lines where indentation could not be matched
.filter(num => num > -1);
const smallestIndent = indents.length > 0 ? Math.min(...indents) : 0;
let result = '';
for (const [i, param] of params.entries()) {
result += dedentStr(strings[i], smallestIndent);
result += param;
} }
return str; return result + dedentStr(strings[strings.length - 1], smallestIndent);
} }
/** /**
...@@ -35,21 +52,45 @@ function dedent(str: string) { ...@@ -35,21 +52,45 @@ function dedent(str: string) {
* if (arg === 3) { * if (arg === 3) {
* console.log(`First line * console.log(`First line
* Second line * Second line
* Third line`); * ${var}
* Fourth line`);
* } * }
* } * }
* *
* to this: * to this:
* function foo(arg) { * function foo(arg) {
* if (arg === 3) { * if (arg === 3) {
* console.log(trimAndDedent(` * console.log(trimAndDedent`
* First line * First line
* Second line * Second line
* Third line * ${var}
* `)); * Fourth line
* `);
* } * }
* } * }
*/ */
export function trimAndDedent(str: string): string { export function trimAndDedent(
return dedent(trimEmptyLines(str)); strings: TemplateStringsArray,
...params: any[]
): string {
if (strings.length < 2) {
// Trim leading and trailing empty lines from first (and only) string
const trimmedLines = [
trimLeadingEmptyLines(trimTrailingEmptyLines(strings[0])),
];
return dedent(trimmedLines, ...params);
}
const firstString = strings[0];
const lastString = strings[strings.length - 1];
const middle = strings.slice(1, strings.length - 1);
// Trim empty leading lines from first string, and empty trailing lines from last one
const trimmedLines = [
trimLeadingEmptyLines(firstString),
...middle,
trimTrailingEmptyLines(lastString),
];
return dedent(trimmedLines, ...params);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment