This repository was archived by the owner on Dec 10, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathengine_underscore.js
More file actions
206 lines (174 loc) · 6.05 KB
/
engine_underscore.js
File metadata and controls
206 lines (174 loc) · 6.05 KB
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
"use strict";
/*
* underscore pattern engine for patternlab-node - v0.15.1 - 2015
*
* Geoffrey Pursell, Brian Muenzenmeyer, and the web community.
* Licensed under the MIT license.
*
* Many thanks to Brad Frost and Dave Olsen for inspiration, encouragement, and advice.
*
*/
/*
* ENGINE SUPPORT LEVEL:
*
* Basic. We can't call partials from inside underscore templates yet, but we
* can render templates with backing JSON.
*
*/
const fs = require('fs-extra');
const path = require('path');
var _ = require('underscore');
var partialRegistry = {};
var errorStyling = `
<style>
.plError {
background: linear-gradient(to bottom, #f1f1f1 0%,#ffffff 60%);
color: #444;
padding: 30px;
}
.plError h1 {
font-size: 16pt;
color: #733;
background: #fcfcfc;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
padding: 17px 30px;
margin: -30px -30px 0 -30px;
}
.plError dt { font-weight: bold; }
</style>
`;
// extend underscore with partial-ing methods and other necessary tooling
// HANDLESCORE! UNDERBARS!
function addParentContext(data, currentContext) {
return Object.assign({}, currentContext, data);
}
_.mixin({
renderNamedPartial: function (partialKey, data, currentContext) {
var compiledPartial = partialRegistry[partialKey];
if (typeof compiledPartial !== 'function') { throw `Pattern ${partialKey} not found.`; }
return _.renderPartial(compiledPartial, data, currentContext);
},
renderPartial: function (compiledPartial, dataIn, currentContext) {
var data = dataIn || {};
if (dataIn && currentContext &&
dataIn instanceof Object && currentContext instanceof Object) {
data = addParentContext(data, currentContext);
}
return compiledPartial(data);
},
/* eslint-disable no-eval, no-unused-vars */
getPath: function (pathString, currentContext, debug) {
try {
var result = eval('currentContext.' + pathString);
if (debug) {
console.log("getPath result = ", result);
}
return result;
} catch (e) {
return null;
}
}
});
var engine_underscore = {
engine: _,
engineName: 'underscore',
engineFileExtension: ['.html', '.underscore'],
// partial expansion is only necessary for Mustache templates that have
// style modifiers or pattern parameters (I think)
expandPartials: false,
// regexes, stored here so they're only compiled once
findPartialsRE: /<%=\s*_\.renderNamedPartial[ \t]*\(\s*("(?:[^"].*?)"|'(?:[^'].*?)').*?%>/g, // TODO
findListItemsRE: /({{#( )?)(list(I|i)tems.)(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)( )?}}/g,
// render it
renderPattern: function renderPattern(pattern, data, partials) {
var renderedHTML;
var compiled;
try {
compiled = partialRegistry[pattern.patternPartial];
} catch (e) {
console.log(`Error looking up underscore template ${pattern.patternName}:`, pattern.extendedTemplate, e);
}
// This try-catch is necessary because references to undefined variables
// in underscore templates are eval()ed directly as javascript, and as
// such will throw very real exceptions that will shatter the whole build
// process if we don't handle them.
try {
renderedHTML = compiled(_.extend(data || {}, {
_allData: data,
_partials: partials
}));
} catch (e) {
var errorMessage = `Error rendering underscore pattern "${pattern.patternName}" (${pattern.relPath}): [${e.toString()}]`;
console.log(errorMessage);
renderedHTML = `${errorStyling} <div class="plError">
<h1>Error rendering underscore pattern "${pattern.patternName}"</h1>
<dl>
<dt>Message</dt><dd>${e.toString()}</dd>
<dt>Partial name</dt><dd>${pattern.patternName}</dd>
<dt>Template path</dt><dd>${pattern.relPath}</dd>
</dl>
</div>
`;
}
return renderedHTML;
},
registerPartial: function (pattern) {
var compiled;
try {
var templateString = pattern.extendedTemplate || pattern.template;
compiled = _.template(templateString);
} catch (e) {
console.log(`Error compiling underscore template ${pattern.patternName}:`, pattern.extendedTemplate, e);
}
partialRegistry[pattern.patternPartial] = compiled;
},
// find and return any {{> template-name }} within pattern
findPartials: function findPartials(pattern) {
var matches = pattern.template.match(this.findPartialsRE);
return matches;
},
findPartialsWithStyleModifiers: function () {
return [];
},
// returns any patterns that match {{> value(foo:"bar") }} or {{>
// value:mod(foo:"bar") }} within the pattern
findPartialsWithPatternParameters: function () {
return [];
},
findListItems: function (pattern) {
var matches = pattern.template.match(this.findListItemsRE);
return matches;
},
// given a pattern, and a partial string, tease out the "pattern key" and
// return it.
findPartial: function (partialString) {
var edgeQuotesMatcher = /^["']|["']$/g;
var partialIDWithQuotes = partialString.replace(this.findPartialsRE, '$1');
var partialID = partialIDWithQuotes.replace(edgeQuotesMatcher, '');
return partialID;
},
spawnFile: function (config, fileName) {
const paths = config.paths;
const metaFilePath = path.resolve(paths.source.meta, fileName);
try {
fs.statSync(metaFilePath);
} catch (err) {
//not a file, so spawn it from the included file
const localMetaFilePath = path.resolve(__dirname, '_meta/', fileName);
const metaFileContent = fs.readFileSync(path.resolve(__dirname, '..', '_meta/', fileName), 'utf8');
fs.outputFileSync(metaFilePath, metaFileContent);
}
},
/**
* Checks to see if the _meta directory has engine-specific head and foot files,
* spawning them if not found.
*
* @param {object} config - the global config object from core, since we won't
* assume it's already present
*/
spawnMeta: function (config) {
this.spawnFile(config, '_00-head.html');
this.spawnFile(config, '_01-foot.html');
}
};
module.exports = engine_underscore;