UNPKG

oj-loader

Version:

Load OJ files into your WebPack bundle! Write your app like you haven't done before.

157 lines (135 loc) 4.8 kB
var juicy = require("ohsojuicy"); var lu = require("loader-utils"); var path = require("path"); var merge = require("merge"); // Copied and modified from ojc/bin/ojc function print_error(err) { function toString(e) { var result = ""; var file = e.file || e.filename; var line = e.line || e.lineNumber; var column = e.column || e.columnNumber || e.col; var reason = e.reason || e.description; if (file) result += file; if (line) result += ":" + line; if (column) result += ":" + column; if (reason) result += " " + reason; return result; } var strings; if (typeof err == "array") { strings = err.map(function(e) { return toString(e) }); } else { strings = [ toString(err) ]; } this.emitError(strings.join("\n")); } // Compiler module.exports = function OJ(source,map) { // OJ is cool like this. this.cacheable(true); var options = lu.parseQuery(this.query); // Compilation-specific caching and state keeping if(typeof this._compilation.ojc == "undefined") { this._compilation.ojc = { cache: {}, state: {} }; // This is a new compilation, so also add the middlewares. if(typeof this.options.oj == "object") { var ojo = this.options.oj; var keys = ["pre","post"]; for(var n in keys) { var k = keys[n]; if(typeof ojo[k] != "undefined") { for(var i in ojo[k]) { juicy.use(k+"-compile", ojo[k][i]); } } } } } var ojcData = this._compilation.ojc; // Write the statement to obtain the OJ runtime. // Note: Statement starts with !! to prevent unwanted side effects. var rtPath = this.options.oj.runtime || options.runtime || require.resolve("ojc/src/runtime"); var header = [ // Import the runtime "var oj = require('!!"+rtPath+"')", ].join("\n"); // We must be able to be sync. var cb = this.async(); if(!cb) { throw new Error([ "The OJ loader must run in async manners.", "Check your config/invocation." ].join(" ")); } if(typeof ojcData.cache[this.resourcePath] != "undefined") { // In order to avoid re-complication, return the cached object. var out = ojcData.cache[this.resourcePath]; cb(null, out.code, out.map); } else { // The query should be - almost! - the OJ options // this might be present so use it. if(typeof this.options.oj == "object" && typeof this.options.oj.options == "object") { options = merge(options, this.options.oj.options); } // Compiler state. Use previous one if possible // `this` keeps changing, so I need another way... options.state = ojcData.state; // Source map and file var rawFile = this.resourcePath.replace(this.options.context, ""); if(rawFile.charAt(0)) rawFile = rawFile.substr(1); options.files = [{ path: rawFile, contents: source }]; if(typeof options.preprocessor == "undefined") { options.preprocessor = {}; } options.preprocessor.onInclude = function(file) { this.addDependency(file); }.bind(this); // SourceMap? if(this.sourceMap) { options["source-map-file"]=true; options["source-map-root"]=this.options.context; } // Mimimize? if(this.minimize) { options.squeeze = true; } // Compiler options [ "warn-unused-ivars", "warn-unknown-ivars", "warn-unknown-selectors", "warn-this-in-methods" ].forEach(function(k,v){ options[v] = options[v] || true; }); // Do it. var _this = this; juicy.compile(options, function(err, result){ if(err) { print_error.call(_this, err); cb(new Error("Compilation failed!")); } else { for(var i in result.warnings) { var warning = result.warnings[i]; _this.emitWarning(warning); } ojcData.state = result.state; ojcData.cache[_this.resourcePath] = { code: header+result.code, map: result.map } cb(err, header+result.code, result.map); } }); // Backwards assignment this._compilation.ojc = ojcData; } }; module.exports.juicy = juicy;