2017-09-23 09:42:16 +00:00
|
|
|
/**
|
2017-10-30 12:47:10 +00:00
|
|
|
* 符合 CommonJS 规范的 类似 Node 的模块化加载
|
|
|
|
* 一. 注: MiaoScript 中 require.main 不存在
|
|
|
|
* 二. 加载 require 流程 例如 在 dir 目录下 调用 require('xx');
|
|
|
|
* a) 加载流程
|
|
|
|
* 1. 如果xx模块是一个內建模块
|
|
|
|
* a. 编译并返回该模块
|
|
|
|
* b. 停止执行
|
|
|
|
* 2. 如果模块以 `./` `../` 开头
|
|
|
|
* a. 尝试使用 resolveAsFile(dir/xx) 加载文件
|
|
|
|
* b. 尝试使用 resolveAsDirectory(dir/xx) 加载目录
|
2017-11-30 05:22:44 +00:00
|
|
|
* 3. 尝试去 root root/core root/modules => xx 加载模块
|
|
|
|
* a. 尝试使用 resolveAsFile(xx/xx) 加载文件
|
|
|
|
* b. 尝试使用 resolveAsDirectory(xx/xx) 加载目录
|
2017-10-30 12:47:10 +00:00
|
|
|
* 4. 抛出 not found 异常
|
|
|
|
* b) resolveAsFile 解析流程
|
|
|
|
* 1. 如果 xx 是一个文件 则作为 `javascript` 文本加载 并停止执行
|
|
|
|
* 2. 如果 xx.js 是一个文件 则作为 `javascript` 文本加载 并停止执行
|
2017-11-30 05:22:44 +00:00
|
|
|
* 3. 如果 xx.json 是一个文件 则使用 `JSON.parse(xx.json)` 解析为对象加载 并停止执行
|
|
|
|
* 暂不支持 4. 如果 xx.msm 是一个文件 则使用MScript解析器解析 并停止执行
|
2017-10-30 12:47:10 +00:00
|
|
|
* c) resolveAsDirectory 解析流程
|
|
|
|
* 1. 如果 xx/package.json 存在 则使用 `JSON.parse(xx/package.json)` 解析并取得 main 字段使用 resolveAsFile(main) 加载
|
|
|
|
* 2. 如果 xx/index.js 存在 则使用 resolveAsFile(xx/index.js) 加载
|
2017-11-30 05:22:44 +00:00
|
|
|
* 3. 如果 xx/index.json 存在 则使用 `xx/index.json` 解析为对象加载 并停止执行
|
|
|
|
* 暂不支持 4. 如果 xx/index.msm 是一个文件 则使用MScript解析器解析 并停止执行
|
2017-10-30 12:47:10 +00:00
|
|
|
* 注: MiaoScript 暂不支持多层 modules 加载 暂时不需要(估计以后也不会需要)
|
2017-09-23 09:42:16 +00:00
|
|
|
*/
|
|
|
|
/*global Java, base*/
|
2017-10-10 13:01:43 +00:00
|
|
|
(function (parent) {
|
2017-09-23 09:42:16 +00:00
|
|
|
'use strict';
|
|
|
|
var File = Java.type("java.io.File");
|
2017-10-23 09:09:24 +00:00
|
|
|
var separatorChar = File.separatorChar;
|
2017-11-30 05:22:44 +00:00
|
|
|
var cacheDir = parent + separatorChar + "runtime";
|
2018-01-08 09:12:08 +00:00
|
|
|
var paths = [parent, parent + separatorChar + 'core', parent + separatorChar + 'api', parent + separatorChar + 'modules'];
|
2017-09-23 09:42:16 +00:00
|
|
|
|
2018-05-17 10:30:40 +00:00
|
|
|
try {
|
2017-11-30 05:22:44 +00:00
|
|
|
base.delete(cacheDir);
|
|
|
|
} catch (ex) {
|
|
|
|
console.ex(ex);
|
|
|
|
}
|
2018-05-17 10:30:40 +00:00
|
|
|
|
2017-11-30 05:22:44 +00:00
|
|
|
/**
|
|
|
|
* 判断是否为一个文件
|
|
|
|
* @param file
|
|
|
|
* @returns {*}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
function _isFile(file) {
|
|
|
|
return file.isFile && file.isFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 获得文件规范路径
|
|
|
|
* @param file
|
|
|
|
* @returns {*}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
function _canonical(file) {
|
|
|
|
// noinspection JSUnresolvedVariable
|
|
|
|
return file.canonicalPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 获得缓存的文件名称
|
|
|
|
* @param file
|
|
|
|
* @returns {string}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
function _cacheFile(file) {
|
|
|
|
return _canonical(file).replace(parent, cacheDir);
|
|
|
|
}
|
|
|
|
|
2017-09-23 09:42:16 +00:00
|
|
|
/**
|
|
|
|
* 解析模块名称为文件
|
|
|
|
* 按照下列顺序查找
|
|
|
|
* 当前目录 ./
|
|
|
|
* 父目录 ../
|
|
|
|
* 核心目录 /core
|
|
|
|
* 模块目录 /modules
|
|
|
|
* @param name 模块名称
|
2017-10-26 13:01:24 +00:00
|
|
|
* @param parent 父目录
|
2017-09-23 09:42:16 +00:00
|
|
|
*/
|
2017-10-11 17:39:51 +00:00
|
|
|
function resolve(name, parent) {
|
2017-10-30 03:17:42 +00:00
|
|
|
name = _canonical(name) || name;
|
2017-10-11 18:06:07 +00:00
|
|
|
// 解析本地目录
|
2017-10-26 13:01:24 +00:00
|
|
|
if (name.startsWith('./') || name.startsWith('../')) {
|
2017-10-11 18:06:07 +00:00
|
|
|
return resolveAsFile(parent, name) || resolveAsDirectory(parent, name) || undefined;
|
|
|
|
} else {
|
|
|
|
// 查找可能存在的路径
|
2017-10-26 13:01:24 +00:00
|
|
|
for (var i in paths) {
|
2017-10-11 18:06:07 +00:00
|
|
|
var path = paths[i];
|
|
|
|
var result = resolveAsFile(path, name) || resolveAsDirectory(path, name);
|
|
|
|
if (result) {
|
2017-10-26 13:01:24 +00:00
|
|
|
return result;
|
2017-10-11 18:06:07 +00:00
|
|
|
}
|
2017-10-11 17:39:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return undefined;
|
2017-10-10 13:01:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 解析文件
|
|
|
|
* @returns {*}
|
|
|
|
*/
|
2017-10-11 17:39:51 +00:00
|
|
|
function resolveAsFile(dir, file) {
|
2017-10-26 13:01:24 +00:00
|
|
|
file = ext.notNull(dir) ? new File(dir, file) : new File(file);
|
2017-11-30 05:22:44 +00:00
|
|
|
// 直接文件
|
2017-10-11 17:39:51 +00:00
|
|
|
if (file.isFile()) {
|
2017-10-10 13:01:43 +00:00
|
|
|
return file;
|
2017-09-23 09:42:16 +00:00
|
|
|
}
|
2017-11-30 05:22:44 +00:00
|
|
|
// JS文件
|
|
|
|
var js = new File(normalizeName(_canonical(file), ".js"));
|
|
|
|
if (js.isFile()) {
|
|
|
|
return js;
|
|
|
|
}
|
|
|
|
// JSON文件
|
|
|
|
var json = new File(normalizeName(_canonical(file), ".json"));
|
|
|
|
if (json.isFile()) {
|
|
|
|
return json;
|
2017-10-11 17:39:51 +00:00
|
|
|
}
|
|
|
|
}
|
2017-10-26 13:01:24 +00:00
|
|
|
|
2017-10-11 17:39:51 +00:00
|
|
|
/**
|
|
|
|
* 解析目录
|
|
|
|
* @returns {*}
|
|
|
|
*/
|
|
|
|
function resolveAsDirectory(dir, file) {
|
2017-10-26 13:01:24 +00:00
|
|
|
dir = ext.notNull(dir) ? new File(dir, file) : new File(file);
|
2017-10-14 06:27:22 +00:00
|
|
|
var _package = new File(dir, 'package.json');
|
2017-10-11 17:39:51 +00:00
|
|
|
if (_package.exists()) {
|
|
|
|
var json = JSON.parse(base.read(_package));
|
2018-05-17 10:30:40 +00:00
|
|
|
/** @namespace json.main */
|
2017-10-11 17:39:51 +00:00
|
|
|
if (json.main) {
|
2017-10-14 06:27:22 +00:00
|
|
|
return resolveAsFile(dir, json.main);
|
2017-10-11 17:39:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// if no package or package.main exists, look for index.js
|
2017-10-14 06:27:22 +00:00
|
|
|
return resolveAsFile(dir, 'index.js');
|
2017-10-10 13:01:43 +00:00
|
|
|
}
|
|
|
|
|
2017-11-30 05:22:44 +00:00
|
|
|
/**
|
|
|
|
* 后缀检测和添加
|
|
|
|
* @param fileName 文件名称
|
|
|
|
* @param ext 后缀
|
|
|
|
* @returns {*}
|
|
|
|
*/
|
2017-10-10 13:01:43 +00:00
|
|
|
function normalizeName(fileName, ext) {
|
|
|
|
var extension = ext || '.js';
|
|
|
|
if (fileName.endsWith(extension)) {
|
|
|
|
return fileName;
|
2017-09-23 09:42:16 +00:00
|
|
|
}
|
2017-10-10 13:01:43 +00:00
|
|
|
return fileName + extension;
|
2017-09-23 09:42:16 +00:00
|
|
|
}
|
|
|
|
|
2017-10-10 13:01:43 +00:00
|
|
|
/**
|
|
|
|
* 编译模块
|
2017-10-26 13:01:24 +00:00
|
|
|
* @param id 模块ID
|
|
|
|
* @param name 模块名称
|
|
|
|
* @param file 模块文件
|
|
|
|
* @param optional 附加选项
|
2017-10-10 13:01:43 +00:00
|
|
|
* @returns {Object}
|
|
|
|
*/
|
2017-11-30 05:22:44 +00:00
|
|
|
function getCacheModule(id, name, file, optional) {
|
|
|
|
var module = cacheModules[id];
|
|
|
|
if (optional.cache && module) {
|
|
|
|
return module;
|
|
|
|
}
|
2017-11-15 10:40:17 +00:00
|
|
|
console.debug('加载模块', name, '位于', id, 'Optional', JSON.stringify(optional));
|
2017-10-10 13:01:43 +00:00
|
|
|
// noinspection JSUnresolvedVariable
|
2017-11-30 05:22:44 +00:00
|
|
|
module = {
|
2017-10-10 13:01:43 +00:00
|
|
|
id: id,
|
|
|
|
exports: {},
|
|
|
|
loaded: false,
|
|
|
|
require: exports(file.parentFile)
|
|
|
|
};
|
2017-11-30 05:22:44 +00:00
|
|
|
cacheModules[id] = module;
|
2017-10-10 13:01:43 +00:00
|
|
|
try {
|
2017-11-30 05:22:44 +00:00
|
|
|
if (_canonical(file).endsWith('.js')) {
|
|
|
|
compileJs(module, file, optional);
|
|
|
|
}
|
|
|
|
if (_canonical(file).endsWith('.json')) {
|
|
|
|
compileJson(module, file, optional);
|
|
|
|
}
|
|
|
|
if (_canonical(file).endsWith('.msm')) {
|
2018-05-17 10:30:40 +00:00
|
|
|
// noinspection ExceptionCaughtLocallyJS
|
2017-11-30 05:22:44 +00:00
|
|
|
throw Error("暂不支持解析 MiaoScript 模块");
|
|
|
|
}
|
2017-10-10 13:01:43 +00:00
|
|
|
} catch (ex) {
|
2017-11-15 10:40:17 +00:00
|
|
|
console.console('§4警告! §c模块§a', name, '§c编译失败! §4ERR:', ex);
|
2017-10-26 13:01:24 +00:00
|
|
|
console.ex(ex);
|
2017-10-10 13:01:43 +00:00
|
|
|
}
|
|
|
|
return module;
|
|
|
|
}
|
|
|
|
|
2017-09-23 09:42:16 +00:00
|
|
|
/**
|
2017-11-30 05:22:44 +00:00
|
|
|
* 预编译JS
|
2018-05-17 10:30:40 +00:00
|
|
|
* @param module JS模块
|
2017-11-30 05:22:44 +00:00
|
|
|
* @param file JS文件
|
|
|
|
* @param optional 附加选项
|
|
|
|
* @returns {Object}
|
2017-09-23 09:42:16 +00:00
|
|
|
*/
|
2017-11-30 05:22:44 +00:00
|
|
|
function compileJs(module, file, optional) {
|
|
|
|
var cacheFile = _cacheFile(file);
|
|
|
|
var origin = base.read(file);
|
|
|
|
if (optional.hook) {
|
|
|
|
origin = optional.hook(origin);
|
|
|
|
}
|
2018-01-05 11:27:35 +00:00
|
|
|
base.save(cacheFile, "(function __init__(module, exports, require, __dirname, __filename) {" + origin + "});");
|
2017-11-30 05:22:44 +00:00
|
|
|
// 使用 load 可以保留行号和文件名称
|
2018-01-09 11:28:00 +00:00
|
|
|
var compiledWrapper = engineLoad(cacheFile);
|
2017-11-30 05:22:44 +00:00
|
|
|
try {
|
|
|
|
base.delete(cacheFile);
|
|
|
|
} catch (ex) {
|
|
|
|
cacheFile.deleteOnExit();
|
|
|
|
}
|
|
|
|
compiledWrapper.apply(module.exports, [
|
|
|
|
module, module.exports, module.require, file.parentFile, file
|
|
|
|
]);
|
|
|
|
module.loaded = true;
|
2017-09-23 09:42:16 +00:00
|
|
|
}
|
|
|
|
|
2017-11-30 05:22:44 +00:00
|
|
|
/**
|
|
|
|
* 预编译Json
|
2018-05-17 10:30:40 +00:00
|
|
|
* @param module Json模块
|
2017-11-30 05:22:44 +00:00
|
|
|
* @param file Json 文件
|
|
|
|
* @param optional 附加选项
|
|
|
|
* @returns {Object}
|
|
|
|
*/
|
|
|
|
function compileJson(module, file, optional) {
|
|
|
|
module.exports = JSON.parse(base.read(file));
|
|
|
|
module.loaded = true;
|
2017-09-27 12:40:57 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 09:42:16 +00:00
|
|
|
/**
|
|
|
|
* 加载模块
|
|
|
|
* @param name 模块名称
|
2017-10-09 13:17:24 +00:00
|
|
|
* @param path 路径
|
2017-10-26 13:01:24 +00:00
|
|
|
* @param optional 附加选项
|
2017-09-23 09:42:16 +00:00
|
|
|
* @returns {*}
|
|
|
|
* @private
|
|
|
|
*/
|
2017-10-14 06:27:22 +00:00
|
|
|
function _require(name, path, optional) {
|
2017-11-02 17:35:51 +00:00
|
|
|
var file = new File(name);
|
|
|
|
file = _isFile(file) ? file : resolve(name, path);
|
2017-12-28 08:28:13 +00:00
|
|
|
optional = Object.assign({cache: true, warnNotFound: true}, optional);
|
2017-10-10 13:01:43 +00:00
|
|
|
if (file === undefined) {
|
2017-12-28 08:28:13 +00:00
|
|
|
if (optional.warnNotFound) {
|
|
|
|
console.console('§c目录§b', path, '§c下模块§a', name, '§c加载失败! §4未找到该模块!');
|
|
|
|
}
|
2017-10-26 13:01:24 +00:00
|
|
|
return {exports: {}};
|
2017-10-10 13:01:43 +00:00
|
|
|
}
|
2017-10-11 17:39:51 +00:00
|
|
|
// 重定向文件名称和类型
|
2017-11-30 05:22:44 +00:00
|
|
|
return getCacheModule(_canonical(file), file.name.split(".")[0], file, optional);
|
2017-09-23 09:42:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 闭包方法
|
|
|
|
* @param parent 父目录
|
|
|
|
* @returns {Function}
|
|
|
|
*/
|
|
|
|
function exports(parent) {
|
2017-10-14 06:27:22 +00:00
|
|
|
return function (path, optional) {
|
|
|
|
return _require(path, parent, optional).exports;
|
2017-09-23 09:42:16 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-01-09 12:16:36 +00:00
|
|
|
if (typeof parent === "string") {
|
2017-09-23 09:42:16 +00:00
|
|
|
parent = new File(parent);
|
|
|
|
}
|
|
|
|
var cacheModules = [];
|
2017-10-26 16:40:01 +00:00
|
|
|
console.debug("初始化 require 模块组件 父目录 ", _canonical(parent));
|
2017-09-23 09:42:16 +00:00
|
|
|
return exports(parent);
|
2018-01-09 11:28:00 +00:00
|
|
|
});
|