momo-ai 1.0.24 → 1.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "momo-ai",
3
- "version": "1.0.24",
3
+ "version": "1.0.25",
4
4
  "description": "Rachel Momo ( OpenSpec )",
5
5
  "main": "src/momo.js",
6
6
  "bin": {
@@ -1,4 +1,4 @@
1
- const program = require('commander');
1
+ const { program } = require('commander');
2
2
  const U = require('underscore');
3
3
  const co = require('co');
4
4
  const Immutable = require('immutable');
@@ -1,4 +1,4 @@
1
- const program = require('commander');
1
+ const { program } = require('commander');
2
2
  const U = require('underscore');
3
3
  const co = require('co');
4
4
  const Immutable = require('immutable');
@@ -96,6 +96,8 @@ const executeBody = (commanders = [], Executor = {}) => {
96
96
  cmd.option(`--${option.name}`, option.description);
97
97
  })
98
98
  });
99
+ // 允许多余参数,避免 -e false / -d ./path 等被当作非法位置参数报错
100
+ cmd.allowExcessArguments(true);
99
101
  cmd.action(() => co(() => executor(commander.options)));
100
102
  });
101
103
  }
@@ -1,8 +1,11 @@
1
- const { spawn } = require('child_process');
1
+ const { spawn, execSync } = require('child_process');
2
2
  const fs = require('fs');
3
3
  const path = require('path');
4
+ const fsAsync = require('fs').promises;
4
5
  const Ec = require('../epic');
5
6
  const { parseOptional } = require('../utils/momo-args');
7
+ const { exists, gitClone } = require('../utils/momo-file-utils');
8
+ const { SPEC_REPO_URL, LOCAL_CACHE_DIR, GITIGNORE_ENTRY } = require('../utils/momo-repo-spec');
6
9
 
7
10
  // 脚本路径(相对于项目根目录)
8
11
  const SCRIPT_PATH_DOMAIN = 'src/python/r2mo_proto_domain.py';
@@ -49,6 +52,58 @@ const _parsePomXml = (pomPath) => {
49
52
  }
50
53
  };
51
54
 
