-
Notifications
You must be signed in to change notification settings - Fork 179
/
Copy pathhandlebars.adapter.ts
122 lines (107 loc) · 3.48 KB
/
handlebars.adapter.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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/** Dependencies **/
import * as fs from 'fs';
import * as path from 'path';
import * as handlebars from 'handlebars';
import { inline } from '@css-inline/css-inline';
import * as glob from 'glob';
import { get } from 'lodash';
import { HelperDeclareSpec } from 'handlebars';
/** Interfaces **/
import { MailerOptions } from '../interfaces/mailer-options.interface';
import { TemplateAdapter } from '../interfaces/template-adapter.interface';
import { TemplateAdapterConfig } from '../interfaces/template-adapter-config.interface';
export class HandlebarsAdapter implements TemplateAdapter {
private precompiledTemplates: {
[name: string]: handlebars.TemplateDelegate;
} = {};
private config: TemplateAdapterConfig = {
inlineCssOptions: {},
inlineCssEnabled: true,
};
constructor(helpers?: HelperDeclareSpec, config?: TemplateAdapterConfig) {
handlebars.registerHelper('concat', (...args) => {
args.pop();
return args.join('');
});
handlebars.registerHelper(helpers || {});
Object.assign(this.config, config);
}
public compile(mail: any, callback: any, mailerOptions: MailerOptions): void {
const precompile = (template: any, callback: any, options: any) => {
const templateBaseDir = get(options, 'dir', '');
const templateExt = path.extname(template) || '.hbs';
let templateName = path.basename(template, path.extname(template));
const templateDir = path.isAbsolute(template)
? path.dirname(template)
: path.join(templateBaseDir, path.dirname(template));
const templatePath = path.join(templateDir, templateName + templateExt);
templateName = path
.relative(templateBaseDir, templatePath)
.replace(templateExt, '');
if (!this.precompiledTemplates[templateName]) {
try {
const template = fs.readFileSync(templatePath, 'utf-8');
this.precompiledTemplates[templateName] = handlebars.compile(
template,
get(options, 'options', {}),
);
} catch (err) {
return callback(err);
}
}
return {
templateExt,
templateName,
templateDir,
templatePath,
};
};
const { templateName } = precompile(
mail.data.template,
callback,
mailerOptions.template,
);
const runtimeOptions = get(mailerOptions, 'options', {
partials: false,
data: {},
});
if (runtimeOptions.partials) {
const partialPath = path
.join(runtimeOptions.partials.dir, '**', '*.hbs')
.replace(/\\/g, '/');
const files = glob.sync(partialPath);
files.forEach((file) => {
const { templateName, templatePath } = precompile(
file,
() => {},
runtimeOptions.partials,
);
const templateDir = path.relative(
runtimeOptions.partials.dir,
path.dirname(templatePath),
);
handlebars.registerPartial(
path.join(templateDir, templateName),
fs.readFileSync(templatePath, 'utf-8'),
);
});
}
const rendered = this.precompiledTemplates[templateName](
mail.data.context,
{
...runtimeOptions,
partials: this.precompiledTemplates,
},
);
if (this.config.inlineCssEnabled) {
try {
mail.data.html = inline(rendered, this.config.inlineCssOptions);
} catch (e) {
callback(e);
}
} else {
mail.data.html = rendered;
}
return callback();
}
}