-
Notifications
You must be signed in to change notification settings - Fork 0
/
mod.ts
54 lines (38 loc) · 1.63 KB
/
mod.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
const indentTag = (strings: TemplateStringsArray, ... expressions: any[]) => {
let parts: string[] = Array.from(strings);
// Drop first line feed
if ('\n' !== strings[0][0]) {
throw new Error('Expect first character to be a line feed');
}
parts[0] = parts[0].slice(1);
// Remove terminating indentation
parts[strings.length - 1] = parts[parts.length - 1].replace(/\n[ \t]*$/, '\n');
// Dedent using indent from first part
const indent = parts[0].match(/^\n*([ \t]*)/)![1];
const deindent = new RegExp(`(^|\n)${indent}`, 'g');
parts = parts.map((string) => string.replace(deindent, '$1'));
// Ensure expressions are strings
const values = expressions.map((expression) => String(expression));
// Treat expression
for (let i= 0; i < values.length; i++) {
const prev = parts[i];
const next = parts[i + 1];
const match = prev.match(/\n( *)$/);
// Only treat expressions that are preceded by only indentation and followed by a newline.
if (!match || !next.startsWith('\n')) {
continue;
}
const indentation = match[1];
// Fix previous and next parts
parts[i] = parts[i].slice(0, parts[i].length - indentation.length);
parts[i + 1] = parts[i + 1].slice(1);
// Fix value end of line if needed
if (!values[i].endsWith('\n')) {
values[i] = `${values[i]}\n`;
}
// Indent value
values[i] = values[i].replace(/(.*)\n/g, `${indentation}$1\n`);
}
return parts.flatMap((part, index) => [part, values[index]]).join('');
}
export default indentTag;