55
+ /**
56
+ * 检查仓库是否是最新的
57
+ * @param {string} repoPath 仓库路径
58
+ * @returns {boolean}
59
+ */
60
+ const _isRepositoryUpToDate = (repoPath) => {
61
+ try {
62
+ execSync(`cd "${repoPath}" && git fetch --quiet origin`, { stdio: 'ignore' });
63
+ const remoteCommit = execSync(`cd "${repoPath}" && git rev-parse origin/HEAD`, { encoding: 'utf8' }).trim();
64
+ const localCommit = execSync(`cd "${repoPath}" && git rev-parse HEAD`, { encoding: 'utf8' }).trim();
65
+ return remoteCommit === localCommit;
66
+ } catch {
67
+ return false;
68
+ }
69
+ };
70
+
71
+ /**
72
+ * 克隆或更新 .r2mo/repo 仓库(与 mmr0/mmr2 共享)
73
+ * @param {string} projectDir 项目根目录
74
+ * @returns {Promise<string>} 仓库路径
75
+ */
76
+ const _cloneOrUpdateRepository = async (projectDir) => {
77
+ const repoPath = path.join(projectDir, LOCAL_CACHE_DIR);
78
+
79
+ if (exists(repoPath)) {
80
+ Ec.waiting('正在检查仓库状态...');
81
+ if (_isRepositoryUpToDate(repoPath)) {
82
+ Ec.info('✓ 仓库已是最新版本,无需更新');
83
+ return repoPath;
84
+ }
85
+ try {
86
+ Ec.waiting('正在更新仓库...');
87
+ execSync(`cd "${repoPath}" && git pull --quiet`, { stdio: 'ignore' });
88
+ Ec.info('✓ 仓库已更新');
89
+ } catch (error) {
90
+ Ec.warn('⚠ 更新失败,尝试重新克隆...');
91
+ await fsAsync.rm(repoPath, { recursive: true, force: true });
92
+ Ec.waiting('正在克隆仓库...');
93
+ await fsAsync.mkdir(path.dirname(repoPath), { recursive: true });
94
+ gitClone(SPEC_REPO_URL, repoPath, { shallow: true });
95
+ Ec.info('✓ 仓库已克隆');
96
+ }
97
+ } else {
98
+ Ec.waiting('正在克隆仓库...');
99
+ await fsAsync.mkdir(path.dirname(repoPath), { recursive: true });
100
+ gitClone(SPEC_REPO_URL, repoPath, { shallow: true });
101
+ Ec.info('✓ 仓库已克隆');
102
+ }
103
+
104
+ return repoPath;
105
+ };
106
+
52
107
  /**
53
108
  * 验证 Maven 项目结构
54
109
  * @param {string} targetDir 目标目录
@@ -225,6 +280,29 @@ module.exports = async (options) => {
225
280
  Ec.info(`✓ Maven 项目验证通过`);
226
281
  Ec.info(` 项目 ID: ${validation.artifactId.cyan}`);
227
282
  Ec.info(` 找到模块: ${validation.artifactId}-domain`.green);
283
+
284
+ // 与 mmr0/mmr2 共享 .r2mo/repo:确保仓库存在并可选更新
285
+ Ec.waiting('正在检查 .r2mo/repo 仓库...');
286
+ const gitAvailable = await _isCommandAvailable('git');
287
+ if (!gitAvailable) {
288
+ Ec.warn('⚠ 未找到 git 命令,将跳过仓库拉取;若本地无 .r2mo/repo,文档注释可能缺失');
289
+ } else {
290
+ const gitignorePath = path.join(targetDir, '.gitignore');
291
+ if (exists(gitignorePath)) {
292
+ const content = fs.readFileSync(gitignorePath, 'utf8');
293
+ const lines = content.split('\n');
294
+ const hasEntry = lines.some(line => line.trim() === GITIGNORE_ENTRY);
295
+ if (!hasEntry) {
296
+ const newContent = content.endsWith('\n') || content === ''
297
+ ? content + GITIGNORE_ENTRY + '\n'
298
+ : content + '\n' + GITIGNORE_ENTRY + '\n';
299
+ fs.writeFileSync(gitignorePath, newContent);
300
+ }
301
+ } else {
302
+ fs.writeFileSync(gitignorePath, GITIGNORE_ENTRY + '\n');
303
+ }
304
+ await _cloneOrUpdateRepository(targetDir);
305
+ }
228
306
  } else {
229
307
  // Database 模式:检查是否有 flyway 目录
230
308
  Ec.waiting('正在检查 Flyway SQL 文件...');
@@ -5,12 +5,9 @@ const fsAsync = require('fs').promises;
5
5
  const { execSync } = require('child_process');
6
6
  const { parseFile, exists, gitClone } = require('../utils/momo-file-utils');
7
7
  const { selectSingle, selectMultiple } = require('../utils/momo-menu');
8
+ const { SPEC_REPO_URL, LOCAL_CACHE_DIR, GITIGNORE_ENTRY } = require('../utils/momo-repo-spec');
8
9
  require('colors');
9
10
 
10
- // 仓库配置
11
- const SPEC_REPO_URL = 'https://gitee.com/silentbalanceyh/r2mo-spec.git';
12
- const LOCAL_CACHE_DIR = '.r2mo/repo/r2mo-spec';
13
-
14
11
  /**
15
12
  * 检查命令是否可用
16
13
  */
@@ -280,21 +277,20 @@ module.exports = async (options) => {
280
277
  process.exit(1);
281
278
  }
282
279
 
283
- // 2. 确保 .r2mo/repo 在 .gitignore
280
+ // 2. 确保 .r2mo/repo 在 .gitignore 中(与 domain/mmr2 共享目录一致)
284
281
  const gitignorePath = path.join(projectDir, '.gitignore');
