UNPKG

auto-router-vue3

Version:
396 lines (391 loc) 16 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.analysisVue = analysisVue; exports.getConfigStr = getConfigStr; exports.loopDir = loopDir; exports.renderAll = renderAll; exports.updateConfigInfo = updateConfigInfo; exports.watchPages = watchPages; exports.writeRouter = writeRouter; var _compilerSfc = require("vue/compiler-sfc"); var _path = _interopRequireDefault(require("path")); var _fs = _interopRequireDefault(require("fs")); var _watch = _interopRequireDefault(require("watch")); var _comm = require("./comm.js"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } var _config = (0, _comm.getConfig)(); var dirInfo = (0, _comm.getSrcInfo)(); var _filename = dirInfo.filename; // 当前文件路径 var _dirname = dirInfo.dirname; // 当前文件所处的文件夹路径 var __dir = dirInfo.dir; // 执行命令时的路径 var pages = _path["default"].join(__dir, "/src", _config.pagePath); var files; var routeDir = _path["default"].join(__dir, "src/router"); var ignoreDirs = /(components|utils)/; function updateConfigInfo() { _config = (0, _comm.getConfig)(); pages = _path["default"].join(__dir, "/src", _config.pagePath); } /** * @desc 递归遍历文件夹及文件 并做相应的处理 * 规则: * * 1. 页面局部组件 , 若放在单文件夹中 , 需放在在目录下的components文件夹中 * * @param fls * @param p */ var routes = []; // 路由列表 var routesInfo = {}; // 路由详情 function loopDir() { var fls = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; var p = arguments.length > 1 ? arguments[1] : undefined; if (fls.length === 0) return; fls.forEach(function (item) { var fullPath = _path["default"].join(p, item); // 完整路径 var isDir = _fs["default"].statSync(fullPath).isDirectory(); // 是否为文件夹类型 if (isDir && !ignoreDirs.test(item.toLowerCase())) { var child = _fs["default"].readdirSync(fullPath) || []; loopDir(child, fullPath); } else { // 获取后缀 var extname = _path["default"].extname(fullPath); // 只处理vue文件 if (extname === ".vue") { var routeStr = analysisRouteConfig(fullPath); routes.push(routeStr); routesInfo[fullPath] = { data: routeStr, index: routes.length - 1 }; } } }); } function getConfigStr(content) { var setup = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var lc = 0; var power = false; var strCfg = ""; var configReg = setup ? /_config\s*(:\s*\w+)?\s*=\s*/ : /_config\s*:\s*/; // 获取_config配置 try { if (setup) content = content.replace(configReg, "_config = "); content.split("\n").forEach(function (item) { // _config 字段 if (!power && configReg.test(item)) { power = true; } if (!power) return; var strlen = item.length; strCfg += item + "\n"; for (var i = 0; i < strlen; i++) { var str = item[i]; if (str === "{") { lc++; } if (str === "}") { lc--; } } if (lc === 0) { power = false; throw "break"; } }); } catch (e) { if (e === "break") return strCfg; return null; } } /** * @desc 解析vue文件 * @param filepath 文件路径 */ function analysisVue(filepath) { if (!filepath) return; var file = _fs["default"].readFileSync(filepath, { encoding: "utf-8" }); var parseVue = (0, _compilerSfc.parse)(file); try { // 因为在有些特殊情况下 , 比如在script标签中没有任何代码的情况下 , compileScript函数会报错 , 所以放在try中 var _compileScript = (0, _compilerSfc.compileScript)(parseVue.descriptor, { filename: _path["default"].basename(filepath), id: (0, _comm.GUID)() }), content = _compileScript.content, setup = _compileScript.setup; var strCfg = getConfigStr(content, setup); if (setup) { strCfg = strCfg.replace(/^(const|let).*_config\s*=\s*/, 'return'); return new Function("".concat(strCfg))(); } else { return new Function("return {".concat(strCfg, "}"))()._config; } } catch (e) { console.log("analysis vue is null"); return null; } } /** * @desc 解析路由配置 * @param filepath 文件路径 */ function analysisRouteConfig(filepath) { if (!filepath) return; var config = analysisVue(filepath); var rePath = filepath.replace(pages, "/" + _config.pagePath).replaceAll("\\", "/"); // 相对路径 var routePath = rePath.replace("/" + _config.pagePath, "").replace(".vue", ""); // 路由路径 var routePathArr = routePath.split("/"); // 相对路径转数组 var res = ""; var setRoute = function setRoute(r) { var res = null; if (!r) { res = { path: routePath }; } else if (r.path) { // 有path的情况 res = r; } else if (r.name != null) { // 没有path 有name的情况 var len = routePathArr.length; routePathArr[len - 1] = encodeURI(r.name); if (routePathArr[len - 1] === "") routePathArr.pop(); res = Object.assign({ path: routePathArr.join("/") }, r); } else res = Object.assign({ path: routePath }, r); res["component"] = "$[()=>import('@".concat(rePath, "')]$"); return JSON.stringify(res).replace('"$[', "").replace(']$"', ""); }; // 没有配置config的情况 or 没有配置route if (!config || !config.route) { return setRoute(null); } else if (config.route) { if (Array.isArray(config.route)) { var result = []; config.route.forEach(function (item) { result.push(setRoute(item)); }); res = result.join(",\n"); } else res = setRoute(config.route); return res; } } /** * @desc 写入路由 */ function writeRouter() { var config = _fs["default"].readFileSync(_path["default"].join(_comm.basename, "template/route.js"), { encoding: "utf-8" }); if (!_fs["default"].existsSync(routeDir)) _fs["default"].mkdirSync(routeDir); if (!_fs["default"].existsSync(routeDir + "/index.js")) _fs["default"].writeFileSync(routeDir + "/index.js", config, { encoding: "utf-8" });else { var index = _fs["default"].readFileSync(_path["default"].join(routeDir, "index.js"), { encoding: "utf-8" }); if (!/import\s+\w+\s+from\s+"[\w.\/]*config\.js"/.test(index)) { _fs["default"].writeFileSync(routeDir + "/index.js", "import config from \"./config.js\"\n" + index, { encoding: "utf-8" }); } } _fs["default"].writeFileSync(routeDir + "/config.js", "export default [\n\t".concat(routes.join(",\n\t"), "\n]"), { encoding: "utf-8" }); } var CURD = /*#__PURE__*/function () { function CURD() { _classCallCheck(this, CURD); _defineProperty(this, "queue", []); } /** * @desc 当文件被更改 , 执行更新操作 * @param filePath */ _createClass(CURD, [{ key: "update", value: function update(filePath) { var _routesInfo$filePath$; console.log("\n [auto-router] update rending..."); var prev = (_routesInfo$filePath$ = routesInfo[filePath]["data"]) === null || _routesInfo$filePath$ === void 0 ? void 0 : _routesInfo$filePath$.replace(/(\n)/g, ""); var cur = analysisRouteConfig(filePath); var cur_cs = cur.replace(/(\n)/g, ""); var index = routesInfo[filePath]["index"]; if (prev !== cur_cs) { routes[index] = cur; routesInfo[filePath]["data"] = cur; writeRouter(); console.log("[auto-router] updated:", filePath); } } /** * @desc 执行删除操作 * @param filePath * @param cur */ }, { key: "delete", value: function _delete(filePath, cur) { console.log("\n [auto-router] delete rending..."); var keys = Object.keys(routesInfo); for (var _i = 0, _keys = keys; _i < _keys.length; _i++) { var key = _keys[_i]; if (key.indexOf(filePath) > -1) { var index = routesInfo[key].index; routes[index] = null; this.queue.push(index); delete routesInfo[key]; } } writeRouter(); console.log("[auto-router] deleted:", filePath); } /** * @desc 执行新增操作 * @param filePath * @param cur */ }, { key: "create", value: function create(filePath, cur) { var _this = this; console.log("\n [auto-router] create rending..."); var res = this._baseLogic(filePath, cur); if (!res) return; res.forEach(function (item) { // 队列长度 var q_len = _this.queue.length; // 判定队列是否为空 , 如果不为空 , 则出队,否则返回数组长度 // 大致意思是 , 如果routes有空值, 则插入,没有控制则push var index = q_len > 0 ? _this.queue.shift() : routes.length; if (routes[index] != null) loopDir(files, pages);else if (routesInfo[item]) { // ... } else { var routeStr = analysisRouteConfig(item); routesInfo[item] = { data: routeStr, index: index }; routes[index] = routeStr; } }); writeRouter(); console.log("\n [auto-router] created:", filePath); } /** * @desc 主要用于判定路径是否是目录, 如果是目录则深度遍历目录下有没有vue文件 , 如果是vue文件则返回路径 * @param dirPath * @param cur * @return {Array|*} * @private */ }, { key: "_dirHasFiles", value: function _dirHasFiles(dirPath, cur) { if (!cur.isDirectory() && _path["default"].extname(dirPath) === '.vue') return [dirPath]; var q = [dirPath]; var res = []; while (q.length) { // 当前文件夹 var c = q.shift(); var f = _fs["default"].readdirSync(c); var _iterator = _createForOfIteratorHelper(f), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var i = _step.value; var fullPath = _path["default"].join(c, i); if (_fs["default"].statSync(fullPath).isDirectory()) q.push(fullPath);else if (_path["default"].extname(fullPath) === '.vue') { res.push(fullPath); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } } return res; } }, { key: "_baseLogic", value: function _baseLogic(filePath, cur) { if (ignoreDirs.test(filePath.toLowerCase())) return null; var res = this._dirHasFiles(filePath, cur); if (res.length === 0) return null; return res; } }]); return CURD; }(); /** * @desc 监听pages目录 */ function watchPages() { try { files = _fs["default"].readdirSync(pages); } catch (e) { throw new Error("未找到pages文件夹 , 请确认是否配置正确。 尝试使用auto-router set -p <path> 重新设置页面目录!"); } var curd = new CURD(); var exclude = _config.excludeReg ? new RegExp(_config.excludeReg) : null; _watch["default"].watchTree(pages, { interval: 1, ignoreDotFiles: true, ignoreUnreadableDir: true, ignoreNotPermitted: true, ignoreDirectoryPattern: exclude }, function (f, cur, prev) { if (typeof f == 'string') { if (_config.excludePath && _config.excludePath.filter(function (e) { return f.includes(_path["default"].join(e)); }).length) return; if (exclude.test(f) || /~$/.test(f)) return;else if (_config.excludeDir && _config.excludeDir.include(f)) return; } if (_typeof(f) == "object" && prev === null && cur === null) { renderAll(); // 完成对树的遍历 } else if (prev === null) { // f 是一个新文件 curd.create(f, cur); } else if (cur.nlink === 0) { // f 被移除 curd["delete"](f, cur); } else if (prev != null) { curd.update(f); } }); } // 全部渲染pages function renderAll() { console.log("\n[auto-router]rending ..."); try { files = _fs["default"].readdirSync(pages); } catch (e) { throw new Error("未找到pages文件夹 , 请确认是否配置正确。 尝试使用auto-router set -p <path> 重新设置页面目录!"); } loopDir(files, pages); // 轮询目录 , 生成route配置 writeRouter(); // 文件写入 console.log("\n[auto-router]render finished ..."); }