领域模型 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设计与解析引擎。开发者可以方便地定义不同领域的模型和项目配置,并且通过解析引擎将这些配置转换为可使用的模型列表。同时,文档提供了清晰的模型定义规范,帮助开发者更好地理解和使用这个系统。

相关推荐
Larcher19 分钟前
新手也能学会,100行代码玩AI LOGO
前端·llm·html
徐子颐32 分钟前
从 Vibe Coding 到 Agent Coding:Cursor 2.0 开启下一代 AI 开发范式
前端
小月鸭44 分钟前
如何理解HTML语义化
前端·html
jump6801 小时前
url输入到网页展示会发生什么?
前端
诸葛韩信1 小时前
我们需要了解的Web Workers
前端
brzhang1 小时前
我觉得可以试试 TOON —— 一个为 LLM 而生的极致压缩数据格式
前端·后端·架构
yivifu2 小时前
JavaScript Selection API详解
java·前端·javascript
这儿有一堆花2 小时前
告别 Class 组件:拥抱 React Hooks 带来的函数式新范式
前端·javascript·react.js
十二春秋2 小时前
场景模拟:基础路由配置
前端
六月的可乐2 小时前
实战干货-Vue实现AI聊天助手全流程解析
前端·vue.js·ai编程