285
- const ignoreEntry = '.r2mo/repo';
286
282
  if (exists(gitignorePath)) {
287
283
  const content = fs.readFileSync(gitignorePath, 'utf8');
288
284
  const lines = content.split('\n');
289
- const hasEntry = lines.some(line => line.trim() === ignoreEntry);
285
+ const hasEntry = lines.some(line => line.trim() === GITIGNORE_ENTRY);
290
286
  if (!hasEntry) {
291
- const newContent = content.endsWith('\n') || content === ''
292
- ? content + ignoreEntry + '\n'
293
- : content + '\n' + ignoreEntry + '\n';
287
+ const newContent = content.endsWith('\n') || content === ''
288
+ ? content + GITIGNORE_ENTRY + '\n'
289
+ : content + '\n' + GITIGNORE_ENTRY + '\n';
294
290
  fs.writeFileSync(gitignorePath, newContent);
295
291
  }
296
292
  } else {
297
- fs.writeFileSync(gitignorePath, ignoreEntry + '\n');
293
+ fs.writeFileSync(gitignorePath, GITIGNORE_ENTRY + '\n');
298
294
  }
299
295
 
300
296
  // 3. 克隆或更新仓库
@@ -5,12 +5,9 @@ const fsAsync = require('fs').promises;
5
5
  const { execSync } = require('child_process');
6
6
  const { parseFile, exists, gitClone, scanDir } = require('../utils/momo-file-utils');
7
7
  const { selectSingle, selectMultiple } = require('../utils/momo-menu');
8
+ const { SPEC_REPO_URL, LOCAL_CACHE_DIR, GITIGNORE_ENTRY } = require('../utils/momo-repo-spec');
8
9
  require('colors');
9
10
 
10
- // 仓库配置
11
- const SPEC_REPO_URL = 'https://gitee.com/silentbalanceyh/r2mo-spec.git';
12
- const LOCAL_CACHE_DIR = '.r2mo/repo/r2mo-spec';
13
-
14
11
  // BaseEntity 中已存在的字段(不需要重复生成)
15
12
  // 注意:需要同时检查下划线命名(SQL 格式)和驼峰命名(Java 格式)
