mirror of
https://github.com/discourse/discourse.git
synced 2024-12-20 00:33:54 +08:00
175 lines
4.7 KiB
JavaScript
175 lines
4.7 KiB
JavaScript
"use strict";
|
|
|
|
const Filter = require("broccoli-filter");
|
|
const Handlebars = require("handlebars");
|
|
|
|
const RawHandlebars = Handlebars.create();
|
|
|
|
function buildPath(blk, args) {
|
|
let result = {
|
|
type: "PathExpression",
|
|
data: false,
|
|
depth: blk.path.depth,
|
|
loc: blk.path.loc,
|
|
};
|
|
|
|
// Server side precompile doesn't have jquery.extend
|
|
Object.keys(args).forEach(function (a) {
|
|
result[a] = args[a];
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
function replaceGet(ast) {
|
|
let visitor = new Handlebars.Visitor();
|
|
visitor.mutating = true;
|
|
|
|
visitor.MustacheStatement = function (mustache) {
|
|
if (!(mustache.params.length || mustache.hash)) {
|
|
mustache.params[0] = mustache.path;
|
|
mustache.path = buildPath(mustache, {
|
|
parts: ["get"],
|
|
original: "get",
|
|
strict: true,
|
|
falsy: true,
|
|
});
|
|
}
|
|
return Handlebars.Visitor.prototype.MustacheStatement.call(this, mustache);
|
|
};
|
|
|
|
// rewrite `each x as |y|` as each y in x`
|
|
// This allows us to use the same syntax in all templates
|
|
visitor.BlockStatement = function (block) {
|
|
if (block.path.original === "each" && block.params.length === 1) {
|
|
let paramName = block.program.blockParams[0];
|
|
block.params = [
|
|
buildPath(block, { original: paramName }),
|
|
{ type: "CommentStatement", value: "in" },
|
|
block.params[0],
|
|
];
|
|
delete block.program.blockParams;
|
|
}
|
|
|
|
return Handlebars.Visitor.prototype.BlockStatement.call(this, block);
|
|
};
|
|
|
|
visitor.accept(ast);
|
|
}
|
|
|
|
RawHandlebars.Compiler = function () {};
|
|
RawHandlebars.Compiler.prototype = Object.create(Handlebars.Compiler.prototype);
|
|
RawHandlebars.Compiler.prototype.compiler = RawHandlebars.Compiler;
|
|
|
|
RawHandlebars.JavaScriptCompiler = function () {};
|
|
|
|
RawHandlebars.JavaScriptCompiler.prototype = Object.create(
|
|
Handlebars.JavaScriptCompiler.prototype
|
|
);
|
|
RawHandlebars.JavaScriptCompiler.prototype.compiler =
|
|
RawHandlebars.JavaScriptCompiler;
|
|
RawHandlebars.JavaScriptCompiler.prototype.namespace = "RawHandlebars";
|
|
|
|
RawHandlebars.precompile = function (value, asObject) {
|
|
let ast = Handlebars.parse(value);
|
|
replaceGet(ast);
|
|
|
|
let options = {
|
|
knownHelpers: {
|
|
get: true,
|
|
},
|
|
data: true,
|
|
stringParams: true,
|
|
};
|
|
|
|
asObject = asObject === undefined ? true : asObject;
|
|
|
|
let environment = new RawHandlebars.Compiler().compile(ast, options);
|
|
return new RawHandlebars.JavaScriptCompiler().compile(
|
|
environment,
|
|
options,
|
|
undefined,
|
|
asObject
|
|
);
|
|
};
|
|
|
|
RawHandlebars.compile = function (string) {
|
|
let ast = Handlebars.parse(string);
|
|
replaceGet(ast);
|
|
|
|
// this forces us to rewrite helpers
|
|
let options = { data: true, stringParams: true };
|
|
let environment = new RawHandlebars.Compiler().compile(ast, options);
|
|
let templateSpec = new RawHandlebars.JavaScriptCompiler().compile(
|
|
environment,
|
|
options,
|
|
undefined,
|
|
true
|
|
);
|
|
|
|
let t = RawHandlebars.template(templateSpec);
|
|
t.isMethod = false;
|
|
|
|
return t;
|
|
};
|
|
function TemplateCompiler(inputTree, options) {
|
|
if (!(this instanceof TemplateCompiler)) {
|
|
return new TemplateCompiler(inputTree, options);
|
|
}
|
|
|
|
Filter.call(this, inputTree, options); // this._super()
|
|
|
|
this.options = options || {};
|
|
this.inputTree = inputTree;
|
|
}
|
|
|
|
TemplateCompiler.prototype = Object.create(Filter.prototype);
|
|
TemplateCompiler.prototype.constructor = TemplateCompiler;
|
|
TemplateCompiler.prototype.extensions = ["hbr"];
|
|
TemplateCompiler.prototype.targetExtension = "js";
|
|
|
|
TemplateCompiler.prototype.registerPlugins = function registerPlugins() {};
|
|
|
|
TemplateCompiler.prototype.initializeFeatures =
|
|
function initializeFeatures() {};
|
|
|
|
TemplateCompiler.prototype.processString = function (string, relativePath) {
|
|
let filename;
|
|
|
|
const pluginName = relativePath.match(/^discourse\/plugins\/([^\/]+)\//)?.[1];
|
|
|
|
if (pluginName) {
|
|
filename = relativePath
|
|
.replace(`discourse/plugins/${pluginName}/`, "")
|
|
.replace(/^(discourse\/)?raw-templates\//, "javascripts/");
|
|
} else {
|
|
filename = relativePath.replace(/^raw-templates\//, "");
|
|
}
|
|
|
|
filename = filename.replace(/\.hbr$/, "");
|
|
const hasModernReplacement = string.includes(
|
|
"{{!-- has-modern-replacement --}}"
|
|
);
|
|
|
|
return `
|
|
import { template as compiler } from "discourse-common/lib/raw-handlebars";
|
|
import { addRawTemplate } from "discourse-common/lib/raw-templates";
|
|
|
|
let template = compiler(${this.precompile(string, false)});
|
|
|
|
addRawTemplate("${filename}", template, {
|
|
core: ${!pluginName},
|
|
pluginName: ${JSON.stringify(pluginName)},
|
|
hasModernReplacement: ${hasModernReplacement},
|
|
});
|
|
|
|
export default template;
|
|
`;
|
|
};
|
|
|
|
TemplateCompiler.prototype.precompile = function (value, asObject) {
|
|
return RawHandlebars.precompile(value, asObject);
|
|
};
|
|
|
|
module.exports = TemplateCompiler;
|