@hsui/core
Version:
Hundsun frontend runtime core framework
1,565 lines (1,491 loc) • 43.5 kB
JavaScript
import _objectWithoutProperties from '@babel/runtime/helpers/esm/objectWithoutProperties';
import _objectSpread from '@babel/runtime/helpers/esm/objectSpread2';
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
import _classCallCheck from '@babel/runtime/helpers/esm/classCallCheck';
import _createClass from '@babel/runtime/helpers/esm/createClass';
import _classPrivateFieldLooseBase from '@babel/runtime/helpers/esm/classPrivateFieldLooseBase';
import _classPrivateFieldLooseKey from '@babel/runtime/helpers/esm/classPrivateFieldLooseKey';
import { ajax, ajaxCancelMap, storage, setConfig } from '@hsui/sdk';
import _toConsumableArray from '@babel/runtime/helpers/esm/toConsumableArray';
import _typeof from '@babel/runtime/helpers/esm/typeof';
import { createLogger } from '@hsui/logger';
import Model from 'vue';
import Router from 'vue-router';
import _regeneratorRuntime from '@babel/runtime/helpers/esm/regeneratorRuntime';
import _asyncToGenerator from '@babel/runtime/helpers/esm/asyncToGenerator';
export * from '@@/huiExports';
/**
* Native isArray
*/
var isArray = Array.isArray;
/**
* Underscore isFunction
*/
function isFunction(value) {
return Object.prototype.toString.call(value) === '[object Function]';
}
/**
* Redux isPlainObject
*/
function isPlainObject(obj) {
if (_typeof(obj) !== 'object' || obj === null) return false;
var proto = obj;
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto);
}
return Object.getPrototypeOf(obj) === proto;
}
/**
* Check if powered by HUI Micro App
*/
function isMicroApp() {
return Boolean(window.__POWERED_BY_HUI_MICRO_APP__);
}
/**
* simple generate uuid
* 支持 ie10 及以上
* 基于 uuid v4 添加 performance.now 避免重复
*/
function uuid() {
var d = Date.now();
if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
d += performance.now(); //use high-precision timer if available
}
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c === 'x' ? r : r & 0x3 | 0x8).toString(16);
});
}
/**
* Underscore uniqueId
*/
var idCounter = 0;
function uniqueId(prefix) {
var id = ++idCounter + '';
return prefix ? prefix + id : id;
}
/**
* Native extend
*/
var extend = Object.assign;
/**
* Lodash isObject
*/
function isObject$1(value) {
var type = _typeof(value);
return value != null && (type == 'object' || type == 'function');
}
/**
* Underscore clone
*/
function clone(value) {
if (!isObject$1(value)) return value;
if (typeof value === 'function') return value;
return isArray(value) ? value.slice() : extend({}, value);
}
/**
* DeepClone
*/
function deepClone(value) {
return JSON.parse(JSON.stringify(value));
}
var utils = /*#__PURE__*/Object.freeze({
__proto__: null,
isArray: isArray,
isFunction: isFunction,
isPlainObject: isPlainObject,
isMicroApp: isMicroApp,
uuid: uuid,
uniqueId: uniqueId,
extend: extend,
isObject: isObject$1,
clone: clone,
deepClone: deepClone
});
/**
* Lodash isUndefined
*/
function isUndefined(value) {
return value === undefined;
}
/**
* Lodash isObject
*/
function isObject(value) {
var type = _typeof(value);
return value != null && (type == 'object' || type == 'function');
}
/**
* Lodash noop
*/
function noop() {
// No operation performed.
}
function isNull(value) {
return value === null || value === undefined;
}
function isString(value) {
return typeof value === 'string';
}
/**
* @class - MiddlewareManager
* @classdesc - manager of middlewares
*/
var MiddlewareManager = /*#__PURE__*/function () {
function MiddlewareManager(type) {
_classCallCheck(this, MiddlewareManager);
this.type = type;
this.middlewares = [];
this.finalHook = noop;
}
_createClass(MiddlewareManager, [{
key: "final",
value: function final(hook) {
this.finalHook = hook;
}
}, {
key: "concat",
value: function concat(middlewares) {
this.middlewares = this.middlewares.concat(middlewares);
}
}, {
key: "push",
value: function push(middleware) {
this.middlewares.push(middleware);
}
// just run and return nothing
}, {
key: "justRun",
value: function justRun() {
this.args = Array.prototype.slice.call(arguments);
var _this = this;
var fn = function fn(index) {
if (index < this.middlewares.length) {
this.middlewares[index].apply(null, [].concat(_toConsumableArray(this.args), [function () {
fn.call(_this, ++index);
}]));
} else {
this.finalHook.apply(null, this.args);
}
};
fn.call(_this, 0);
}
// run middlewares and return a promise
}, {
key: "runAndReturn",
value: function runAndReturn() {
this.args = Array.prototype.slice.call(arguments);
var _this = this;
return new Promise(function (resolve, reject) {
var fn = function fn(index) {
if (index < this.middlewares.length) {
try {
this.middlewares[index].apply(null, [].concat(_toConsumableArray(this.args), [function () {
fn.call(_this, ++index);
}]));
} catch (error) {
reject(error);
}
} else {
// final hook should return a promise too
this.finalHook.apply(null, this.args).then(resolve).catch(reject);
}
};
fn.call(_this, 0);
});
}
}]);
return MiddlewareManager;
}();
var manager = {};
['before-route-change', 'after-route-change', 'before-request-send', 'after-request-send', 'before-launch'].forEach(function (type) {
manager[type] = new MiddlewareManager(type);
});
var beforeRouteChange = manager['before-route-change'];
var afterRouteChange = manager['after-route-change'];
var beforeRequestSend = manager['before-request-send'];
var afterRequestSend = manager['after-request-send'];
var beforeLaunch = manager['before-launch'];
function registerMiddleware(type, middleware) {
if (isFunction(middleware)) {
manager[type].push(middleware);
}
if (isArray(middleware)) {
manager[type].concat(middleware);
}
}
var logger = createLogger();
var log = function log() {
for (var _len = arguments.length, content = new Array(_len), _key = 0; _key < _len; _key++) {
content[_key] = arguments[_key];
}
return logger.info.apply(logger, content);
};
logger.levels.forEach(function (level) {
log[level] = function () {
for (var _len2 = arguments.length, content = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
content[_key2] = arguments[_key2];
}
return logger[level].apply(logger, content);
};
});
function final_(error, response) {
if (error) {
return Promise.reject(error);
}
return Promise.resolve(response);
}
/**
* 合并全局配置和实例配置
* @param {Object} defaultConfig 全局配置
* @param {Object} config 实例配置
* @returns 合并后的请求配置
*/
function mergeConfig(defaultConfig, config) {
var mergedConfig = _objectSpread(_objectSpread({}, defaultConfig), config);
if (mergedConfig.shouldMergeHeaders) {
var defaultHeaders = defaultConfig.headers;
var configHeaders = config.headers;
var mergedHeaders = _objectSpread(_objectSpread({}, defaultHeaders), configHeaders);
mergedConfig.headers = mergedHeaders;
}
return mergedConfig;
}
/**
* fetchPromise(调用fetch函数得到) 和 ajaxPromise(调用ajax函数得到) 关联对应
* 其中,key 为 fetchPromise,value 为 ajaxPromise
*/
var fetchMap = new WeakMap();
var defaultConfig = {
method: 'post',
data: {},
timeout: 5000,
headers: {},
withCredentials: false
};
var Fetch = /*#__PURE__*/_createClass(function Fetch() {
var _config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, Fetch);
extend(defaultConfig, _config);
var ajaxPromise; // 存储 ajax 返回的 promise
beforeRequestSend.final(function (config) {
return new Promise(function (resolve, reject) {
var error, response;
ajaxPromise = ajax(config);
ajaxPromise.then(function (res) {
return response = res;
}).catch(function (err) {
return error = err;
}).finally(function () {
afterRequestSend.runAndReturn(error, response).then(resolve).catch(reject);
});
});
});
afterRequestSend.final(final_);
function fetch(config) {
log.debug('Fetch 实例初始化选项', mergeConfig(defaultConfig, config));
var fetchPromise = beforeRequestSend.runAndReturn(mergeConfig(defaultConfig, config));
fetchMap.set(fetchPromise, ajaxPromise); // 建立关联,fetchPromise 和 ajaxPromise
return fetchPromise;
}
fetch.get = function (url, config) {
if (config) {
extend(config, {
url: url,
method: 'get'
});
} else {
config = {
url: url,
method: 'get'
};
}
return fetch(config);
};
fetch.post = function (url, data, config) {
if (config) {
extend(config, {
url: url,
method: 'post',
data: data
});
} else {
config = {
url: url,
method: 'post',
data: data
};
}
return fetch(config);
};
fetch.cancel = function () {
for (var _len = arguments.length, fetchPromises = new Array(_len), _key = 0; _key < _len; _key++) {
fetchPromises[_key] = arguments[_key];
}
fetchPromises.forEach(function (fetchPromise, index) {
var ajaxPromise = fetchMap.get(fetchPromise);
var cancel = ajaxCancelMap.get(ajaxPromise);
cancel ? cancel() : log.debug("\u6CA1\u6709\u627E\u5230\u4E0B\u6807\u4E3A ".concat(index, " \u5BF9\u5E94\u7684 cancel \u51FD\u6570"));
});
};
return fetch;
});
function initFetch() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref$defaultConfig = _ref.defaultConfig,
defaultConfig = _ref$defaultConfig === void 0 ? {
method: 'post',
data: {},
timeout: 5000,
headers: {},
withCredentials: false
} : _ref$defaultConfig,
_ref$beforeRequestSen = _ref.beforeRequestSendMiddlewares,
beforeRequestSendMiddlewares = _ref$beforeRequestSen === void 0 ? [] : _ref$beforeRequestSen,
_ref$afterRequestSend = _ref.afterRequestSendMiddlewares,
afterRequestSendMiddlewares = _ref$afterRequestSend === void 0 ? [] : _ref$afterRequestSend;
var beforeRequestSend = new MiddlewareManager('before-request-send');
beforeRequestSend.concat(beforeRequestSendMiddlewares);
var afterRequestSend = new MiddlewareManager('after-request-send');
afterRequestSend.concat(afterRequestSendMiddlewares);
afterRequestSend.final(final_);
var ajaxPromise; // 存储 ajax 函数返回的 promise
beforeRequestSend.final(function (config) {
return new Promise(function (resolve, reject) {
var error, response;
ajaxPromise = ajax(config);
ajaxPromise.then(function (res) {
return response = res;
}).catch(function (err) {
return error = err;
}).finally(function () {
afterRequestSend.runAndReturn(error, response).then(resolve).catch(reject);
});
});
});
var fetch = function fetch(config) {
log.debug('Fetch 实例初始化选项', mergeConfig(defaultConfig, config));
var fetchPromise = beforeRequestSend.runAndReturn(mergeConfig(defaultConfig, config));
fetchMap.set(fetchPromise, ajaxPromise);
return fetchPromise;
};
fetch.get = function (url, config) {
if (config) {
extend(config, {
url: url,
method: 'get'
});
} else {
config = {
url: url,
method: 'get'
};
}
return fetch(config);
};
fetch.post = function (url, data, config) {
if (config) {
extend(config, {
url: url,
method: 'post',
data: data
});
} else {
config = {
url: url,
method: 'post',
data: data
};
}
return fetch(config);
};
fetch.cancel = function () {
for (var _len2 = arguments.length, fetchPromises = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
fetchPromises[_key2] = arguments[_key2];
}
fetchPromises.forEach(function (fetchPromise, index) {
var ajaxPromise = fetchMap.get(fetchPromise); // 根据传入的 fetchPromise,查找对应的 ajaxPromise
var cancel = ajaxCancelMap.get(ajaxPromise); // 根据指定的 ajaxPromise,查找对应的取消函数
cancel ? cancel() : log.debug("\u6CA1\u6709\u627E\u5230\u4E0B\u6807\u4E3A ".concat(index, " \u5BF9\u5E94\u7684 cancel \u51FD\u6570"));
});
};
return fetch;
}
var _require = require('../package.json'),
version = _require.version;
var isNavigationFailure = Router.isNavigationFailure,
NavigationFailureType = Router.NavigationFailureType;
var encodeReserveRE = /[!'()*]/g;
var encodeReserveReplacer = function encodeReserveReplacer(c) {
return '%' + c.charCodeAt(0).toString(16);
};
var commaRE = /%2C/g;
// fixed encodeURIComponent which is more conformant to RFC3986:
// - escapes [!'()*]
// - preserve commas
var encode = function encode(str) {
return encodeURIComponent(str).replace(encodeReserveRE, encodeReserveReplacer).replace(commaRE, ',');
};
var decode = decodeURIComponent;
var defaultRouterOpts = {
scrollBehavior: function scrollBehavior() {
return {
x: 0,
y: 0
};
}
};
var router = null;
function initRouter$1(routes, opts) {
if (router) return router;
// 避免在调用 initRouter 之前注册,在 1.0 的场景下,多个子应用都访问 @hsui/core 的情况下会造成冲突
Model.use(Router);
// 合并 defaultRouterOpts
opts = _objectSpread(_objectSpread({}, defaultRouterOpts), opts);
// 保证在 hash 模式下也能从 location.search 中读取查询参数
// TODO - 暂时还没有解决方案,在主子应用同时存在路由参数的情况下,url 会存在多个 search 片段的问题
if (opts.mode === 'hash') {
opts = _objectSpread(_objectSpread({}, opts), {}, {
parseQuery: function parseQuery(query) {
var res = {};
query = query.trim().replace(/^(\?|#|&)/, '');
if (!query) {
var _location = location,
search = _location.search;
search = search.trim().replace(/^(\?|#|&)/, '');
if (!search) {
return res;
}
query = search;
}
query.split('&').forEach(function (param) {
var parts = param.replace(/\+/g, ' ').split('=');
var key = decode(parts.shift());
var val = parts.length > 0 ? decode(parts.join('=')) : null;
if (res[key] === undefined) {
res[key] = val;
} else if (Array.isArray(res[key])) {
res[key].push(val);
} else {
res[key] = [res[key], val];
}
});
return res;
},
stringifyQuery: function stringifyQuery(obj) {
var res = obj ? Object.keys(obj).map(function (key) {
var val = obj[key];
if (val === undefined) {
return '';
}
if (val === null) {
return encode(key);
}
if (Array.isArray(val)) {
var result = [];
val.forEach(function (val2) {
if (val2 === undefined) {
return;
}
if (val2 === null) {
result.push(encode(key));
} else {
result.push(encode(key) + '=' + encode(val2));
}
});
return result.join('&');
}
return encode(key) + '=' + encode(val);
}).filter(function (x) {
return x.length > 0;
}).join('&') : null;
if (res && !location.search.includes(res)) {
return "?".concat(res);
}
return '';
}
});
}
router = new Router(opts);
if (routes) {
router.addRoutes(routes);
}
log.debug('Router 实例', router);
log.debug('Router 构建选项', opts);
log.debug('Routes 路由记录', router.getRoutes());
router.beforeEach(function (to, from, next) {
log.debug('路由跳转前置导航守卫', to, from);
next();
});
beforeRouteChange.middlewares.forEach(function (middleware) {
return router.beforeEach(middleware);
});
router.afterEach(function (to, from) {
log.debug('路由跳转后置导航守卫', to, from);
afterRouteChange.justRun(to, from);
});
return router;
}
/**
* Set default router options
* @param {object} opts
*/
function setRouterOpts(opts) {
extend(defaultRouterOpts, opts);
}
/**
* @description jump programmatically
* @param {String} path target path
* @param {Object} opts options
* @param {Boolean} opts.history whether to keep current browser history, perform like pushState or replaceState, default true
* @param {Boolean} opts.animation todo
* @param {Object} query query params
*/
function navigate(path, opts, query) {
if (!router) return;
var defaultOpts = {
history: true
};
var defaultQuery = {};
if (!_typeof(path) === 'string' || path === '') {
log.error('navigate 方法必须指定 path 为字符串类型且不能为空');
return false;
}
// 只有两个参数,则第二个为 query
if (isPlainObject(opts) && isUndefined(query)) {
query = opts;
opts = defaultOpts;
}
// path 是必填项
if (isUndefined(opts)) {
opts = defaultOpts;
query = defaultQuery;
}
var _opts = opts,
history = _opts.history;
var onError = function onError(err) {
if (isNavigationFailure(err, NavigationFailureType.duplicated) || isNavigationFailure(err, NavigationFailureType.redirected)) {
return;
}
log.error('路由跳转异常', err);
throw err;
};
if (history) {
router.push({
path: path,
query: query
}).catch(onError);
} else {
router.replace({
path: path,
query: query
}).catch(onError);
}
}
/**
* @description go forwards or go backwards in the history stack programmatically
* @param {Number} n steps to go, setting to 0 perform like reload
*/
function go(n) {
if (!router) return;
router.go(n);
}
/**
* https://github.com/developit/mitt
*/
function mitt(all) {
all = all || new Map();
return {
on: function on(type, handler) {
var handlers = all.get(type);
var added = handlers && handlers.push(handler);
if (!added) {
all.set(type, [handler]);
}
log.debug('部署事件监听', type);
},
off: function off(type, handler) {
var handlers = all.get(type);
if (handlers) {
if (handler) {
handlers.splice(handlers.indexOf(handler) >>> 0, 1);
} else {
all.set(type, []);
}
}
log.debug('取消事件监听', type);
},
emit: function emit(type) {
log.debug.apply(log, ['触发事件监听'].concat(Array.prototype.slice.call(arguments)));
var args = Array.prototype.slice.call(arguments);
(all.get(type) || []).slice().map(function (handler) {
log.debug('响应事件监听', type, handler);
handler.apply(null, args.slice(1));
});
(all.get('*') || []).slice().map(function (handler) {
log.debug('响应事件监听', type, handler);
handler.apply(null, args);
});
}
};
}
var emitter = mitt();
emitter.once = function (type, handler) {
var _handler = function _handler() {
handler.apply(null, Array.prototype.slice.call(arguments));
emitter.off(type, _handler);
};
emitter.on(type, _handler);
};
var on = emitter.on,
once = emitter.once,
off = emitter.off,
emit = emitter.emit,
trigger = emitter.emit;
/**
* Path parser
* - Inspired:
* Vue.js Path parser
*/
// actions
var APPEND = 0;
var PUSH = 1;
var INC_SUB_PATH_DEPTH = 2;
var PUSH_SUB_PATH = 3;
// states
var BEFORE_PATH = 0;
var IN_PATH = 1;
var BEFORE_IDENT = 2;
var IN_IDENT = 3;
var IN_SUB_PATH = 4;
var IN_SINGLE_QUOTE = 5;
var IN_DOUBLE_QUOTE = 6;
var AFTER_PATH = 7;
var ERROR = 8;
var pathStateMachine = [];
pathStateMachine[BEFORE_PATH] = {
ws: [BEFORE_PATH],
ident: [IN_IDENT, APPEND],
'[': [IN_SUB_PATH],
eof: [AFTER_PATH]
};
pathStateMachine[IN_PATH] = {
ws: [IN_PATH],
'.': [BEFORE_IDENT],
'[': [IN_SUB_PATH],
eof: [AFTER_PATH]
};
pathStateMachine[BEFORE_IDENT] = {
ws: [BEFORE_IDENT],
ident: [IN_IDENT, APPEND],
'0': [IN_IDENT, APPEND],
number: [IN_IDENT, APPEND]
};
pathStateMachine[IN_IDENT] = {
ident: [IN_IDENT, APPEND],
'0': [IN_IDENT, APPEND],
number: [IN_IDENT, APPEND],
ws: [IN_PATH, PUSH],
'.': [BEFORE_IDENT, PUSH],
'[': [IN_SUB_PATH, PUSH],
eof: [AFTER_PATH, PUSH]
};
pathStateMachine[IN_SUB_PATH] = {
"'": [IN_SINGLE_QUOTE, APPEND],
'"': [IN_DOUBLE_QUOTE, APPEND],
'[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH],
']': [IN_PATH, PUSH_SUB_PATH],
eof: ERROR,
else: [IN_SUB_PATH, APPEND]
};
pathStateMachine[IN_SINGLE_QUOTE] = {
"'": [IN_SUB_PATH, APPEND],
eof: ERROR,
else: [IN_SINGLE_QUOTE, APPEND]
};
pathStateMachine[IN_DOUBLE_QUOTE] = {
'"': [IN_SUB_PATH, APPEND],
eof: ERROR,
else: [IN_DOUBLE_QUOTE, APPEND]
};
/**
* Check if an expression is a literal value.
*/
var literalValueRE = /^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/;
function isLiteral(exp) {
return literalValueRE.test(exp);
}
/**
* Strip quotes from a string
*/
function stripQuotes(str) {
var a = str.charCodeAt(0);
var b = str.charCodeAt(str.length - 1);
return a === b && (a === 0x22 || a === 0x27) ? str.slice(1, -1) : str;
}
/**
* Determine the type of a character in a keypath.
*/
function getPathCharType(ch) {
if (ch === undefined || ch === null) {
return 'eof';
}
var code = ch.charCodeAt(0);
switch (code) {
case 0x5b: // [
case 0x5d: // ]
case 0x2e: // .
case 0x22: // "
case 0x27:
// '
return ch;
case 0x5f: // _
case 0x24: // $
case 0x2d:
// -
return 'ident';
case 0x09: // Tab
case 0x0a: // Newline
case 0x0d: // Return
case 0xa0: // No-break space
case 0xfeff: // Byte Order Mark
case 0x2028: // Line Separator
case 0x2029:
// Paragraph Separator
return 'ws';
}
return 'ident';
}
/**
* Format a subPath, return its plain form if it is
* a literal string or number. Otherwise prepend the
* dynamic indicator (*).
*/
function formatSubPath(path) {
var trimmed = path.trim();
// invalid leading 0
if (path.charAt(0) === '0') {
return false;
}
return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed;
}
/**
* Parse a string path into an array of segments
*/
function parse(path) {
var keys = [];
var index = -1;
var mode = BEFORE_PATH;
var subPathDepth = 0;
var c;
var key;
var newChar;
var type;
var transition;
var action;
var typeMap;
var actions = [];
actions[PUSH] = function () {
if (key !== undefined) {
keys.push(key);
key = undefined;
}
};
actions[APPEND] = function () {
if (key === undefined) {
key = newChar;
} else {
key += newChar;
}
};
actions[INC_SUB_PATH_DEPTH] = function () {
actions[APPEND]();
subPathDepth++;
};
actions[PUSH_SUB_PATH] = function () {
if (subPathDepth > 0) {
subPathDepth--;
mode = IN_SUB_PATH;
actions[APPEND]();
} else {
subPathDepth = 0;
if (key === undefined) {
return false;
}
key = formatSubPath(key);
if (key === false) {
return false;
} else {
actions[PUSH]();
}
}
};
function maybeUnescapeQuote() {
var nextChar = path[index + 1];
if (mode === IN_SINGLE_QUOTE && nextChar === "'" || mode === IN_DOUBLE_QUOTE && nextChar === '"') {
index++;
newChar = '\\' + nextChar;
actions[APPEND]();
return true;
}
}
while (mode !== null) {
index++;
c = path[index];
if (c === '\\' && maybeUnescapeQuote()) {
continue;
}
type = getPathCharType(c);
typeMap = pathStateMachine[mode];
transition = typeMap[type] || typeMap['else'] || ERROR;
if (transition === ERROR) {
return; // parse error
}
mode = transition[0];
action = actions[transition[1]];
if (action) {
newChar = transition[2];
newChar = newChar === undefined ? c : newChar;
if (action() === false) {
return;
}
}
if (mode === AFTER_PATH) {
return keys;
}
}
}
var I18nPath = /*#__PURE__*/function () {
function I18nPath() {
_classCallCheck(this, I18nPath);
this._cache = void 0;
this._cache = Object.create(null);
}
/**
* External parse that check for a cache hit first
*/
_createClass(I18nPath, [{
key: "parsePath",
value: function parsePath(path) {
var hit = this._cache[path];
if (!hit) {
hit = parse(path);
if (hit) {
this._cache[path] = hit;
}
}
return hit || [];
}
/**
* Get path value from path string
*/
}, {
key: "getPathValue",
value: function getPathValue(obj, path) {
if (!isObject(obj)) {
return null;
}
var paths = this.parsePath(path);
if (paths.length === 0) {
return null;
} else {
var length = paths.length;
var last = obj;
var i = 0;
while (i < length) {
var value = last[paths[i]];
if (value === undefined || value === null) {
return null;
}
last = value;
i++;
}
return last;
}
}
}]);
return I18nPath;
}();
var i18ns = [];
var I18n = /*#__PURE__*/function () {
/**
* lightweight i18n
* @param {object} options
* - locale
* - messages
*/
function I18n(options) {
_classCallCheck(this, I18n);
this.locale = options.locale || 'en-US';
this.messages = options.messages || {};
// window.__hCoreReference
var root = window.__hCoreReference__.root;
this._root = options.root || root || null;
this._path = new I18nPath();
this.watchLocale();
i18ns.push(this);
}
_createClass(I18n, [{
key: "watchLocale",
value: function watchLocale() {
// sync with vue-i18n root
if (this._root && this._root.$i18n) {
// locale watcher
var _this = this;
this.localeWatcher = this._root.$i18n.vm.$watch('locale', function (val) {
_this.locale = val;
}, {
immediate: true
});
}
return null;
}
// string support only
}, {
key: "_translate",
value: function _translate(message, key) {
var pathRet = this._path.getPathValue(message, key);
if (isArray(pathRet) || isPlainObject(pathRet)) {
return pathRet;
}
var ret;
if (isNull(pathRet) && isPlainObject(message)) {
ret = message[key];
} else if (isString(pathRet)) {
ret = pathRet;
} else {
return null;
}
return !isString(ret) ? ret.join('') : ret;
}
}, {
key: "t",
value: function t(key) {
if (!key) return '';
var message = this.messages[this.locale];
if (message) {
return this._translate(message, key);
}
return '';
}
}]);
return I18n;
}();
var _app = /*#__PURE__*/_classPrivateFieldLooseKey("app");
var _isNavigable = /*#__PURE__*/_classPrivateFieldLooseKey("isNavigable");
var _options = /*#__PURE__*/_classPrivateFieldLooseKey("options");
var _walkOpts = /*#__PURE__*/_classPrivateFieldLooseKey("walkOpts");
var HCore = /*#__PURE__*/function () {
function HCore(_opts) {
_classCallCheck(this, HCore);
Object.defineProperty(this, _walkOpts, {
value: _walkOpts2
});
Object.defineProperty(this, _app, {
writable: true,
value: void 0
});
// enable or disable router system
Object.defineProperty(this, _isNavigable, {
writable: true,
value: true
});
// model options
Object.defineProperty(this, _options, {
writable: true,
value: {
el: '#app',
beforeDestroy: function beforeDestroy() {
i18ns.forEach(function (i18n) {
if (i18n.localeWatcher) {
delete i18n.localeWatcher;
i18n = null;
}
});
}
}
});
if (!!_classPrivateFieldLooseBase(this, _app)[_app]) {
return _classPrivateFieldLooseBase(this, _app)[_app];
}
_classPrivateFieldLooseBase(this, _app)[_app] = this;
_classPrivateFieldLooseBase(this, _walkOpts)[_walkOpts](_opts);
this.Model.prototype.$hCore = _classPrivateFieldLooseBase(this, _app)[_app];
if (!this.ajax) {
var fetch = new Fetch();
extend(this, {
ajax: fetch,
fetch: fetch
});
}
extend(this, {
middleware: registerMiddleware
});
extend(this, {
on: on,
once: once,
off: off,
emit: emit,
trigger: trigger
});
extend(this, {
log: log,
logger: logger
});
extend(this, {
utils: utils
});
extend(this, {
storage: storage
});
extend(this, {
navigate: navigate,
go: go
});
}
_createClass(HCore, [{
key: "Model",
get: function get() {
return Model;
}
}, {
key: "options",
get: function get() {
return _classPrivateFieldLooseBase(this, _options)[_options];
}
}, {
key: "version",
get: function get() {
return version;
}
}, {
key: "initRouter",
value: function initRouter(routes, opts) {
if (_classPrivateFieldLooseBase(this, _isNavigable)[_isNavigable]) {
var router = initRouter$1(routes, opts);
extend(_classPrivateFieldLooseBase(this, _options)[_options], {
router: router,
template: '<router-view></router-view>'
});
extend(this, {
router: router
});
}
}
}, {
key: "addRoutes",
value: function addRoutes(routes) {
if (this.router) {
this.log.debug('新增 Routes 路由记录', routes);
this.router.addRoutes(routes);
} else {
this.initRouter(routes);
}
}
}, {
key: "start",
value: function start(cb) {
var _this = this;
// 在应用前要确保已经完成路由系统的初始化
if (!this.router) {
this.initRouter();
}
// 这里最好不要有异步逻辑,在微前端框架下可能会出现问题
// 暂时不对外
beforeLaunch.final(function () {
// 在微前端框架下应用生命周期被接管
if (!isMicroApp()) {
_this.root = new _this.Model(_classPrivateFieldLooseBase(_this, _options)[_options]);
_this.root.$nextTick(function () {
trigger('app-ready', _this.root);
cb && cb(_this.root);
});
} else {
// 启动的回调函数传递给 singleSpaVue,保持和独立运行一致的处理逻辑
trigger('app-start', cb);
}
});
beforeLaunch.justRun(this);
}
}]);
return HCore;
}();
function _walkOpts2(opts) {
var _this2 = this;
if (isPlainObject(opts)) {
Object.keys(opts).forEach(function (key) {
// ajaxConfig === fetchConfig
if (key === 'ajaxConfig' || key === 'fetchConfig') {
var fetch = new Fetch(opts[key]);
extend(_this2, {
ajax: fetch,
fetch: fetch
}); // ajax === fetch
}
// logLevel
if (key === 'logLevel') {
logger.setLevel(opts[key]);
}
// extra vue options
if (key === 'extraModelOptions') {
var staticModelKey = ['router'];
Object.keys(opts[key]).filter(function (modelKey) {
return !staticModelKey.includes(modelKey);
}).forEach(function (modelKey) {
extend(_classPrivateFieldLooseBase(_this2, _options)[_options], _defineProperty({}, modelKey, opts[key][modelKey]));
// store
if (modelKey === 'store') {
extend(_this2, _defineProperty({}, modelKey, opts[key][modelKey]));
}
});
}
// extra router options
if (key === 'extraRouterOptions') {
if (typeof opts[key]['isNavigable'] !== 'undefined') {
_classPrivateFieldLooseBase(_this2, _isNavigable)[_isNavigable] = opts[key]['isNavigable'];
}
if (_classPrivateFieldLooseBase(_this2, _isNavigable)[_isNavigable]) {
_classPrivateFieldLooseBase(_this2, _isNavigable)[_isNavigable] && setRouterOpts(opts[key]);
}
}
});
}
}
/**
* Find which layout the component should render.
* If the component is not specified layout name, `default` is used.
* Otherwise return undefined.
*/
function resolveLayoutName(matched) {
var defaultName = 'default';
var last = matched[matched.length - 1];
if (!last) {
return;
}
var Component = last.components.default;
if (!Component) {
return;
}
var isAsync = typeof Component === 'function' && !Component.options;
if (isAsync) {
return;
}
return getLayoutName(Component) || defaultName;
}
function getLayoutName(Component /* ComponentOptions | VueConstructor */) {
var isCtor = typeof Component === 'function' && Component.options;
var options = isCtor ? Component.options : Component;
if (options.layout) {
return options.layout;
} else {
// Retrieve super component and mixins
var mixins = (options.mixins || []).slice().reverse();
var extend = options.extends || [];
return mixins.concat(extend).reduce(function (acc, c) {
return acc || getLayoutName(c);
}, undefined);
}
}
function loadAsyncComponents(route) {
var promises = [];
route.matched.forEach(function (record) {
Object.keys(record.components).forEach(function (key) {
var component = record.components[key];
var isAsync = typeof component === 'function' && !component.options;
if (isAsync) {
promises.push(component().then(function (loaded) {
var isEsModule = loaded.__esModule || typeof Symbol !== 'undefined' && loaded[Symbol.toStringTag] === 'Module';
record.components[key] = isEsModule ? loaded.default : loaded;
}));
}
});
});
return Promise.all(promises);
}
/*!
* vue-router-layout v0.1.5
* Lightweight layout resolver for Vue Router.
* https://github.com/ktsn/vue-router-layout
*
* @license
* Copyright (c) 2018 katashin
* Released under the MIT license
* https://github.com/ktsn/vue-router-layout/blob/master/LICENSE
*/
function initRouterLayout(resolve) {
Model.use(Router);
Model.mixin({
inject: {
$_routerLayout_notifyRouteUpdate: {
default: null
}
},
beforeRouteUpdate: function beforeRouteUpdate(to, _from, next) {
var _this = this;
return _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
var notify;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
notify = _this.$_routerLayout_notifyRouteUpdate;
if (!notify) {
_context.next = 4;
break;
}
_context.next = 4;
return notify(to);
case 4:
next();
case 5:
case "end":
return _context.stop();
}
}, _callee);
}))();
}
});
return Model.extend({
name: 'RouterLayout',
data: function data() {
return {
layoutName: undefined,
layouts: Object.create(null)
};
},
watch: {
layoutName: function layoutName(name) {
if (!this.layouts[name]) {
this.$set(this.layouts, name, function () {
return resolve(name);
});
}
}
},
provide: function provide() {
var _this2 = this;
return {
$_routerLayout_notifyRouteUpdate: function () {
var _$_routerLayout_notifyRouteUpdate = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(to) {
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
_context2.next = 2;
return loadAsyncComponents(to);
case 2:
_this2.layoutName = resolveLayoutName(to.matched) || _this2.layoutName;
case 3:
case "end":
return _context2.stop();
}
}, _callee2);
}));
function $_routerLayout_notifyRouteUpdate(_x) {
return _$_routerLayout_notifyRouteUpdate.apply(this, arguments);
}
return $_routerLayout_notifyRouteUpdate;
}()
};
},
/**
* Somehow, app can't be rendered when navigate back under micro app framework without this hook
*/
mounted: function mounted() {
var _this3 = this;
return _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3() {
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
while (1) switch (_context3.prev = _context3.next) {
case 0:
if (!_this3.$router) {
_context3.next = 4;
break;
}
_context3.next = 3;
return loadAsyncComponents(_this3.$route);
case 3:
_this3.layoutName = resolveLayoutName(_this3.$route.matched) || _this3.layoutName;
case 4:
case "end":
return _context3.stop();
}
}, _callee3);
}))();
},
beforeRouteEnter: function beforeRouteEnter(to, _from, next) {
return _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4() {
return _regeneratorRuntime().wrap(function _callee4$(_context4) {
while (1) switch (_context4.prev = _context4.next) {
case 0:
_context4.next = 2;
return loadAsyncComponents(to);
case 2:
next(function (vm) {
vm.layoutName = resolveLayoutName(to.matched) || vm.layoutName;
});
case 3:
case "end":
return _context4.stop();
}
}, _callee4);
}))();
},
beforeRouteUpdate: function beforeRouteUpdate(to, _from, next) {
var _this4 = this;
return _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5() {
return _regeneratorRuntime().wrap(function _callee5$(_context5) {
while (1) switch (_context5.prev = _context5.next) {
case 0:
_context5.next = 2;
return loadAsyncComponents(to);
case 2:
_this4.layoutName = resolveLayoutName(to.matched) || _this4.layoutName;
next();
case 4:
case "end":
return _context5.stop();
}
}, _callee5);
}))();
},
render: function render(h) {
var layout = this.layoutName && this.layouts[this.layoutName];
if (!layout) {
return h();
}
return h(layout, {
key: this.layoutName
});
}
});
}
var _excluded = ["meta"];
/**
* 整个应用框架接口应该有且仅有三种调用方式:
*
* 1. 通过应用实例调用,这应该是首选的调用方式,适合在应用入口或者 vue 文件中,具体如下:
* const app = hCore();
* app.ajax 或者 this.$hCore.ajax
*
* 2. 通过 hCore 函数对象调用,这应该可以覆盖非 vue 实例的场景,比如在一个普通的 js 文件中调用,具体如下:
* hCore.ajax
*
* 3. 通过 @hsui/core 暴露的接口调用,这样的接口应该是有限的,目前包括:
* - hCoreReference
* - initFetch
* - initRouter
* - initRouterLayout
*
* 4. 通过 @@/huiExports 动态扩展 @hsui/core
*/
var hCoreReference;
var hCoreOpts = {
meta: {
versions: {
'@hsui/core': version,
vue: Model.version,
'vue-router': Router.version
}
}
};
function hCore(opts) {
if (isPlainObject(opts)) {
// 设置日志级别
logger.setLevel(opts.logLevel || 'info');
// 本地日志容量控制配置
logger.setConfig && logger.setConfig(opts.logConfig || {});
// 合并元数据信息
if (opts.meta) {
for (var key in opts.meta) {
if (Object.hasOwnProperty.call(opts.meta, key)) {
if (key === 'versions') {
hCoreOpts.meta.versions = _objectSpread(_objectSpread({}, hCoreOpts.meta.versions), opts.meta.versions);
} else {
hCoreOpts.meta[key] = opts.meta[key];
}
}
}
}
opts.meta;
var extra = _objectWithoutProperties(opts, _excluded);
hCoreOpts = _objectSpread(_objectSpread({}, hCoreOpts), extra);
}
window.__hCoreReference__ = hCoreReference = new HCore(hCoreOpts);
log.debug('应用元数据信息', hCoreOpts.meta);
log.debug('hCore 实例', hCoreReference);
log.debug('hCore 构建选项', hCoreOpts);
return hCoreReference;
}
setConfig({
logger: logger
});
// 支持扩展 HCore 的原型方法
extend(hCore, {
extend: function extend(opts) {
// Handle case when target is a string or something (possible in deep copy)
if (!isPlainObject(opts)) return false;
// Extend the base object
for (var name in opts) {
if (Object.hasOwnProperty.call(opts, name)) {
var copy = opts[name];
// Prevent Object.prototype pollution
// Prevent never-ending loop
if (name === '__proto__' || opts === copy) {
continue;
}
// Recurse if we're merging plain objects or arrays
if (copy && (isPlainObject(copy) || isArray(copy))) {
// Handle a deep copy situation
HCore.prototype[name] = deepClone(copy);
// Don't bring in undefined values
} else if (copy !== undefined) {
HCore.prototype[name] = copy;
}
}
}
}
});
extend(hCore, {
middleware: registerMiddleware
});
extend(hCore, {
log: log,
logger: logger
});
extend(hCore, {
navigate: navigate,
go: go
});
extend(hCore, {
on: on,
once: once,
off: off,
emit: emit,
trigger: trigger
});
extend(hCore, {
storage: storage
});
extend(hCore, {
utils: utils
});
if (hCoreOpts['ajaxConfig'] || hCoreOpts['fetchConfig']) {
var fetch = new Fetch(hCoreOpts['ajaxConfig'] || hCoreOpts['fetchConfig']);
extend(hCore, {
ajax: fetch,
fetch: fetch
});
} else {
var _fetch = new Fetch();
extend(hCore, {
ajax: _fetch,
fetch: _fetch
});
}
/** Legacy for bundler <= 1.3.4 */
var initRouter = function initRouter(routes, opts) {
return setRouterOpts(extend(opts, {
routes: routes
}));
};
export default hCore;
export { I18n, hCoreReference, initFetch, initRouter, initRouterLayout, setRouterOpts as initRouterOptions };