16
13
  const BASE_ENTITY_FIELDS = new Set([
@@ -660,21 +657,20 @@ module.exports = async (options) => {
660
657
  process.exit(1);
661
658
  }
662
659
 
663
- // 2. 确保 .r2mo/repo 在 .gitignore
660
+ // 2. 确保 .r2mo/repo 在 .gitignore 中(与 domain/mmr0 共享目录一致)
664
661
  const gitignorePath = path.join(projectDir, '.gitignore');
665
- const ignoreEntry = '.r2mo/repo';
666
662
  if (exists(gitignorePath)) {
667
663
  const content = fs.readFileSync(gitignorePath, 'utf8');
668
664
  const lines = content.split('\n');
669
- const hasEntry = lines.some(line => line.trim() === ignoreEntry);
665
+ const hasEntry = lines.some(line => line.trim() === GITIGNORE_ENTRY);
670
666
  if (!hasEntry) {
671
- const newContent = content.endsWith('\n') || content === ''
672
- ? content + ignoreEntry + '\n'
673
- : content + '\n' + ignoreEntry + '\n';
667
+ const newContent = content.endsWith('\n') || content === ''
668
+ ? content + GITIGNORE_ENTRY + '\n'
669
+ : content + '\n' + GITIGNORE_ENTRY + '\n';
674
670
  fs.writeFileSync(gitignorePath, newContent);
675
671
  }
676
672
  } else {
677
- fs.writeFileSync(gitignorePath, ignoreEntry + '\n');
673
+ fs.writeFileSync(gitignorePath, GITIGNORE_ENTRY + '\n');
678
674
  }
679
675
 
680
676
  // 3. 克隆或更新仓库
@@ -2,20 +2,19 @@
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
4
  """
5
- R2MO SQL to Protobuf Converter (V2 - Enhanced Java Property & Constraints)
5
+ R2MO SQL to Protobuf Converter (V4 - Shared .r2mo/repo & Note Properties)
6
6
  从 Flyway SQL 脚本生成 Protobuf 文件
7
7
  更新内容:
8
- 1. 【修复】中文注释提取 BUG:正确解析「javaProperty」- 描述格式
9
- 2. 【强化】Java 属性名保留:从 COMMENT 的「」中提取并附加到注释 [Java:xxx]
10
- 3. 【强化】约束规范化:必填、唯一、主键、默认值、最大长度等统一格式
11
- 4. 【强化】仅扫描 src/main/resources 下的 flyway/MYSQL(排除 target/classes)
12
- 5. 【优化】逐行解析,支持多行注释过滤和行尾 -- 补充描述
8
+ 1. 【共享】与 momo mmr0/mmr2/domain 共用 .r2mo/repo 仓库;按 message 名称检索 XApp.md
9
+ 2. 【注释】将文档头部的笔记属性(front-matter)完整追加到 message 的注释中(与 domain 一致)
10
+ 3. 【保留】中文注释「javaProperty」- 描述、[Java:xxx]、约束规范化等 V3 特性
13
11
  """
14
12
 
15
13
  import os
16
14
  import re
17
15
  import sys
18
16
  import argparse
17
+ import yaml
19
18
 
20
19
  # ================= 1. 配置与映射表 =================
21
20
 
@@ -55,6 +54,49 @@ def extract_sql_type(type_def):
55
54
  match = re.match(r'([A-Z]+)', type_def.upper())
56
55
  return match.group(1) if match else 'VARCHAR'
57
56
 
57
+
58
+ def _find_repo_doc(message_name, project_root):
59
+ """
60
+ 从 .r2mo/repo/r2mo-spec 仓库中查找 {message_name}.md 文档。
61
+ 返回: (front-matter dict, 命中的文件名) 或 (None, None)
62
+ """
63
+ repo_path = os.path.join(project_root, '.r2mo', 'repo', 'r2mo-spec')
64
+ if not os.path.isdir(repo_path):
65
+ return None, None
66
+ for root, dirs, files in os.walk(repo_path):
67
+ for f in files:
68
+ if f.lower() == f'{message_name.lower()}.md':
69
+ md_file = os.path.join(root, f)
70
+ try:
71
+ with open(md_file, 'r', encoding='utf-8') as fp:
72
+ content = fp.read()
73
+ m = re.match(r'^---\s*\n(.*?)\n---\s*\n', content, re.DOTALL)
74
+ if m:
75
+ yaml_text = m.group(1)
76
+ attrs = yaml.safe_load(yaml_text)
77
+ if isinstance(attrs, dict):
78
+ return attrs, os.path.basename(md_file)
79
+ except Exception:
80
+ pass
81
+ return None, None
82
+
83
+
84
+ def _build_message_comment(attrs):
85
+ """
86
+ 将文档头部的所有 front-matter 属性解析到注释中,每个属性一行,格式为 key: value。
87
+ 与 r2mo_proto_domain 保持一致。
88
+ """
89
+ if not attrs or not isinstance(attrs, dict):
90
+ return []
91
+ lines = []
92
+ for k, v in attrs.items():
93
+ if v is None or v == '':
94
+ continue
95
+ if isinstance(v, (list, dict)):
96
+ v = str(v)[:80]
97
+ lines.append(f"{k}: {v}")
98
+ return lines
99
+
58
100
  def extract_comment_parts(comment):
59
101
  """
60
102
  从 COMMENT 提取:Java属性名(「xxx」)、中文描述(- 后面的内容)
@@ -203,26 +245,37 @@ def parse_create_table(sql_content):
203
245
  'fields': fields
204
246
  }
205
247
 
206
- def generate_proto_from_table(table_info, java_package="domain"):
248
+ def generate_proto_from_table(table_info, java_package="domain", project_root=None):
207
249
  """
208
250
  从表信息生成 Proto 文件内容。
209
- java_package: 与 jOOQ 生成的 domain pojos 包一致,用于 option java_package 和 Generated from 注释。
251
+ java_package: 与 jOOQ 生成的 domain pojos 包一致。
252
+ project_root: 项目根目录,用于在 .r2mo/repo 中检索 {MessageName}.md 并追加笔记属性到注释;默认 getcwd()。
210
253
  """
211
254
  table_name = table_info['table_name']
212
255
  fields = table_info['fields']
213
256
  message_name = snake_to_pascal(table_name)
214
-
257
+ root = project_root if project_root is not None else os.getcwd()
258
+
215
259
  lines = [
216
260
  'syntax = "proto3";',
217
261
  'package domain;',
218
262
  '',
219
263
  f'// Generated from {java_package}.{message_name}',
264
+ ]
265
+ # 从 .r2mo/repo 检索 {MessageName}.md,将文档头部的笔记属性追加到 message 注释(与 domain 一致)
266
+ doc_attrs, found_md = _find_repo_doc(message_name, root)
267
+ if doc_attrs and found_md:
268
+ for comment_line in _build_message_comment(doc_attrs):
269
+ if comment_line:
270
+ lines.append(f'// {comment_line}')
271
+ print(f" ✓ {message_name}: 已从 {found_md} 追加笔记属性到注释")
272
+ lines.extend([
220
273
  f'option java_package = "{java_package}";',
221
274
  'option java_multiple_files = true;',
222
275
  '',
223
276
  f'message {message_name} {{'
224
- ]
225
-
277
+ ])
278
+
226
279
  for idx, field in enumerate(fields, 1):
227
280
  comment_suffix = f' // {field["comment"]}' if field["comment"] else ''
228
281
  lines.append(f' {field["type"]} {field["name"]} = {idx};{comment_suffix}')
@@ -300,7 +353,7 @@ def main():
300
353
  sys.exit(1)
301
354
 
302
355
  # 查找所有 flyway 目录
303
- print(f"🚀 R2MO Proto Generator (V2 - Flyway SQL Mode)")
356
+ print(f"🚀 R2MO Proto Generator (V4 - Flyway SQL Mode, .r2mo/repo docs)")
304
357
  print(f" Scanning: {input_dir}")
305
358
  print("-" * 40)
306
359
 
@@ -2,14 +2,13 @@
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
4
  """
5
- R2MO Java Domain to Protobuf Converter (V9 - Enhanced Java Property & Constraints)
5
+ R2MO Java Domain to Protobuf Converter (V11 - Shared .r2mo/repo & Note Properties)
6
6
  从 Java Domain 实体类生成 Protobuf 文件
7
7
  更新内容:
8
- 1. 【强化】Java 属性名追加到注释:proto 字段用下划线,注释中保留原始驼峰名 [Java:xxx]
9
- 2. 【强化】约束格式规范化:长度、必填、数值范围等统一为"中文:值"格式
10
- 3. 【强化】更全面的注解支持:@Pattern、@DecimalMax/Min、@ApiModelProperty
11
- 4. 【强化】注释提取优先级:@Schema > JavaDoc > 行内注释
12
- 5. 保留所有 V8 特性(jOOQ Getter 提取、BaseEntity 补全、自动导入)
8
+ 1. 【共享】与 momo mmr0/mmr2 共用 .r2mo/repo 仓库;momo domain 执行前会克隆/更新该仓库
9
+ 2. 【检索】在仓库中按 message 名称(如 XApp)查找对应 XApp.md 文件
10
+ 3. 【注释】将文档头部的笔记属性(front-matter)完整追加到 message 的注释中(首行主描述,其余 key: value)
11
+ 4. 【保留】Java 属性名 [Java:xxx]、约束规范化、V9/V10 特性
13
12
  """
14
13
 
15
14
  import os
@@ -17,6 +16,7 @@ import re
17
16
  import sys
18
17
  import argparse
19
18
  import xml.etree.ElementTree as ET
19
+ import yaml
20
20
 
21
21
  # ================= 1. 配置与映射表 =================
22
22
 
@@ -73,6 +73,70 @@ def get_package_name(content):
73
73
  match = re.search(r'package\s+([\w\.]+);', content)
74
74
  return match.group(1) if match else "domain"
75
75
 
76
+
77
+ def _read_md_front_matter(md_path):
78
+ """只提取 .md 文件头部 front-matter,返回 (attrs dict, 文件名) 或 (None, None)。"""
79
+ if not os.path.isfile(md_path):
80
+ return None, None
81
+ try:
82
+ with open(md_path, 'r', encoding='utf-8') as fp:
83
+ content = fp.read()
84
+ m = re.match(r'^---\s*\n(.*?)\n---\s*\n', content, re.DOTALL)
85
+ if m:
86
+ attrs = yaml.safe_load(m.group(1))
87
+ if isinstance(attrs, dict):
88
+ return attrs, os.path.basename(md_path)
89
+ except Exception:
90
+ pass
91
+ return None, None
92
+
93
+
94
+ def _find_doc_for_java(message_name, java_file_path, project_root):
95
+ """
96
+ 查找与 Java 类对应的 .md 文档,只提取头部 front-matter。
97
+ 1)优先:与 Java 同目录的同名 .md(如 Order.java 同目录的 Order.md)
98
+ 2)回退:.r2mo/repo/r2mo-spec 中 {message_name}.md 或去掉 Entity 的 {name}.md
99
+ 返回: (front-matter dict, 命中的文件名) 或 (None, None)
100
+ """
101
+ # 1)与 Java 同目录的 {ClassName}.md
102
+ if java_file_path and os.path.isfile(java_file_path):
103
+ same_dir = os.path.dirname(java_file_path)
104
+ same_dir_md = os.path.join(same_dir, f'{message_name}.md')
105
+ attrs, found = _read_md_front_matter(same_dir_md)
106
+ if attrs and found:
107
+ return attrs, found
108
+ # 2).r2mo/repo/r2mo-spec
109
+ repo_path = os.path.join(project_root, '.r2mo', 'repo', 'r2mo-spec')
110
+ if not os.path.isdir(repo_path):
111
+ return None, None
112
+ candidates = [f'{message_name}.md']
113
+ if message_name.endswith('Entity'):
114
+ candidates.append(f'{message_name[:-6]}.md')
115
+ for root, dirs, files in os.walk(repo_path):
116
+ for f in files:
117
+ if f.lower() in [c.lower() for c in candidates]:
118
+ md_file = os.path.join(root, f)
119
+ attrs, _ = _read_md_front_matter(md_file)
120
+ if attrs:
121
+ return attrs, os.path.basename(md_file)
122
+ return None, None
123
+
124
+
125
+ def _build_message_comment(attrs):
126
+ """
127
+ 将文档头部的所有 front-matter 属性解析到注释中,每个属性一行,格式为 key: value。
128
+ """
129
+ if not attrs or not isinstance(attrs, dict):
130
+ return []
131
+ lines = []
132
+ for k, v in attrs.items():
133
+ if v is None or v == '':
134
+ continue
135
+ if isinstance(v, (list, dict)):
136
+ v = str(v)[:80]
137
+ lines.append(f"{k}: {v}")
138
+ return lines
139
+
76
140
  def extract_constraints(lines):
77
141
  """
