| 'use strict'; |
| |
| var path = require('path'); |
| var fs = require('fs'); |
| var md5 = require('md5'); |
| var loaderUtils = require('loader-utils'); |
| var blocker = require('weex-transformer/lib/blocker'); |
| |
| var pkg = require('./package.json'); |
| var transformerVersion = pkg.dependencies['weex-transformer'].match(/\d+(?:\.\d+){0,2}/)[0]; |
| |
| var templater; |
| var styler; |
| var scripter; |
| |
| var MODULE_EXPORTS_REG = /module\.exports/g; |
| var REQUIRE_REG = /require\((["'])(\@weex\-module\/[^\)\1]+)\1\)/g; |
| |
| function parseScript(loader, params, source, config, data) { |
| if (!scripter) { |
| return Promise.reject('please use a script parser. ex. weex-scripter'); |
| } |
| |
| var target = scripter.fix(source); |
| var name = params.resourceQuery.name || |
| path.basename(params.resourcePath).replace(/\..*$/, ''); |
| |
| if (params.resourceQuery.entry === true) { |
| name = md5(source); |
| } |
| |
| target = target.replace(MODULE_EXPORTS_REG, '__weex_module__.exports') |
| .replace(REQUIRE_REG, '__weex_require__($1$2$1)'); |
| |
| target = ';__weex_define__("@weex-component/' + name + '", [], ' + |
| 'function(__weex_require__, __weex_exports__, __weex_module__)' + |
| '{\n' + target + '\n})'; |
| |
| if (params.resourceQuery.entry === true) { |
| target += '\n;__weex_bootstrap__("@weex-component/' + name + '", ' + |
| String(config) + ', ' + |
| String(data) + ')'; |
| } |
| |
| return Promise.resolve(target); |
| } |
| |
| function logWarning(loader, log) { |
| if (log && log instanceof Array) { |
| log.forEach(function(l) { |
| loader.emitWarning(l.reason + '\t@' + l.line + ':' + l.column) |
| }); |
| } |
| } |
| |
| function parseStyle(loader, params, source) { |
| return new Promise(function(resolve, reject) { |
| if (!styler) { |
| return reject('please use a style parser. ex. weex-styler'); |
| } |
| |
| styler.parse(source, function(err, obj) { |
| if (err) { |
| reject(err); |
| } else { |
| logWarning(loader, obj.log); |
| var target = JSON.stringify(obj.jsonStyle, null, ' '); |
| resolve(target); |
| } |
| }); |
| }); |
| } |
| |
| var FUNC_START = '#####FUN_S#####'; |
| var FUNC_START_REG = new RegExp('["\']' + FUNC_START, 'g'); |
| var FUNC_END = '#####FUN_E#####'; |
| var FUNC_END_REG = new RegExp(FUNC_END + '["\']', 'g'); |
| function stringifyFunction(key, value) { |
| if (typeof value === 'function') { |
| return FUNC_START + value.toString() + '#####FUN_E#####'; |
| } |
| return value; |
| } |
| |
| function parseTemplate(loader, params, source, deps) { |
| return new Promise(function(resolve, reject) { |
| if (!templater) { |
| return reject('please use a template parser. ex. weex-styler'); |
| } |
| |
| templater.parse(source, function(err, obj) { |
| if (err) { |
| reject(err); |
| } else { |
| logWarning(loader, obj.log); |
| |
| if (deps && obj.deps) { |
| var context = path.dirname(params.resourcePath); |
| obj.deps.map(function(dep) { |
| var filename = './' + dep + '.we'; |
| var filepath = path.resolve(context, filename); |
| if (fs.existsSync(filepath)) { |
| return filepath; |
| } |
| }).forEach(function(dep) { |
| if (dep) { |
| deps.push(dep); |
| } |
| }); |
| } |
| |
| var target = JSON.stringify(obj.jsonTemplate, stringifyFunction, ' '); |
| target = target.replace(FUNC_START_REG, '') |
| .replace(FUNC_END_REG, ''); |
| |
| resolve(target); |
| } |
| }); |
| }); |
| } |
| |
| function parseWeexFile(loader, params, source) { |
| var results; |
| var deps = []; |
| |
| return new Promise(function(resolve, reject) { |
| blocker.format(source, function(err, ret) { |
| if (err) { |
| reject(err); |
| } else { |
| results = ret; |
| resolve(); |
| } |
| }); |
| }).then(function() { |
| var promises = [Promise.resolve(), Promise.resolve()]; |
| var content; |
| |
| if (results.template) { |
| content = results.template.content; |
| promises[0] = parseTemplate(loader, params, content, deps); |
| } |
| if (results.styles) { |
| content = results.styles.reduce(function(pre, cur) { |
| return pre + '\n' + cur.content; |
| }, ''); |
| promises[1] = parseStyle(loader, params, content); |
| } |
| |
| return Promise.all(promises); |
| }).then(function(ret) { |
| var template = ret[0]; |
| var style = ret[1]; |
| |
| var content = ''; |
| var config = {}; |
| var data; |
| |
| if (results.scripts) { |
| content += results.scripts.reduce(function(pre, cur) { |
| return pre + '\n;' + cur.content; |
| }, ''); |
| } |
| |
| var requireContent = ''; |
| if (deps.length) { |
| requireContent += deps.map(function(dep) { |
| if (!content.match(new RegExp('require\\(["\']./' + path.basename(dep) + '["\']\\)', 'g'))) { |
| return 'require("' + dep + '");\n'; |
| } else { |
| return ''; |
| } |
| }); |
| |
| content = requireContent + '\n' + content; |
| } |
| |
| if (template) { |
| content += '\n;module.exports.template=' + template; |
| } |
| |
| if (style) { |
| content += '\n;module.exports.style=' + style; |
| } |
| |
| if (results.config) { |
| config = JSON.parse(results.config.content); |
| } |
| config.transformerVersion = transformerVersion; |
| config = JSON.stringify(config); |
| |
| if (results.data) { |
| data = results.data.content; |
| } |
| |
| return parseScript(loader, params, content, config, data); |
| }); |
| } |
| |
| function partedLoader(type, loader, params, source) { |
| var promise; |
| switch(type) { |
| case 'script': |
| var config = JSON.stringify({ |
| transformerVersion: transformerVersion |
| }); |
| promise = parseScript(loader, params, source, config); |
| break; |
| case 'style': |
| promise = parseStyle(loader, params, source); |
| break; |
| case 'tpl': |
| promise = parseTemplate(loader, params, source); |
| break; |
| case 'we': |
| default: |
| promise = parseWeexFile(loader, params, source); |
| break; |
| } |
| return promise; |
| } |
| |
| function loader(source) { |
| var self = this; |
| this.cacheable && this.cacheable(); |
| |
| var callback = this.async(); |
| var params = { |
| loaderQuery: loaderUtils.parseQuery(this.query), |
| resourceQuery: loaderUtils.parseQuery(this.resourceQuery), |
| resourcePath: this.resourcePath |
| }; |
| var type = params.loaderQuery.type || 'we'; |
| var promise = partedLoader(type, this, params, source); |
| |
| promise.then(function(result) { |
| if (type === 'style' || type === 'tpl' || type === 'template') { |
| result = 'module.exports=' + result; |
| } |
| // console.log('\n[' + type + ', ' + params.resourcePath + ']\n', source, '\n=========>\n', result + '\n'); |
| callback(null, result); |
| }).catch(function(err) { |
| self.emitError(err.toString()); |
| callback(err.toString(), ''); |
| }); |
| } |
| |
| loader.useScripter = function(module) { |
| scripter = module; |
| } |
| |
| loader.useStyler = function(module) { |
| styler = module; |
| } |
| |
| loader.useTemplater = function(module) { |
| templater = module; |
| } |
| |
| module.exports = loader; |