зеркало из https://github.com/mozilla/commonplace.git
129 строки
4.1 KiB
JavaScript
129 строки
4.1 KiB
JavaScript
function search(tree, typename, callback) {
|
|
if (!tree || !tree.typename) return;
|
|
if (tree.typename === typename) {
|
|
callback(tree);
|
|
}
|
|
if (!tree.fields) return;
|
|
for (var i = 0, field; field = tree.fields[i++];) {
|
|
if (!tree[field]) continue;
|
|
if (tree[field].length) { // It's an array
|
|
for (var j = 0; j < tree[field].length; j++) {
|
|
search(tree[field][j], typename, callback);
|
|
}
|
|
} else if (typeof tree[field] === 'object') {
|
|
search(tree[field], typename, callback);
|
|
}
|
|
}
|
|
}
|
|
|
|
function safeRemoveWhitespace(value) {
|
|
// Replaces whitespace followed by a `<` with null.
|
|
// ` \n <foo>` -> `<foo>`
|
|
value = value.replace(/^\s+(?=<)/im, '');
|
|
// Replaces whitespace followed by anything else with a space.
|
|
// ` data-hello="` -> ` data-hello="`
|
|
value = value.replace(/^\s+(?=\w)/im, ' ');
|
|
|
|
// Is there work to be done at the end of the string?
|
|
if (value !== value.trimRight()) {
|
|
value = value.trimRight();
|
|
// If the last non-whitespace character is not a `>`, add a space.
|
|
if (value.substr(-1) !== '>') {
|
|
value += ' ';
|
|
}
|
|
}
|
|
// Strip interim whitespace
|
|
// `<li>\n <a class="` -> `<li>\n<a class="`
|
|
value = value.replace(/(\S\n)\s+(\S)/img, '$1$2');
|
|
return value;
|
|
}
|
|
|
|
function stripWhitespace(tree) {
|
|
search(tree, 'Output', function(output) {
|
|
if (!output.children.length) return;
|
|
var new_children = output.children;
|
|
for (var i = 0; i < output.children.length; i++) {
|
|
var child = output.children[i];
|
|
if (child.typename !== 'TemplateData' ||
|
|
typeof child.value !== 'string') continue;
|
|
if (!child.value.trim()) {
|
|
// Whitespace-only nodes should only generate a single space.
|
|
child.value = ' ';
|
|
} else {
|
|
child.value = safeRemoveWhitespace(child.value);
|
|
}
|
|
}
|
|
output.children = new_children;
|
|
});
|
|
return tree;
|
|
}
|
|
|
|
exports.helpers = [
|
|
'_',
|
|
'_plural',
|
|
'url',
|
|
'api',
|
|
'apiParams',
|
|
'media'
|
|
];
|
|
|
|
exports.optimize = function(tree) {
|
|
stripWhitespace(tree);
|
|
return tree;
|
|
};
|
|
|
|
exports.monkeypatch = function(compiler) {
|
|
/*
|
|
Monkeypatch the symbol compiler to not produce a ton of crap for true and false.
|
|
*/
|
|
compiler.origCompileSymbol = compiler.compileSymbol;
|
|
compiler.compileSymbol = function(node, frame) {
|
|
if (node.value === 'True') {
|
|
return this.compileLiteral({value: true});
|
|
}
|
|
if (node.value === 'False') {
|
|
return this.compileLiteral({value: false});
|
|
}
|
|
return this.origCompileSymbol(node, frame);
|
|
};
|
|
|
|
function compileTranslationMethod(node, frame) {
|
|
this.emit('context.lookup("' + node.name.value + '")');
|
|
this._compileAggregate(node.args, frame, '(', ')');
|
|
}
|
|
|
|
/*
|
|
Monkeypatch the output compiler to not produce a ton of crap for translations.
|
|
*/
|
|
compiler.origCompileOutput = compiler.compileOutput;
|
|
compiler.compileOutput = function(node, frame) {
|
|
if (node.children.length === 1) {
|
|
var child = node.children[0];
|
|
if (child.typename === 'FunCall' &&
|
|
child.name.typename === 'Symbol' &&
|
|
exports.helpers.indexOf(child.name.value) !== -1) {
|
|
this.emit(this.buffer + ' += ');
|
|
compileTranslationMethod.call(this, child, frame);
|
|
this.emit(';\n');
|
|
return;
|
|
}
|
|
}
|
|
return this.origCompileOutput(node, frame);
|
|
};
|
|
|
|
/*
|
|
Monkeypatch the function call compiler:
|
|
- to not produce debug output (big and un-gzippable)
|
|
- to not do function wrap checks (slow and big)
|
|
*/
|
|
compiler.compileFunCall = function(node, frame) {
|
|
if (node.name.value &&
|
|
(node.name.value === '_' || node.name.value === '_plural')) {
|
|
compileTranslationMethod.call(this, node, frame);
|
|
return;
|
|
}
|
|
this._compileExpression(node.name, frame);
|
|
this._compileAggregate(node.args, frame, '(', ')');
|
|
};
|
|
};
|