78
142
  从注解中提取约束信息(规范化格式),包括:
@@ -345,13 +409,12 @@ def _extract_fields_from_getters(content):
345
409
 
346
410
  return fields
347
411
 
348
- def generate_proto(name, pkg, content, ftype):
412
+ def generate_proto(name, pkg, content, ftype, java_file_path=None):
349
413
  lines = [
350
414
  'syntax = "proto3";',
351
415
  'package domain;', ''
352
416
  ]
353
417
 
354
- # 只有 class 类型才需要 import
355
418
  imports = set()
356
419
  fields = []
357
420
  enum_items = []
@@ -360,11 +423,9 @@ def generate_proto(name, pkg, content, ftype):
360
423
  enum_items = parse_java_enum(content, name)
361
424
  if not enum_items: return None
362
425
  else:
363
- # 解析字段并获取依赖
364
426
  fields, imports = parse_java_class(content)
365
427
  if not fields: return None
366
428
 
367
- # 生成 import 语句
368
429
  self_import = f"{camel_to_snake(name)}.proto"
369
430
  if self_import in imports:
370
431
  imports.remove(self_import)
@@ -373,9 +434,19 @@ def generate_proto(name, pkg, content, ftype):
373
434
  sorted_imports = sorted(list(imports))
374
435
  for imp in sorted_imports:
