@technomoron/mail-magic-client 1.0.30 → 1.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js DELETED
@@ -1,325 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- const fs_1 = __importDefault(require("fs"));
8
- const readline_1 = __importDefault(require("readline"));
9
- const commander_1 = require("commander");
10
- const cli_env_1 = require("./cli-env");
11
- const cli_helpers_1 = require("./cli-helpers");
12
- const cli_version_1 = require("./cli-version");
13
- const mail_magic_client_1 = __importDefault(require("./mail-magic-client"));
14
- const preprocess_1 = require("./preprocess");
15
- const program = new commander_1.Command();
16
- const envDefaults = (0, cli_env_1.loadCliEnv)();
17
- const defaultToken = (0, cli_env_1.resolveToken)(envDefaults);
18
- const apiDefault = envDefaults.api || 'http://localhost:3000';
19
- program.option('-a, --api <api>', 'Base API endpoint', apiDefault);
20
- if (defaultToken) {
21
- program.option('-t, --token <token>', 'Authentication token in the format "username:token"', defaultToken);
22
- }
23
- else {
24
- program.option('-t, --token <token>', 'Authentication token in the format "username:token"');
25
- }
26
- program
27
- .option('-f, --file <file>', 'Path to the file containing the template data (Nunjucks with MJML)')
28
- .option('-s, --sender <sender>', 'Sender email address')
29
- .option('-r, --rcpt <rcpt>', 'Recipient email addresses (comma-separated)')
30
- .option('-n, --name <name>', 'Template name')
31
- .option('-b, --subject <subject>', 'Email subject')
32
- .option('-l, --locale <locale>', 'Locale')
33
- .option('-d, --domain <domain>', 'Domain', envDefaults.domain)
34
- .option('-p, --part <true|false>', 'Part')
35
- .option('-v, --vars <vars>', 'Template parameters (JSON string)');
36
- const readStdin = async () => {
37
- if (process.stdin.isTTY) {
38
- return '';
39
- }
40
- return new Promise((resolve, reject) => {
41
- const rl = readline_1.default.createInterface({
42
- input: process.stdin,
43
- output: process.stdout,
44
- terminal: false
45
- });
46
- let data = '';
47
- rl.on('line', (line) => {
48
- data += line + '\n';
49
- });
50
- rl.on('close', () => {
51
- resolve(data.trim());
52
- });
53
- rl.on('error', (err) => {
54
- reject(err);
55
- });
56
- });
57
- };
58
- const getTemplateData = async () => {
59
- if (program.opts().file) {
60
- const filePath = program.opts().file;
61
- if (!fs_1.default.existsSync(filePath)) {
62
- throw new Error(`File not found: ${filePath}`);
63
- }
64
- return fs_1.default.readFileSync(filePath, 'utf-8');
65
- }
66
- else {
67
- return await readStdin();
68
- }
69
- };
70
- const isPlainObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
71
- const parseVarsOption = (input) => {
72
- if (!input) {
73
- return {};
74
- }
75
- let parsed;
76
- try {
77
- parsed = JSON.parse(input);
78
- }
79
- catch (error) {
80
- const message = error instanceof Error ? error.message : String(error);
81
- throw new Error(`Invalid JSON for --vars: ${message}`);
82
- }
83
- if (!isPlainObject(parsed)) {
84
- throw new Error('--vars must be a JSON object');
85
- }
86
- return parsed;
87
- };
88
- program
89
- .command('template')
90
- .description('Store a template on the server')
91
- .action(async () => {
92
- const client = new mail_magic_client_1.default(program.opts().api, program.opts().token);
93
- try {
94
- const template = await getTemplateData();
95
- const templateData = {
96
- template,
97
- sender: program.opts().sender,
98
- name: program.opts().name,
99
- subject: program.opts().subject,
100
- locale: program.opts().locale,
101
- domain: program.opts().domain,
102
- part: !!program.opts().part
103
- };
104
- await client.storeTemplate(templateData);
105
- console.log('Template updated');
106
- }
107
- catch (error) {
108
- if (error instanceof Error) {
109
- console.error('Error:', error.message);
110
- }
111
- else {
112
- console.error('An unknown error occurred.');
113
- }
114
- process.exit(1);
115
- }
116
- });
117
- program
118
- .command('send')
119
- .description('Send a template to recipients')
120
- .action(async () => {
121
- const client = new mail_magic_client_1.default(program.opts().api, program.opts().token);
122
- try {
123
- const vars = parseVarsOption(program.opts().vars);
124
- const templateData = {
125
- name: program.opts().name,
126
- rcpt: program.opts().rcpt,
127
- domain: program.opts().domain,
128
- locale: program.opts().locale,
129
- vars
130
- };
131
- await client.sendTemplate(templateData);
132
- console.log('Template sent');
133
- }
134
- catch (error) {
135
- if (error instanceof Error) {
136
- console.error('Error:', error.message);
137
- }
138
- else {
139
- console.error('An unknown error occurred.');
140
- }
141
- process.exit(1);
142
- }
143
- });
144
- program
145
- .command('version')
146
- .description('Show current client version')
147
- .action(async () => {
148
- console.log((0, cli_version_1.resolvePackageVersion)());
149
- });
150
- program
151
- .command('compile')
152
- .description('Compile templates by resolving inheritance and processing with FFE')
153
- .option('-i, --input <input>', 'Input directory', './templates')
154
- .option('-o, --output <output>', 'Output directory', './templates-dist')
155
- .option('-c, --css <css>', 'Path to Foundation for Emails CSS', './templates/foundation-emails.css')
156
- .option('-t, --template <template>', 'Process a specific template only')
157
- .action(async (cmdOptions) => {
158
- try {
159
- await (0, preprocess_1.do_the_template_thing)({
160
- src_dir: cmdOptions.input,
161
- dist_dir: cmdOptions.output,
162
- css_path: cmdOptions.css,
163
- tplname: cmdOptions.template // Pass undefined if not specified
164
- });
165
- }
166
- catch (error) {
167
- if (error instanceof Error) {
168
- console.error('Error:', error.message);
169
- }
170
- else {
171
- console.error('An unknown error occurred.');
172
- }
173
- process.exit(1);
174
- }
175
- });
176
- program
177
- .command('push')
178
- .description('Compile a template with partials and store it on the server')
179
- .option('-i, --input <input>', 'Input directory', './templates')
180
- .option('-c, --css <css>', 'Path to Foundation for Emails CSS', './templates/foundation-emails.css')
181
- .option('-t, --template <template>', 'Template path relative to input (without .njk)')
182
- .option('-n, --name <name>', 'Template name (defaults to template basename)')
183
- .option('-s, --sender <sender>', 'Sender email address')
184
- .option('-b, --subject <subject>', 'Email subject')
185
- .option('-l, --locale <locale>', 'Locale')
186
- .option('-d, --domain <domain>', 'Domain')
187
- .option('--dry-run', 'Show what would be uploaded without sending anything')
188
- .action(async (cmdOptions) => {
189
- try {
190
- const summary = await (0, cli_helpers_1.pushTemplate)({
191
- api: program.opts().api,
192
- token: program.opts().token,
193
- domain: cmdOptions.domain,
194
- template: cmdOptions.template,
195
- name: cmdOptions.name,
196
- locale: cmdOptions.locale,
197
- sender: cmdOptions.sender,
198
- subject: cmdOptions.subject,
199
- input: cmdOptions.input,
200
- css: cmdOptions.css,
201
- dryRun: !!cmdOptions.dryRun
202
- });
203
- if (cmdOptions.dryRun) {
204
- console.log(`Dry run - template: ${summary.domain} ${summary.locale || ''} ${summary.name}`);
205
- console.log(`Source: ${summary.filePath}`);
206
- }
207
- else {
208
- console.log('Template compiled and uploaded');
209
- }
210
- }
211
- catch (error) {
212
- if (error instanceof Error) {
213
- console.error('Error:', error.message);
214
- }
215
- else {
216
- console.error('An unknown error occurred.');
217
- }
218
- process.exit(1);
219
- }
220
- });
221
- program
222
- .command('push-dir')
223
- .description('Upload templates and assets from a config-style directory')
224
- .option('-i, --input <input>', 'Config directory (contains init-data.json)', './data')
225
- .option('-c, --css <css>', 'Path to Foundation for Emails CSS (optional)')
226
- .option('--dry-run', 'Show what would be uploaded without sending anything')
227
- .option('--skip-assets', 'Skip asset uploads')
228
- .option('--skip-tx', 'Skip transactional templates')
229
- .option('--skip-forms', 'Skip form templates')
230
- .option('-d, --domain <domain>', 'Domain to upload (overrides global)')
231
- .action(async (cmdOptions) => {
232
- try {
233
- const summary = await (0, cli_helpers_1.pushTemplateDir)({
234
- api: program.opts().api,
235
- token: program.opts().token,
236
- input: cmdOptions.input,
237
- domain: cmdOptions.domain || program.opts().domain,
238
- css: cmdOptions.css,
239
- includeAssets: !cmdOptions.skipAssets,
240
- includeTx: !cmdOptions.skipTx,
241
- includeForms: !cmdOptions.skipForms,
242
- dryRun: !!cmdOptions.dryRun
243
- });
244
- if (cmdOptions.dryRun) {
245
- console.log('Dry run - planned uploads:');
246
- for (const action of summary.actions) {
247
- if (action.kind === 'tx-template') {
248
- console.log(`tx-template: ${action.domain} ${action.locale || ''} ${action.template}`);
249
- }
250
- else if (action.kind === 'form-template') {
251
- console.log(`form-template: ${action.domain} ${action.locale || ''} ${action.template}`);
252
- }
253
- else if (action.kind === 'domain-assets') {
254
- const files = action.files?.join(', ') || '';
255
- console.log(`domain-assets: ${action.domain} ${action.path || '.'} ${files}`);
256
- }
257
- else if (action.kind === 'template-assets') {
258
- const files = action.files?.join(', ') || '';
259
- console.log(`template-assets: ${action.domain} ${action.locale || ''} ${action.template} ${action.path || '.'} ${files}`);
260
- }
261
- }
262
- console.log(`Summary: ${summary.templates} tx template(s), ${summary.forms} form template(s), ${summary.assetBatches} asset batch(es)`);
263
- }
264
- else {
265
- console.log('Templates and assets uploaded');
266
- }
267
- }
268
- catch (error) {
269
- if (error instanceof Error) {
270
- console.error('Error:', error.message);
271
- }
272
- else {
273
- console.error('An unknown error occurred.');
274
- }
275
- process.exit(1);
276
- }
277
- });
278
- program
279
- .command('assets')
280
- .description('Upload asset files to the server')
281
- .option('-f, --file <file...>', 'Asset file path(s)')
282
- .option('--template-type <type>', 'Template type (tx or form)')
283
- .option('--template <template>', 'Template name/idname')
284
- .option('--path <path>', 'Destination subdirectory under assets or template')
285
- .option('-l, --locale <locale>', 'Locale')
286
- .option('--dry-run', 'Show what would be uploaded without sending anything')
287
- .action(async (cmdOptions) => {
288
- const client = new mail_magic_client_1.default(program.opts().api, program.opts().token);
289
- try {
290
- const files = cmdOptions.file;
291
- if (!files || files.length === 0) {
292
- throw new Error('At least one --file is required');
293
- }
294
- if (cmdOptions.dryRun) {
295
- for (const file of files) {
296
- if (!fs_1.default.existsSync(file)) {
297
- throw new Error(`File not found: ${file}`);
298
- }
299
- }
300
- console.log('Dry run - assets:');
301
- console.log(`domain=${program.opts().domain} templateType=${cmdOptions.templateType || ''} template=${cmdOptions.template || ''} locale=${cmdOptions.locale || ''} path=${cmdOptions.path || ''}`);
302
- console.log(`files=${files.join(', ')}`);
303
- return;
304
- }
305
- await client.uploadAssets({
306
- domain: program.opts().domain,
307
- files,
308
- templateType: cmdOptions.templateType,
309
- template: cmdOptions.template,
310
- locale: cmdOptions.locale,
311
- path: cmdOptions.path
312
- });
313
- console.log('Assets uploaded');
314
- }
315
- catch (error) {
316
- if (error instanceof Error) {
317
- console.error('Error:', error.message);
318
- }
319
- else {
320
- console.error('An unknown error occurred.');
321
- }
322
- process.exit(1);
323
- }
324
- });
325
- program.parse(process.argv);
@@ -1,308 +0,0 @@
1
- "use strict";
2
- /*
3
- * Merge templates in source dir using nunjucks blocks and layouts.
4
- * Preserve flow control and variable expansion for later dynamic data.
5
- */
6
- var __importDefault = (this && this.__importDefault) || function (mod) {
7
- return (mod && mod.__esModule) ? mod : { "default": mod };
8
- };
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.do_the_template_thing = do_the_template_thing;
11
- exports.compileTemplate = compileTemplate;
12
- const node_fs_1 = __importDefault(require("node:fs"));
13
- const node_path_1 = __importDefault(require("node:path"));
14
- const cheerio_1 = require("cheerio");
15
- const juice_1 = __importDefault(require("juice"));
16
- const nunjucks_1 = __importDefault(require("nunjucks"));
17
- function createCompileCfg(options) {
18
- return {
19
- env: null,
20
- src_dir: options.src_dir ?? 'templates',
21
- dist_dir: options.dist_dir ?? 'templates-dist',
22
- css_path: options.css_path ?? node_path_1.default.join(process.cwd(), 'templates', 'foundation-emails.css'),
23
- css_content: null,
24
- inline_includes: options.inline_includes ?? true
25
- };
26
- }
27
- function resolvePathRoot(dir) {
28
- return node_path_1.default.isAbsolute(dir) ? dir : node_path_1.default.join(process.cwd(), dir);
29
- }
30
- function resolveCssPath(cssPath) {
31
- if (!cssPath) {
32
- return '';
33
- }
34
- return node_path_1.default.isAbsolute(cssPath) ? cssPath : node_path_1.default.join(process.cwd(), cssPath);
35
- }
36
- function inlineIncludes(content, baseDir, srcRoot, normalizedSrcRoot, stack) {
37
- const includeExp = /\{%\s*include\s+['"]([^'"]+)['"][^%]*%\}/g;
38
- return content.replace(includeExp, (_match, includePath) => {
39
- const cleaned = includePath.replace(/^\/+/, '');
40
- const candidates = [node_path_1.default.resolve(baseDir, cleaned), node_path_1.default.resolve(srcRoot, cleaned)];
41
- const found = candidates.find((candidate) => node_fs_1.default.existsSync(candidate));
42
- if (!found) {
43
- throw new Error(`Include not found: ${includePath}`);
44
- }
45
- const resolved = node_fs_1.default.realpathSync(found);
46
- if (!resolved.startsWith(normalizedSrcRoot)) {
47
- throw new Error(`Include path escapes template root: ${includePath}`);
48
- }
49
- if (!node_fs_1.default.statSync(resolved).isFile()) {
50
- throw new Error(`Include is not a file: ${includePath}`);
51
- }
52
- if (stack.has(resolved)) {
53
- throw new Error(`Circular include detected for ${includePath}`);
54
- }
55
- stack.add(resolved);
56
- const raw = node_fs_1.default.readFileSync(resolved, 'utf8');
57
- const inlined = inlineIncludes(raw, node_path_1.default.dirname(resolved), srcRoot, normalizedSrcRoot, stack);
58
- stack.delete(resolved);
59
- return inlined;
60
- });
61
- }
62
- class PreprocessExtension {
63
- constructor(cfg) {
64
- this.tags = ['process_layout'];
65
- this.cfg = cfg;
66
- }
67
- parse(parser, nodes) {
68
- const token = parser.nextToken();
69
- const args = parser.parseSignature(null, true);
70
- parser.advanceAfterBlockEnd(token.value);
71
- return new nodes.CallExtension(this, 'run', args);
72
- }
73
- run(_context, tplname) {
74
- const template = this.cfg.env.getTemplate(tplname);
75
- const src = template.tmplStr;
76
- const extmatch = src.match(/\{%\s*extends\s+['"]([^'"]+)['"]\s*%\}/);
77
- if (!extmatch)
78
- return src;
79
- const layoutName = extmatch[1];
80
- const layoutTemplate = this.cfg.env.getTemplate(layoutName);
81
- const layoutSrc = layoutTemplate.tmplStr;
82
- const blocks = {};
83
- const blockexp = /\{%\s*block\s+([a-zA-Z0-9_]+)\s*%\}([\s\S]*?)\{%\s*endblock\s*%\}/g;
84
- let match;
85
- while ((match = blockexp.exec(src)) !== null) {
86
- const bname = match[1];
87
- const bcontent = match[2];
88
- blocks[bname] = bcontent.trim();
89
- }
90
- let merged = layoutSrc;
91
- for (const [bname, bcontent] of Object.entries(blocks)) {
92
- const lbexpt = new RegExp(`\\{%\\s*block\\s+${bname}\\s*%\\}[\\s\\S]*?\\{%\\s*endblock\\s*%\\}`, 'g');
93
- merged = merged.replace(lbexpt, bcontent);
94
- }
95
- merged = merged.replace(/\{%\s*extends\s+['"][^'"]+['"]\s*%\}/, '');
96
- if (merged.match(/\{%\s*extends\s+['"]([^'"]+)['"]\s*%\}/)) {
97
- return this.run(_context, layoutName);
98
- }
99
- merged = merged.replace(/\{%\s*block\s+([a-zA-Z0-9_]+)\s*%\}\s*\{%\s*endblock\s*%\}/g, '');
100
- return merged;
101
- }
102
- }
103
- function process_template(cfg, tplname, writeOutput = true) {
104
- console.log(`Processing template: ${tplname}`);
105
- try {
106
- const srcRoot = resolvePathRoot(cfg.src_dir);
107
- const resolvedSrcRoot = node_fs_1.default.realpathSync(srcRoot);
108
- const normalizedSrcRoot = resolvedSrcRoot.endsWith(node_path_1.default.sep) ? resolvedSrcRoot : resolvedSrcRoot + node_path_1.default.sep;
109
- const templateFile = node_path_1.default.join(srcRoot, `${tplname}.njk`);
110
- // 1) Resolve template inheritance
111
- const mergedTemplate = cfg.env.renderString(`{% process_layout "${tplname}.njk" %}`, {});
112
- // 1.5) Inline partials/includes so the server doesn't need a loader
113
- const mergedWithPartials = cfg.inline_includes
114
- ? inlineIncludes(mergedTemplate, node_path_1.default.dirname(templateFile), srcRoot, normalizedSrcRoot, new Set())
115
- : mergedTemplate;
116
- // 2) Protect variables/flow
117
- const protectedTemplate = cfg.env.filters.protect_variables(mergedWithPartials);
118
- // 3) Light HTML transforms for email compatibility
119
- console.log('Processing HTML for email compatibility');
120
- let processedHtml = protectedTemplate;
121
- try {
122
- const $ = (0, cheerio_1.load)(protectedTemplate, {
123
- xmlMode: false
124
- // decodeEntities: false
125
- });
126
- // <container> -> <table>
127
- $('container').each((_index, element) => {
128
- const $container = $(element);
129
- const $table = $('<table/>').attr({
130
- align: 'center',
131
- class: $container.attr('class') || '',
132
- width: '100%',
133
- cellpadding: '0',
134
- cellspacing: '0',
135
- border: '0'
136
- });
137
- const $tbody = $('<tbody/>');
138
- $table.append($tbody);
139
- $tbody.append($container.contents());
140
- $container.replaceWith($table);
141
- });
142
- // <row> -> <tr>
143
- $('row').each((_index, element) => {
144
- const $row = $(element);
145
- const background = $row.attr('background') || '';
146
- const $tr = $('<tr/>').attr({ class: $row.attr('class') || '' });
147
- if (background)
148
- $tr.css('background', background);
149
- $tr.append($row.contents());
150
- $row.replaceWith($tr);
151
- });
152
- // <columns> -> <td>
153
- $('columns').each((_index, element) => {
154
- const $columns = $(element);
155
- const padding = $columns.attr('padding') || '0';
156
- const $td = $('<td/>').attr({
157
- class: $columns.attr('class') || '',
158
- style: `padding: ${padding};`
159
- });
160
- $td.append($columns.contents());
161
- $columns.replaceWith($td);
162
- });
163
- // <button> -> <a>
164
- $('button').each((_index, element) => {
165
- const $button = $(element);
166
- const href = $button.attr('href') || '#';
167
- const buttonClass = $button.attr('class') || '';
168
- const $a = $('<a/>').attr({
169
- href,
170
- class: buttonClass,
171
- style: $button.attr('style') ||
172
- 'display: inline-block; padding: 8px 16px; border-radius: 3px; text-decoration: none;'
173
- });
174
- $a.append($button.contents());
175
- $button.replaceWith($a);
176
- });
177
- processedHtml = $.html();
178
- console.log('HTML processing complete');
179
- }
180
- catch (htmlError) {
181
- console.error('HTML processing error:', htmlError);
182
- processedHtml = protectedTemplate;
183
- }
184
- // 4) Inline CSS
185
- let inlinedHtml;
186
- try {
187
- inlinedHtml = (0, juice_1.default)(processedHtml, {
188
- extraCss: cfg.css_content ?? undefined,
189
- removeStyleTags: false,
190
- preserveMediaQueries: true,
191
- preserveFontFaces: true
192
- });
193
- }
194
- catch (juiceError) {
195
- console.error('CSS inlining error:', juiceError);
196
- inlinedHtml = processedHtml;
197
- }
198
- // 5) Restore variables/flow
199
- const finalHtml = cfg.env.filters.restore_variables(inlinedHtml);
200
- // Write
201
- if (writeOutput) {
202
- const distRoot = resolvePathRoot(cfg.dist_dir);
203
- const outputPath = node_path_1.default.join(distRoot, `${tplname}.njk`);
204
- node_fs_1.default.mkdirSync(node_path_1.default.dirname(outputPath), { recursive: true });
205
- node_fs_1.default.writeFileSync(outputPath, finalHtml);
206
- }
207
- if (writeOutput) {
208
- console.log(`Created ${tplname}.njk`);
209
- }
210
- return finalHtml;
211
- }
212
- catch (error) {
213
- console.error(`Error processing ${tplname}:`, error);
214
- throw error;
215
- }
216
- }
217
- function get_all_files(dir, filelist = []) {
218
- const files = node_fs_1.default.readdirSync(dir);
219
- files.forEach((file) => {
220
- const file_path = node_path_1.default.join(dir, file);
221
- if (node_fs_1.default.statSync(file_path).isDirectory()) {
222
- get_all_files(file_path, filelist);
223
- }
224
- else {
225
- filelist.push(file_path);
226
- }
227
- });
228
- return filelist;
229
- }
230
- function find_templates(cfg) {
231
- const srcRoot = resolvePathRoot(cfg.src_dir);
232
- const all = get_all_files(srcRoot);
233
- return all
234
- .filter((file) => file.endsWith('.njk'))
235
- .filter((file) => {
236
- const basename = node_path_1.default.basename(file);
237
- const content = node_fs_1.default.readFileSync(file, 'utf8');
238
- return (!basename.startsWith('_') &&
239
- !basename.includes('layout') &&
240
- !basename.includes('part') &&
241
- content.includes('{% extends'));
242
- })
243
- .map((file) => {
244
- const name = node_path_1.default.relative(srcRoot, file);
245
- return name.substring(0, name.length - 4);
246
- });
247
- }
248
- async function process_all_templates(cfg) {
249
- const distRoot = resolvePathRoot(cfg.dist_dir);
250
- if (!node_fs_1.default.existsSync(distRoot)) {
251
- node_fs_1.default.mkdirSync(distRoot, { recursive: true });
252
- }
253
- const templates = find_templates(cfg);
254
- console.log(`Found ${templates.length} templates to process: ${templates.join(', ')}`);
255
- for (const template of templates) {
256
- try {
257
- process_template(cfg, template);
258
- }
259
- catch (error) {
260
- console.error(`Failed to process ${template}:`, error);
261
- }
262
- }
263
- console.log('All templates processed!');
264
- }
265
- function init_env(cfg) {
266
- const loader = new nunjucks_1.default.FileSystemLoader(resolvePathRoot(cfg.src_dir));
267
- cfg.env = new nunjucks_1.default.Environment(loader, { autoescape: false });
268
- if (!cfg.env)
269
- throw Error('Unable to init nunjucks environment');
270
- // Load CSS if present
271
- const cssPath = resolveCssPath(cfg.css_path);
272
- if (cssPath && node_fs_1.default.existsSync(cssPath)) {
273
- cfg.css_content = node_fs_1.default.readFileSync(cssPath, 'utf8');
274
- }
275
- else {
276
- cfg.css_content = null;
277
- }
278
- // Extension
279
- cfg.env.addExtension('PreprocessExtension', new PreprocessExtension(cfg));
280
- // Filters
281
- cfg.env.addFilter('protect_variables', function (content) {
282
- return content
283
- .replace(/(\{\{[\s\S]*?\}\})/g, (m) => `<!--VAR:${Buffer.from(m).toString('base64')}-->`)
284
- .replace(/(\{%(?!\s*block|\s*endblock|\s*extends)[\s\S]*?%\})/g, (m) => {
285
- return `<!--FLOW:${Buffer.from(m).toString('base64')}-->`;
286
- });
287
- });
288
- cfg.env.addFilter('restore_variables', function (content) {
289
- return content
290
- .replace(/<!--VAR:(.*?)-->/g, (_m, enc) => Buffer.from(enc, 'base64').toString('utf8'))
291
- .replace(/<!--FLOW:(.*?)-->/g, (_m, enc) => Buffer.from(enc, 'base64').toString('utf8'));
292
- });
293
- }
294
- async function do_the_template_thing(options = {}) {
295
- const cfg = createCompileCfg(options);
296
- init_env(cfg);
297
- if (options.tplname) {
298
- process_template(cfg, options.tplname);
299
- }
300
- else {
301
- await process_all_templates(cfg);
302
- }
303
- }
304
- async function compileTemplate(options) {
305
- const cfg = createCompileCfg(options);
306
- init_env(cfg);
307
- return process_template(cfg, options.tplname, false);
308
- }