@yorha2b-lab/autodev 5.5.0 → 5.6.0

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/src/utils/core.js DELETED
@@ -1,262 +0,0 @@
1
- /**
2
- * Auto CRUD Copilot - YoRHa Bunker Construction System
3
- *
4
- */
5
- const { Segment, useDefault } = require('segmentit')
6
- const segmentit = useDefault(new Segment())
7
- /**
8
- * 清理大模型生成的代码
9
- * 大模型输出的标准 JSON 无法携带 render: (text) => <Tag> 等箭头函数。
10
- * 我们在 Prompt 中要求大模型用 _CODE_ 占位符包裹函数字符串,
11
- * 在此处用正则剥离外层的双引号和占位符,将其还原为真正的可执行 JS 代码。
12
- * @param {string} str - 大模型返回的 JSON 字符串
13
- * @returns {string} 清理后的可执行 JS 代码
14
- */
15
- const cleanCode = str => {
16
- return str
17
- // 物理超度 Markdown 糖衣(解决```json 报错)
18
- .replace(/```[a-z]*\n?/gi, '')
19
- .replace(/```/g, '')
20
- // 逻辑自愈 处理 AI 错误转义的引号(把 \" 还原回 ")
21
- .replace(/\\"/g, '"')
22
- .replace(/['"]?_CODE_([\s\S]*?)_CODE_['"]?/g, '$1') // 去掉 _CODE_ 包裹的代码
23
- .replace(/_CODE_/g, '') // 兜底清理
24
- .replace(/"(\w+)":/g, '$1:') // 去掉 key 的双引号
25
- .replace(/"/g, "'") // 双引号全部转单引号
26
- .replace(/[ \t]+$/gm, '') // 去除每一行行尾的多余空格
27
- .replace(/\n{3,}/g, '\n\n') // 将3个或以上的换行符压缩成2个换行符
28
- .replace(/^\s+/, '') // 去掉文件头部的空行
29
- .trim() + '\n'
30
- }
31
-
32
- /**
33
- * @function unwrapSignal
34
- * @description [地堡数据脱水机] 物理扫描 JSON 结构,剥离业务外壳(code/msg/total 等)。
35
- * 目标:精准定位到核心的 Array。
36
- */
37
- const unwrapSignal = json => {
38
- if (Array.isArray(json)) return json
39
-
40
- // 💡 扫描常见的数据仓库 Key
41
- const dataKeys = ['data', 'list', 'items', 'datas', 'rows', 'result', 'payload', 'results', 'dataList']
42
- for (const key of dataKeys) {
43
- if (json[key] && Array.isArray(json[key])) return json[key]
44
- }
45
-
46
- // 💡 递归侦察:处理 data: { list: [...] } 这种二级套娃
47
- for (const key in json) {
48
- if (json[key] && typeof json[key] === 'object') {
49
- const nested = unwrapSignal(json[key])
50
- if (Array.isArray(nested)) return nested
51
- }
52
- }
53
- return null
54
- }
55
-
56
- /**
57
- * @function createTaskQueue
58
- * @description [任务队列] 创建一个并发任务队列,用于处理异步任务。
59
- * @param {number} concurrency - 并发任务数,默认 1。
60
- */
61
- const createTaskQueue = (concurrency = 1) => {
62
-
63
- let running = 0
64
- let queue = []
65
- let onIdleCallback = null
66
-
67
- const next = async () => {
68
-
69
- if (running >= concurrency || queue.length === 0) return
70
-
71
- const task = queue.shift()
72
- running++
73
-
74
- try {
75
- await task()
76
- } catch (err) {
77
- console.error('任务执行异常:', err)
78
- } finally {
79
- running--
80
- next()
81
- if (running === 0 && queue.length === 0 && onIdleCallback) {
82
- onIdleCallback()
83
- }
84
- }
85
- }
86
-
87
- return {
88
- add: (task) => {
89
- queue.push(task)
90
- next()
91
- },
92
- onIdle: (callback) => {
93
- onIdleCallback = callback
94
- }
95
- }
96
- }
97
-
98
- /**
99
- * @function isQuerySignal
100
- * @description [语义雷达]
101
- * 核心逻辑:不纠结请求是怎么发的,只看带回来的货(Response)长什么样。
102
- */
103
- const isQuerySignal = (req, json, coreData) => {
104
-
105
- const url = req.url.toLowerCase()
106
- // 💡 1. 物理红区:只要 URL 包含这些动作,无论返回什么都视为“非列表”
107
- const actionKeywords = ['add', 'delete', 'update', 'save', 'remove', 'edit', 'insert', 'create', 'export', 'upload']
108
- if (actionKeywords.some(key => url.includes(key))) return false
109
- // 💡 2. 物理金标准:脱壳后的核心物资是一个【非空数组】
110
- // 只要带回了一堆长得一样的对象,那它 99.9% 就是列表页
111
- const hasListData = Array.isArray(coreData) && coreData.length > 0
112
- // 💡 3. 语义辅助:如果响应里包含“分页指纹”
113
- // 有时候第一页刚好没数据(coreData 是空数组),但 JSON 里带有 total, page 等字段
114
- const hasPaginationFingerprint = ['total', 'records', 'page', 'size', 'count'].some(key => {
115
- const k = key.toLowerCase()
116
- // 在原始 JSON 的第一层寻找分页相关的 key
117
- return Object.keys(json).some(rawKey => rawKey.toLowerCase().includes(k))
118
- })
119
- // 结论:具备列表特征或者是分页指纹的,判定为查询信号
120
- return hasListData || hasPaginationFingerprint
121
- }
122
-
123
- /**
124
- * @function getSemanticKeywords
125
- * @description [语义精炼厂 2.0] 使用 segmentit 引擎进行物理切片。
126
- */
127
- const getSemanticKeywords = text => {
128
- // 💡 物理脱水:确保输入为纯净字符串
129
- const content = Array.isArray(text) ? text.join(' ') : (text || '')
130
- // 💡 执行分词
131
- const result = segmentit.doSegment(content, {
132
- simple: true, // 开启简易模式,提升吞吐效率
133
- stripPunctuation: true // 物理过滤掉所有的标点符号
134
- })
135
- // 💡 提取词条并执行“基因筛选”
136
- return Array.from(new Set(result.filter(word => word.length >= 2 && !/^[0-9]+$/.test(word))))
137
- }
138
-
139
-
140
- /**
141
- * @function formatFormItemAndColumns
142
- * @description [地堡逻辑转录引擎] 执行核心的语义对齐与代码物理注入协议。
143
- * 该函数负责将 AI 识别出的视觉类型标签(money/date/enum等)转化为标准的 React 渲染逻辑,
144
- * 并自动提取全频道所需的字典引用(Dictionary Blocks)。
145
- *
146
- * @param {Object} params - 构筑参数包
147
- * @param {Object} params.pageConfig - 由 Pod 042 扫描出的原始页面配置对象
148
- *
149
- * @returns {Object} 返回物理装配完成的数据包:
150
- * @returns {Array} .formItems - 已注入 Options 指令的表单零部件清单
151
- * @returns {Array} .processedColumns - 已执行逻辑注入(Render 补丁)的表格列清单
152
- * @returns {Array} .dictBlocks - 全频道去重后的字典(Options)变量名清单
153
- */
154
- const formatFormItemAndColumns = ({ pageConfig }) => {
155
-
156
- const codePresets = {
157
- money: 'text => moneyRender(text)',
158
- date: 'text => timeRender({time: text})',
159
- index: '(_, record, index) => index + 1',
160
- tag: `text => <Tag color='magenta'>{text}</Tag>`,
161
- badge: `text => <Badge status='success' text={text} />`,
162
- enum: dataIndex => `text => ${dataIndex}Options.find(item => item.value === text)?.label ?? text`,
163
- }
164
-
165
- const columns = pageConfig.table?.columns ?? pageConfig?.columns ?? []
166
-
167
- const tableDicts = columns?.filter(item => item.type === 'enum')?.map(item => `${item.dataIndex}Options`) ?? []
168
- const formDicts = pageConfig.formItems?.filter(item => item.type === 'select')?.map(item => `${item.name}Options`) ?? []
169
- const dictBlocks = Array.from(new Set([...formDicts, ...tableDicts]))
170
-
171
- const formItems = pageConfig.formItems?.map(item => {
172
- if (item.type === 'text') {
173
- delete item.type
174
- }
175
- return {
176
- ...item,
177
- ...(item.type === 'select' ? { options: `_CODE_${item.name}Options_CODE_` } : {})
178
- }
179
- })
180
-
181
- const processedColumns = columns?.map(col => {
182
- if (col.type === 'text') {
183
- delete col.type
184
- }
185
- if (['image'].includes(col.type)) {
186
- return { ...col, renderAction: true }
187
- }
188
- if (col.type && codePresets[col.type]) {
189
- // 💡 物理注入:根据标签,强行塞入标准化的 JS 代码字符串
190
- const renderCode = typeof codePresets[col.type] === 'function' ? codePresets[col.type](col.dataIndex) : codePresets[col.type]
191
- return {
192
- ...col,
193
- render: `_CODE_${renderCode}_CODE_` // 重新打标,交给 cleanCode 处理
194
- }
195
- }
196
- return col
197
- })
198
-
199
- return { formItems, dictBlocks, processedColumns }
200
- }
201
-
202
- /**
203
- * @function getLocalScore
204
- * @description [战力评估协议] 计算语义重合度。
205
- */
206
- const getLocalScore = (api, pageKeywords, moduleName) => {
207
- let score = 0
208
- const path = api.path.toLowerCase()
209
- const desc = api.desc.toLowerCase()
210
- const mod = moduleName.toLowerCase()
211
-
212
- // 💡 权重 A:路径直接包含模块名 (暴击加分 +50)
213
- if (path.includes(mod)) score += 50
214
-
215
- // 💡 权重 B:描述包含模块核心词 (中量加分 +10)
216
- pageKeywords.forEach(word => {
217
- if (desc.includes(word.toLowerCase())) score += 10
218
- if (path.includes(word.toLowerCase())) score += 5
219
- })
220
-
221
- return score
222
- }
223
-
224
- /**
225
- * 生成智能导入语句
226
- * 根据代码中实际使用的依赖,自动生成对应的 import 语句
227
- * @param {string} codeStr - 生成的代码字符串
228
- * @param {boolean} hasTabs - 是否包含标签页
229
- * @returns {string} 拼接后的 import 语句
230
- */
231
- const generateSmartImports = ({ module, hasTabs, bodyCode, hasFormItems }) => {
232
-
233
- const hooksLib = ['useTableQuery']
234
- const utilsLib = ['timeRender', 'moneyRender']
235
- const reactLib = ['useState', 'useEffect', 'useRef', 'useMemo']
236
- const componentsLib = ['MyTable', 'MyImage', 'MyModalForm', 'MySearchForm']
237
- const antdLib = ['Tag', 'Card', 'Badge', 'Space', 'Modal', 'Alert', 'Image', 'Table', 'Input', 'Select', 'Button']
238
-
239
- const usedAntd = antdLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
240
- const usedUtils = utilsLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
241
- const usedHooks = hooksLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
242
- const usedReact = reactLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
243
- const usedComps = componentsLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
244
-
245
- const imports = [
246
- usedReact.length && `import { ${usedReact.join(', ')} } from 'react'`,
247
- usedAntd.length && `import { ${hasFormItems && module === 'index' ? 'Form, ' : ''}${usedAntd.join(', ')} } from 'antd'`,
248
- ...usedHooks.map(hook => `import { ${hook} } from '../../hooks/${hook}'`),
249
- ...usedComps.map(comp => `import { ${comp} } from '../../components/${comp}'`),
250
- ...(module === 'index' ? [
251
- `import { request } from '../../utils/request'`,
252
- `import { formatQuery } from '../../utils/utils'`,
253
- `import { ${hasTabs ? 'tabs, ' : ''}${hasFormItems ? 'formItems, ' : ''}modalItems, tableColumns} from './resource'`
254
- ] : [
255
- usedUtils.length && `import { ${usedUtils.join(', ')} } from '../../utils/utils'`
256
- ]),
257
- ].sort((a, b) => a.length - b.length)
258
-
259
- return imports.filter(Boolean).join('\n')
260
- }
261
-
262
- module.exports = { cleanCode, unwrapSignal, isQuerySignal, getLocalScore, createTaskQueue, getSemanticKeywords, generateSmartImports, formatFormItemAndColumns }