375
436
  lines.append(f'import "{imp}";')
376
- lines.append('') # 空行分隔
437
+ lines.append('')
377
438
 
378
439
  lines.append(f'// Generated from {pkg}.{name}')
440
+
441
+ # 先查与 Java 同目录的同名 .md,再查 .r2mo/repo;只提取头部 front-matter,找到才打印
442
+ project_root = os.getcwd()
443
+ doc_attrs, found_md = _find_doc_for_java(name, java_file_path, project_root)
444
+ if doc_attrs and found_md:
445
+ for comment_line in _build_message_comment(doc_attrs):
446
+ if comment_line:
447
+ lines.append(f'// {comment_line}')
448
+ print(f" ✓ {name}: 已从 {found_md} 追加笔记属性到注释")
449
+
379
450
  lines.append(f'option java_package = "{pkg}";')
380
451
  lines.append('option java_multiple_files = true;')
381
452
  lines.append('')
@@ -387,7 +458,6 @@ def generate_proto(name, pkg, content, ftype):
387
458
  else:
388
459
  lines.append(f'message {name} {{')
389
460
  for idx, f in enumerate(fields, 1):
390
- # BaseEntity 等字段用 java_name 拼注释;其余字段 comment 已含 [Java:xxx]
391
461
  comment_str = f.get("comment") or ""
