This repository has been archived by the owner on Nov 28, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
stache.js
144 lines (134 loc) · 6.11 KB
/
stache.js
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
/**
* RequireJS loader plugin for CanJS 2.2 Stache templates.
*/
define([
'text'
], function(text) {
'use strict';
// File extension.
var extension = '.stache';
// Stores parsed result for a given moduleName.
var parsedMap = {};
// Store renderer function for a given moduleName.
var buildMap = {};
// Template of the compiled module, used for the optimizer build.
var buildTemplateSource = (
"define('{pluginName}!{moduleName}', " +
"{dependencies}, " +
"function(can) { " +
"var intermediate = {intermediate}; " +
"return can.stache('{canViewId}', intermediate); " +
"});" +
"\n");
// Clone of require() that won't try to load jQuery in node.
var buildRequire = require.config({
context: '__build',
baseUrl: require.s.contexts._.config.baseUrl,
paths: require.s.contexts._.config.paths,
map: {
'*': {
'can/util/jquery' : 'can/util/domless'
}
}
});
// Convert module name to module path. This should be a real path
// relative to the baseUrl.
var toModulePath = function(moduleName) {
return moduleName + extension;
};
// Convert a module path to a can.view ID, so that can.view(id) works.
var toId = function(modulePath) {
var pathParts = modulePath.toString().split(/\/|\./g);
var filteredParts = [];
for (var i = 0; i < pathParts.length; i += 1) {
if (pathParts[i]) {
filteredParts.push(pathParts[i]);
}
}
return filteredParts.join('_');
};
return {
normalize: function(moduleName, normalize) {
// Remove the file extension from the module name.
if (moduleName.slice(-extension.length) === extension) {
moduleName = moduleName.substr(0, moduleName.length - extension.length);
}
return normalize(moduleName);
},
load: function(moduleName, parentRequire, onload, config) {
// This path is always relative to the baseUrl.
var modulePath = toModulePath(moduleName);
// This path is the absolute path.
var fullPath = parentRequire.toUrl(modulePath);
// The can.view ID.
var canViewId = toId(modulePath);
// Have we already loaded this? Resolve with result of first load.
if (buildMap[moduleName]) {
onload(buildMap[moduleName]);
}
else {
// Use the text plugin to load the raw source.
text.load(fullPath, parentRequire, function(rawSource) {
// Are we executing inside the optimizer build?
if (config.isBuild) {
var getIntermediateAndImports = buildRequire('can/view/intermediate_and_imports');
var intermediateAndImports = getIntermediateAndImports(rawSource);
// Keep parsed results for the write() call.
parsedMap[moduleName] = {
imports: intermediateAndImports.imports,
intermediate: intermediateAndImports.intermediate
};
// Force the dependencies inside the template to become part of the build.
require(intermediateAndImports.imports);
// Don't need to resolve with anything.
onload();
}
else {
// ... else we're in the normal load process.
// We want to resolve with the template renderer,
// so we require the template compiler first.
parentRequire(['can/util/library', 'can/view/stache', 'can/view/intermediate_and_imports'], function(can, stache, getIntermediateAndImports) {
// Parse into intermediate form, and get any <can-import> imports.
var intermediateAndImports = getIntermediateAndImports(rawSource);
// Fetch imports first...
parentRequire(intermediateAndImports.imports, function() {
// Compile into a renderer, from the intermediate form.
var renderer = can.stache(canViewId, intermediateAndImports.intermediate);
// Cache the renderer.
buildMap[moduleName] = renderer;
// Resolve with the renderer.
onload(renderer);
});
});
}
}, config);
}
},
write: function(pluginName, moduleName, write, config) {
// This path is always relative to the baseUrl.
var modulePath = toModulePath(moduleName);
// The can.view ID.
var canViewId = toId(modulePath);
// Get the result we kept during load().
var intermediateAndImports = parsedMap[moduleName];
var dependencies = [
'can/util/library', 'can/view/stache'
];
intermediateAndImports.imports.forEach(function(dependency) {
dependencies.push(dependency);
});
// Write out the compiled module, which has the same value
// as the normal load process (returns a template renderer),
// but uses the intermediates generated after parsing. Also,
// any dependencies declared with <can-import> are loaded
// beforehand.
write.asModule(pluginName + '!' + moduleName,
buildTemplateSource
.replace('{canViewId}', canViewId)
.replace('{pluginName}', pluginName)
.replace('{moduleName}', moduleName)
.replace('{dependencies}', JSON.stringify(dependencies))
.replace('{intermediate}', JSON.stringify(intermediateAndImports.intermediate)));
}
};
});