领域模型 DSL设计与解析引擎

领域模型DSL设计与解析引擎技术文档

一、概述

在当前工程中,modeldocs 文件夹承担了领域模型DSL(领域特定语言)设计与解析引擎的核心功能。领域模型DSL允许开发者以特定的、易于理解的语言来描述业务领域的模型,而解析引擎则负责将这些描述转换为可执行的代码或数据结构。本技术文档将详细介绍这两个文件夹中代码的功能、实现原理以及如何使用。

二、文件结构与功能概述

2.1 model 文件夹

model 文件夹包含了多个子文件夹和文件,用于定义不同领域的模型以及相关的项目配置。以下是主要的文件和功能:

  • model/index.js:核心解析引擎,负责遍历所有模型和项目配置文件,将项目配置继承自模型配置,并返回最终的模型列表。
  • model/buinessmodel/course 等子文件夹 :不同领域的模型定义,每个子文件夹下包含 model.js 定义通用模型,以及 project 子文件夹下的具体项目配置。

2.2 docs 文件夹

docs 文件夹包含了与领域模型相关的文档和示例,如 dashboard-model.js 定义了仪表盘模型的结构,为开发者提供了清晰的模型定义规范。

三、核心功能实现

3.1 模型配置继承

model/index.js 中,实现了项目配置继承模型配置的功能。核心函数 projectExtendModel 用于处理配置的合并:

js 复制代码
const glob = require("glob");
const path = require("path");
const { sep } = path;
const _ = require("lodash");

/**
 * 继承 model 配置
 * @param {*} model 模型配置
 * @param {*} project 项目配置
 */
const projectExtendModel = (model, project) => {
  return _.mergeWith({}, model, project, (modelValue, projectValue) => {
    // 处理数据合并的特殊情况
    if (Array.isArray(modelValue) && Array.isArray(projectValue)) {
      let result = [];

      // project 继承 model, 所以需要处理修改和新增的内容情况 [menu中的值比对]
      // project中有键值,model也有 => 修改(重载)  递归调用 projectExtendModel 方法覆盖
      // project中没有键值,model中有键值 => 保留(继承)
      // project中有键值,model没有 => 新增(拓展)

      // 处理修改和保留
      for (let i = 0; i < modelValue.length; i++) {
        let modelItem = modelValue[i];
        const projItem = projectValue.find(
          (projItem) => projItem.key === modelItem.key
        );
        // project中存在的key,model中也存在,则递归调用 projectExtendModel 方法覆盖修改
        result.push(
          projItem ? projectExtendModel(modelItem, projItem) : modelItem
        );
      }
      // 处理新增
      for (let i = 0; i < projectValue.length; i++) {
        let projItem = projectValue[i];
        const modelItem = modelValue.find(
          (modelItem) => modelItem.key === projItem.key
        );
        if (!modelItem) {
          result.push(projItem);
        }
      }
      return result;
    }
  });
};

3.2 模型解析与整理

model/index.js 中的 module.exports 函数负责遍历所有模型和项目配置文件,将它们解析并整理成最终的模型列表:

js 复制代码
/**
 * 解析 model 模型配置,并返回 menu 菜单配置
 * @example return 
 *  [
      {
        model: { model: 'dashboard', name: '电商系统', menu: [Array], key: 'buiness' },
        project: { echomarket: [Object], shopnest: [Object] }
      },
      {
        model: { model: 'dashboard', name: '教育系统', menu: [Array], key: 'course' },
        project: { learnly: [Object], scholarly: [Object] }
      }
    ]
 */