392
462
  if f.get("java_name"):
393
463
  comment_str = f"[Java:{f['java_name']}] {comment_str}".strip() if comment_str else f"[Java:{f['java_name']}]"
@@ -442,7 +512,7 @@ def main():
442
512
  pkg = get_package_name(content)
443
513
  ftype = 'enum' if is_enum else 'class'
444
514
 
445
- proto = generate_proto(name, pkg, content, ftype)
515
+ proto = generate_proto(name, pkg, content, ftype, java_file_path=path)
446
516
  if proto:
447
517
  out_name = f"{camel_to_snake(name)}.proto"
448
518
  with open(os.path.join(output_dir, out_name), 'w') as fh: fh.write(proto)
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @module momo-repo-spec
3
+ * 与 momo domain / momo mmr0 / momo mmr2 共享的 r2mo-spec 仓库配置。
4
+ * 仓库名为 r2mo-spec,直接从 .r2mo/repo/r2mo-spec 加载,不做 rename。
5
+ */
6
+ const REPO_SPEC_NAME = 'r2mo-spec';
7
+ const SPEC_REPO_URL = 'https://gitee.com/silentbalanceyh/r2mo-spec.git';
8
+ /** 本地缓存目录:.r2mo/repo/{仓库名},与仓库名一致 */
9
+ const LOCAL_CACHE_DIR = `.r2mo/repo/${REPO_SPEC_NAME}`;
10
+ /** .gitignore 中写入的条目(共享目录根) */
11
+ const GITIGNORE_ENTRY = '.r2mo/repo';
12
+
13
+ module.exports = {
14
+ REPO_SPEC_NAME,
15
+ SPEC_REPO_URL,
16
+ LOCAL_CACHE_DIR,
17
+ GITIGNORE_ENTRY
18
+ };