zs
2025-06-04 5a149d626ae8bc3fa4bddbb53f8caf40f51f6da6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
const { glob } = require('glob')
const { readFileSync, writeFileSync, ensureDirSync } = require('fs-extra')
const { resolve } = require('path')
const regExp = /export default [\s\S]*?;/
const regExpObj = /\{[\s\S]*?;/
const babel = require('@babel/core')
const pkg = require('../package.json')
const isWin = process.platform === 'win32'
 
/**
 * 根据widgets下的组件,自动生成菜单数据,用于对外引用
 */
async function start() {
  const tsFiles = await glob(resolve(process.cwd(), 'src/widgets/*/index.ts'), {
    ignore: 'node_modules/**',
    windowsPathsNoEscape: true,
  })
 
  const menu = []
  const menuMap = {}
  const errorKey = ' is not defined'
 
  tsFiles.forEach((filePath) => {
    const spl = !isWin ? filePath.split('/') : filePath.split('\\')
 
    const patchName = spl[spl.length - 2]
    const file = readFileSync(filePath, { encoding: 'utf8' })
    const { code } = babel.transformSync(file)
    const exportDefaultRegion = code.match(regExp)
    const exportDefaultContent = exportDefaultRegion[0]
    if (exportDefaultContent) {
      const v = exportDefaultContent.match(regExpObj)
      const canvasView = exportDefaultContent.match(/canvasView: ([^,]+),/)
      let canvasViewValue = canvasView ? canvasView[0] : ''
      canvasViewValue = !canvasViewValue.includes(')')
        ? canvasViewValue.replace(',', '),')
        : canvasViewValue
 
      const c = v[0].replace(canvasViewValue, '')
      let setViewMatch = c.match(/settingsView:\s*(.*?)(?=\s*[,}])/)
      let newCode = ''
      if (setViewMatch[0]) {
        newCode = c.replace(setViewMatch[0], '').replace(';', '')
      }
      if (newCode.includes('canvasView')) {
        newCode = newCode.replace(
          /canvasView\s*:\s*.*?(\{.*?\}|\(.*?\)|[^\s,]+)\s*,?\s*(?=\n|$)/gs,
          ''
        )
      }
 
      const codeRun = (code) => {
        const fn = new Function(`return ${code}`)
        const widgetInfo = fn()
        const row = {
          name: widgetInfo.name,
          path: `/${pkg.name}/` + patchName,
          patchName: patchName,
 
          icon: widgetInfo.icon,
          notPage: !!widgetInfo.notPage,
        }
        menu.push(row)
        menuMap[patchName] = row
      }
      try {
        codeRun(newCode)
      } catch (error) {
        if (error.message.includes(errorKey)) {
          const iconKey = error.message.split(errorKey)
          if (iconKey.length > 1) {
            const iconName = iconKey[0]
            const code = newCode.replaceAll(iconName, `"${iconName}"`)
            codeRun(code)
          }
        } else {
          console.error(error.message)
        }
      }
    }
  })
  const data = `export const menu: Record<string,any>[] = ${JSON.stringify(
    menu,
    null,
    2
  )};\nexport const menuMap: Record<string,any> = ${JSON.stringify(
    menuMap,
    null,
    2
  )};`
  // 生成menu JSON 到build.prod
  // const buildInfo = readFileSync(resolve(process.cwd(), '.build'), {
  //   encoding: 'utf-8',
  // })
  // const recoveryWidget = buildInfo.split('\n')
  ensureDirSync(resolve(process.cwd(), './src/config/'))
  writeFileSync(resolve(process.cwd(), './src/config/menu.ts'), data, {
    encoding: 'utf-8',
  })
 
  // const widgets = menu
  //   .map((item) => item.patchName)
  //   .filter((name) => !recoveryWidget.includes(name))
  // writeFileSync(resolve(process.cwd(), '.build.prod'), widgets.join('\n'), {
  //   encoding: 'utf-8',
  // })
}
const startTime = performance.now()
 
start()
 
console.log('执行时间: ', Math.ceil(performance.now() - startTime), 'ms')