module.exports = (app) => {
  const modelList = [];

  // 遍历当前文件夹,构造模型数据结构,挂载到modelList上
  const modelPath = path.resolve(app.baseDir, `.${sep}model`);
  const fileList = glob.sync(path.resolve(modelPath, `.${sep}**${sep}**.js`));
  fileList.forEach((file) => {
    if (file.indexOf("index.js") > -1) return;

    // 区分配置类型 [model / project]
    const type = file.indexOf(`project`) > -1 ? "project" : "model";

    if (type === "project") {
      const modelKey = file.match(/\/model\/(.*?)\/project/)?.[1];
      const projKey = file.match(/\/project\/(.*?)\.js/)?.[1];
      let modelItem = modelList.find((item) => item.model?.key === modelKey);
      if (!modelItem) {
        //初始化 model 数据结构
        modelItem = {};
        modelList.push(modelItem);
      }
      if (!modelItem.project) {
        //初始化 project 数据结构
        modelItem.project = {};
      }
      modelItem.project[projKey] = require(path.resolve(file));
      modelItem.project[projKey].key = projKey; // 注入 projectKey
    }
    if (type === "model") {
      const modelKey = file.match(/\/model\/(.*?)\/model\.js/)?.[1];

      let modelItem = modelList.find((item) => item.model?.key === modelKey);
      if (!modelItem) {
        //初始化 model 数据结构
        modelItem = {};
        modelList.push(modelItem);
      }
      modelItem.model = require(path.resolve(file));
      modelItem.model.key = modelKey; // 注入 modelKey
    }
  });

  // 整理 project => 继承 model
  modelList.forEach((item) => {
    const { model, project } = item;
    for (const key in project) {
      project[key] = projectExtendModel(model, project[key]);
    }
  });
  return modelList;
};

3.3 模型定义规范

docs/dashboard-model.js 提供了仪表盘模型的定义规范,开发者可以根据这个规范来定义自己的模型:

js 复制代码
{
  mode: "dashboard", // 模板类型,不同模板类型对应不一样的模板数据结构
  name: "", // 模板名称
  desc: "", // 模板描述
  icon: "", // 模板图标
  homePage: "", // 模板首页地址
  menu: [
    {
      key: "", // 菜单key
      name: "", // 菜单名称
      menuType: "", // 菜单类型 枚举值:group / module

      // 当 menuType === group 可配置子菜单
      submenu: [
        {
          // 可递归 submenuItem
        },
      ],

      // 当 menuType === module 可配置模块信息
      moduleType: "", // 模块类型 枚举值:sider / iframe / custom / schema

      // 当 moduleType === sider 可配置 侧边栏信息
      siderConfig: {
        menu: [
          {
            // 可递归 sidermenuItem
          },
        ],
      }, // 侧边栏地址

      // 当 moduleType === iframe 可配置 iframe 信息
      iframeConfig: {
        path: "", //iframe 路径
      }, // iframe 地址

      // 当 moduleType === cutom 可配置 自定义模块信息
      customConfig: {
        path: "", // 自定义路由路径
      }, // 自定义模块地址

      // 当 moduleType === schema 可配置 schema 信息
      schemaConfig: {
        api: "", // 数据源API[遵循 RESTFUL 规范]
        schema: {
          // 板块数据结构
          type: "object",
          properties: {
            key: {
              ...schema, // 标准的 schema 配置
              type: "", //字段类型
              label: "", //字段中文名
            },
          },
        },
        tableConfig: {}, // table 表格配置
        searchConfig: {}, // search-bar 搜索相关配置
        components: {}, // 模块组件
      },
    },
  ];
}

四、使用方法

4.1 定义模型

开发者可以在 model 文件夹下的不同子文件夹中定义模型和项目配置。例如,在 model/buiness 文件夹中:

  • model.js 定义通用的业务模型:
js 复制代码
module.exports = {
  model: "dashboard",
  name: "电商系统",
  menu: [
    {
      key: "product",
      name: "商品管理",
      menuType: "module",
      moduleType: "custom",
      customConfig: {
        path: "/todo",
      },
    },
    // 其他菜单配置...
  ],
};
  • project 子文件夹下的具体项目配置:
js 复制代码
module.exports = {
  name: "口碑商城",
  desc: "一家非常注重用户评价的购物商城",
  homePage: "",
  menu: [
    {
      key: "operating",
      name: "运营活动",
      menuType: "module",
      moduleType: "sider",
      siderConfig: {
        menu: [
          {
            key: "coupon",
            name: "优惠券",
            menuType: "module",
            customConfig: {
              path: "/todo",
            },
          },
          // 其他侧边栏菜单配置...
        ],
      },
    },
  ],
};

4.2 解析数据

通过 model/index.js解析引擎,对model/buiness电商系统和model/course教育系统2个模拟板块项目进行解析, 获得约定模型数据源:

4.2.1 模型数据结构
js 复制代码
[
  {
    model: { model: 'dashboard', name: '电商系统', menu: [Array], key: 'buiness' },
    project: { echomarket: [Object], shopnest: [Object] }
  },
  {
    model: { model: 'dashboard', name: '教育系统', menu: [Array], key: 'course' },
    project: { learnly: [Object], scholarly: [Object] }
  }
]
4.2.2 模型数据源
json 复制代码
[
  {
    "model": {
      "model": "dashboard",
      "name": "电商系统",
      "menu": [
        {
          "key": "product",
          "name": "商品管理",
          "menuType": "module",
          "moduleType": "custom",
          "customConfig": {
            "path": "/todo"
          }
        },
        {
          "key": "order",
          "name": "订单管理",
          "menuType": "module",
          "moduleType": "custom",
          "customConfig": {
            "path": "/todo"
          }
        },
        {
          "key": "client",
          "name": "客户管理",
          "menuType": "module",
          "moduleType": "custom",
          "customConfig": {
            "path": "/todo"
          }
        }
      ],
      "key": "buiness"
    },
    "project": {
      "echomarket": {
        "model": "dashboard",
        "name": "口碑商城",
        "menu": [
          {
            "key": "product",
            "name": "商品管理",
            "menuType": "module",
            "moduleType": "custom",
            "customConfig": {
              "path": "/todo"
            }
          },
          {
            "key": "order",
            "name": "订单管理",
            "menuType": "module",
            "moduleType": "custom",
            "customConfig": {
              "path": "/todo"
            }
          },
          {
            "key": "client",
            "name": "客户管理",
            "menuType": "module",
            "moduleType": "custom",
            "customConfig": {
              "path": "/todo"
            }
          },
          {
            "key": "operating",
            "name": "运营活动",
            "menuType": "module",
            "moduleType": "sider",
            "siderConfig": {
              "menu": [
                {
                  "key": "coupon",
                  "name": "优惠券",
                  "menuType": "module",
                  "customConfig": {
                    "path": "/todo"
                  }
                },
                {
                  "key": "limited",
                  "name": "限量购",
                  "menuType": "module",
                  "customConfig": {
                    "path": "/todo"
                  }
                },
                {
                  "key": "festival",
                  "name": "节日活动",
                  "menuType": "module",
                  "customConfig": {
                    "path": "/todo"
                  }
                }
              ]
            }
          }
        ],
        "key": "echomarket",
        "desc": "一家非常注重用户评价的购物商城",
        "homePage": ""
      },
      "shopnest": {
        "model": "dashboard",
        "name": "购物巢穴",
        "menu": [
          {
            "key": "product",
            "name": "商品清单",
            "menuType": "module",
            "moduleType": "custom",
            "customConfig": {
              "path": "/todo"
            }
          },
          {
            "key": "order",
            "name": "订单管理",
            "menuType": "module",
            "moduleType": "custom",
            "customConfig": {
              "path": "/todo"
            }
          },
          {
            "key": "client",
            "name": "客户清单",
            "menuType": "module",
            "moduleType": "custom",
            "customConfig": {
              "path": "/todo"
            }
          },
          {
            "key": "search",
            "name": "信息查询",
            "moduleType": "iframe",
            "iframeConfig": {
              "path": "https://www.taobao.com"
            }
          },
          {
            "key": "data",
            "name": "数据分析",
            "menuType": "module",
            "moduleType": "sider",
            "sideConfig": {
              "menu": [
                {
                  "key": "analysis",
                  "name": "电商罗盘",
                  "menuType": "module",
                  "moduleType": "custom",
                  "customConfig": {
                    "path": "/todo"
                  }
                },
                {
                  "key": "sider-search",
                  "name": "信息查询",
                  "moduleType": "iframe",
                  "iframeConfig": {
                    "path": "https://www.baidu.com"
                  }
                }
              ]
            }
          }
        ],
        "key": "shopnest",
        "desc": "一个注入像家一样温馨购物环境的超市",
        "homePage": ""
      }
    }
  },
  {
    "model": {
      "model": "dashboard",
      "name": "教育系统",
      "menu": [
        {
          "key": "video",
          "name": "视频管理",
          "menuType": "module",
          "moduleType": "custom",
          "customConfig": {
            "path": "/todo"
          }
        },
        {
          "key": "user",
          "name": "用户管理",
          "menuType": "module",
          "moduleType": "custom",
          "customConfig": {
            "path": "/todo"
          }
        }
      ],
      "key": "course"
    },
    "project": {
      "learnly": {
        "model": "dashboard",
        "name": "现代教育",
        "menu": [
          {
            "key": "video",
            "name": "视频管理",
            "menuType": "module",
            "moduleType": "custom",
            "customConfig": {
              "path": "/todo"
            }
          },
          {
            "key": "user",
            "name": "用户管理",
            "menuType": "module",
            "moduleType": "custom",
            "customConfig": {
              "path": "/todo"
            }
          },
          {
            "key": "traffic",
            "name": "流量管理",
            "menuType": "module",
            "moduleType": "sider",
            "siderConfig": {
              "menu": [
                {
                  "key": "user-traffic",
                  "name": "学员流量",
                  "menuType": "module",
                  "moduleType": "custom",
                  "customConfig": {
                    "path": "/todo"
                  }
                }
              ]
            }
          }
        ],
        "key": "learnly",
        "desc": "一家前沿现代教育平台系统",
        "homePage": ""
      },
      "scholarly": {
        "model": "dashboard",
        "name": "学者教育",
        "menu": [
          {
            "key": "video",
            "name": "视频管理",
            "menuType": "module",
            "moduleType": "custom",
            "customConfig": {
              "path": "/todo"
            }
          },
          {
            "key": "user",
            "name": "用户管理",
            "menuType": "module",
            "moduleType": "custom",
            "customConfig": {
              "path": "/todo"
            }
          },
          {
            "key": "coursematerials",
            "name": "课程资料",
            "menuType": "module",
            "moduleType": "sider",
            "siderConfig": {
              "menu": [
                {
                  "key": "pdf",
                  "name": "PDF",
                  "menuType": "module",
                  "moduleType": "custom",
                  "customConfig": {
                    "path": "/todo"
                  }
                },
                {
                  "key": "excel",
                  "name": "EXCEL",
                  "menuType": "module",
                  "moduleType": "custom",
                  "customConfig": {
                    "path": "/todo"
                  }
                },
                {
                  "key": "ppt",
                  "name": "PPT",
                  "menuType": "module",
                  "moduleType": "custom",
                  "customConfig": {
                    "path": "/todo"
                  }
                },
                {
                  "key": "word",
                  "name": "WORD",
                  "menuType": "module",
                  "moduleType": "custom",
                  "customConfig": {
                    "path": "/todo"
                  }
                }
              ]
            }
          }
        ],
        "key": "scholarly",
        "desc": "一家学术类教育平台系统",
        "homePage": ""
      }
    }
  }
]

4.3 参考文档

开发者可以参考 docs/dashboard-model.js 中的模型定义规范,确保自己定义的模型符合要求。

五、总结

通过 modeldocs 文件夹的设计,我们实现了一个灵活的领域模型DSL设计与解析引擎。开发者可以方便地定义不同领域的模型和项目配置,并且通过解析引擎将这些配置转换为可使用的模型列表。同时,文档提供了清晰的模型定义规范,帮助开发者更好地理解和使用这个系统。

相关推荐
招风的黑耳15 分钟前
Web元件库 ElementUI元件库+后台模板页面(支持Axure9、10、11)
前端·elementui·axure
雯0609~16 分钟前
CSS:使用内边距时,解决宽随之改变问题
前端·css
Dolphin_海豚27 分钟前
10 分钟带你入坑 electron
前端·javascript·electron
乐闻x37 分钟前
性能优化:javascript 如何检测并处理页面卡顿
前端·javascript·性能优化
雯0609~42 分钟前
vue3:八、登录界面实现-忘记密码
前端·javascript·vue.js
烂蜻蜓1 小时前
深入理解 HTML 中的<div>和元素:构建网页结构与样式的基石
开发语言·前端·css·html·html5
木木黄木木1 小时前
HTML5 Canvas弹跳小球游戏开发实战与技术分析
前端·html·html5
Anlici2 小时前
Axios 是基于 Ajax 还是 Fetch?从源码解析其实现
前端·面试
一个处女座的程序猿O(∩_∩)O2 小时前
Vue 中的 MVVM、MVC 和 MVP 模式深度解析
前端·vue.js·mvc
鱼樱前端2 小时前
前端程序员集体破防!AI工具same.dev像素级抄袭你的代码,你还能高傲多久?
前端·javascript·后端