nsgm-cli 2.1.13 → 2.1.14
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/README.md +370 -155
- package/client/components/Button.tsx +3 -5
- package/client/components/__tests__/Button.test.tsx +10 -10
- package/client/layout/index.tsx +149 -137
- package/client/redux/reducers.ts +1 -1
- package/client/redux/store.ts +2 -1
- package/client/redux/template/manage/actions.ts +77 -88
- package/client/redux/template/manage/reducers.ts +25 -37
- package/client/redux/template/manage/types.ts +1 -1
- package/client/service/template/manage.ts +20 -21
- package/client/styled/common.ts +12 -13
- package/client/styled/layout/index.ts +19 -19
- package/client/styled/template/manage.ts +14 -13
- package/client/utils/common.ts +23 -21
- package/client/utils/cookie.ts +18 -19
- package/client/utils/fetch.ts +64 -100
- package/client/utils/menu.tsx +16 -3
- package/client/utils/sso.ts +74 -84
- package/eslint.config.js +38 -1
- package/generation/README.md +25 -6
- package/generation/__tests__/example.test.js +41 -0
- package/generation/client/utils/menu.tsx +9 -2
- package/generation/env.example +3 -0
- package/generation/eslint.config.js +112 -0
- package/generation/gitignore +6 -1
- package/generation/jest.config.js +40 -0
- package/generation/package.json +24 -3
- package/jest.config.js +23 -6
- package/lib/args.js +9 -1
- package/lib/cli/app.d.ts +28 -0
- package/lib/cli/app.js +99 -0
- package/lib/cli/commands/build.d.ts +2 -0
- package/lib/cli/commands/build.js +29 -0
- package/lib/cli/commands/create.d.ts +2 -0
- package/lib/cli/commands/create.js +113 -0
- package/lib/cli/commands/delete.d.ts +3 -0
- package/lib/cli/commands/delete.js +151 -0
- package/lib/cli/commands/export.d.ts +2 -0
- package/lib/cli/commands/export.js +42 -0
- package/lib/cli/commands/help.d.ts +2 -0
- package/lib/cli/commands/help.js +42 -0
- package/lib/cli/commands/init.d.ts +2 -0
- package/lib/cli/commands/init.js +115 -0
- package/lib/cli/commands/server.d.ts +3 -0
- package/lib/cli/commands/server.js +26 -0
- package/lib/cli/commands/upgrade.d.ts +2 -0
- package/lib/cli/commands/upgrade.js +38 -0
- package/lib/cli/commands/version.d.ts +2 -0
- package/lib/cli/commands/version.js +24 -0
- package/lib/cli/index.d.ts +16 -0
- package/lib/cli/index.js +33 -0
- package/lib/cli/parser.d.ts +22 -0
- package/lib/cli/parser.js +115 -0
- package/lib/cli/registry.d.ts +33 -0
- package/lib/cli/registry.js +81 -0
- package/lib/cli/types/project.d.ts +10 -0
- package/lib/cli/types/project.js +2 -0
- package/lib/cli/types.d.ts +31 -0
- package/lib/cli/types.js +20 -0
- package/lib/cli/utils/console.d.ts +62 -0
- package/lib/cli/utils/console.js +148 -0
- package/lib/cli/utils/index.d.ts +2 -0
- package/lib/cli/utils/index.js +7 -0
- package/lib/cli/utils/prompt.d.ts +83 -0
- package/lib/cli/utils/prompt.js +368 -0
- package/lib/constants.d.ts +58 -0
- package/lib/constants.js +162 -0
- package/lib/generate.d.ts +25 -3
- package/lib/generate.js +97 -621
- package/lib/generate_create.d.ts +9 -0
- package/lib/generate_create.js +326 -0
- package/lib/generate_delete.d.ts +8 -0
- package/lib/generate_delete.js +156 -0
- package/lib/generate_init.d.ts +50 -0
- package/lib/generate_init.js +492 -0
- package/lib/generators/base-generator.d.ts +47 -0
- package/lib/generators/base-generator.js +92 -0
- package/lib/generators/generator-factory.d.ts +20 -0
- package/lib/generators/generator-factory.js +25 -0
- package/lib/generators/page-generator.d.ts +41 -0
- package/lib/generators/page-generator.js +552 -0
- package/lib/generators/resolver-generator.d.ts +12 -0
- package/lib/generators/resolver-generator.js +303 -0
- package/lib/generators/schema-generator.d.ts +7 -0
- package/lib/generators/schema-generator.js +57 -0
- package/lib/generators/service-generator.d.ts +7 -0
- package/lib/generators/service-generator.js +119 -0
- package/lib/generators/sql-generator.d.ts +8 -0
- package/lib/generators/sql-generator.js +52 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +14 -173
- package/lib/server/csrf.js +9 -16
- package/lib/server/db.js +6 -7
- package/lib/server/graphql.js +5 -6
- package/lib/server/plugins/date.js +1 -1
- package/lib/server/utils/graphql-cache.js +3 -3
- package/lib/tsconfig.build.tsbuildinfo +1 -1
- package/lib/utils/project-config.d.ts +5 -0
- package/lib/utils/project-config.js +145 -0
- package/lib/utils.js +1 -1
- package/next.config.js +12 -8
- package/package.json +10 -7
- package/pages/_app.tsx +23 -28
- package/pages/_document.tsx +39 -19
- package/pages/index.tsx +84 -39
- package/pages/login.tsx +21 -21
- package/pages/template/manage.tsx +114 -89
- package/public/fonts/font-awesome.min.css +4 -0
- package/public/fonts/fontawesome-webfont.woff +0 -0
- package/public/fonts/fontawesome-webfont.woff2 +0 -0
- package/public/slbhealthcheck.html +1 -1
- package/server/apis/template.js +0 -2
- package/generation/eslintrc.js +0 -16
package/client/utils/sso.ts
CHANGED
|
@@ -5,16 +5,16 @@ import _ from 'lodash'
|
|
|
5
5
|
|
|
6
6
|
const env = getLocalEnv()
|
|
7
7
|
|
|
8
|
-
const LOGIN_COOKIE_ID = env
|
|
9
|
-
const LOGIN_COOKIE_USER = env
|
|
8
|
+
const LOGIN_COOKIE_ID = `${env}_cas_nsgm`
|
|
9
|
+
const LOGIN_COOKIE_USER = `${env}_nsgm_user`
|
|
10
10
|
|
|
11
11
|
const getPrincipalUrl = () => {
|
|
12
|
-
const url = getLocalApiPrefix()
|
|
12
|
+
const url = `${getLocalApiPrefix()}/rest/sso/sessionCheck`
|
|
13
13
|
return url
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
const getValidateUrl = () => {
|
|
17
|
-
const url = getLocalApiPrefix()
|
|
17
|
+
const url = `${getLocalApiPrefix()}/rest/sso/ticketCheck`
|
|
18
18
|
return url
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -33,18 +33,17 @@ const handleLocationHref = () => {
|
|
|
33
33
|
if (paramStr.indexOf('&') !== -1) {
|
|
34
34
|
const paramArr = paramStr.split('&')
|
|
35
35
|
|
|
36
|
-
_.each(paramArr, (item
|
|
36
|
+
_.each(paramArr, (item) => {
|
|
37
37
|
if (item.indexOf('=') !== -1) {
|
|
38
38
|
const itemArr = item.split('=')
|
|
39
39
|
const itemArrLen = itemArr.length
|
|
40
40
|
|
|
41
41
|
const key = itemArr[0]
|
|
42
42
|
let value = ''
|
|
43
|
-
if (itemArrLen > 1)
|
|
44
|
-
value = itemArr[1]
|
|
43
|
+
if (itemArrLen > 1) value = itemArr[1]
|
|
45
44
|
|
|
46
45
|
if ('ticket' !== key) {
|
|
47
|
-
newParamStr += key
|
|
46
|
+
newParamStr += `${key}=${value}&`
|
|
48
47
|
}
|
|
49
48
|
}
|
|
50
49
|
})
|
|
@@ -58,16 +57,12 @@ const handleLocationHref = () => {
|
|
|
58
57
|
}
|
|
59
58
|
|
|
60
59
|
const locationHrefArrFirst = locationHrefArr[0]
|
|
61
|
-
if (newParamStr !== '')
|
|
62
|
-
|
|
63
|
-
else
|
|
64
|
-
newHref = locationHrefArrFirst
|
|
60
|
+
if (newParamStr !== '') newHref = `${locationHrefArrFirst}?${newParamStr}`
|
|
61
|
+
else newHref = locationHrefArrFirst
|
|
65
62
|
} else {
|
|
66
63
|
newHref = locationHref
|
|
67
64
|
}
|
|
68
65
|
}
|
|
69
|
-
|
|
70
|
-
// console.log('newHref', newHref)
|
|
71
66
|
return encodeURIComponent(newHref)
|
|
72
67
|
}
|
|
73
68
|
|
|
@@ -76,16 +71,7 @@ const jumpToLogin = () => {
|
|
|
76
71
|
delCookie(LOGIN_COOKIE_USER)
|
|
77
72
|
|
|
78
73
|
if (typeof window !== 'undefined') {
|
|
79
|
-
window.location.href = window.location.origin
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const jumpToLogout = () => {
|
|
84
|
-
delCookie(LOGIN_COOKIE_ID)
|
|
85
|
-
delCookie(LOGIN_COOKIE_USER)
|
|
86
|
-
|
|
87
|
-
if (typeof window !== 'undefined') {
|
|
88
|
-
window.location.href = window.location.origin
|
|
74
|
+
window.location.href = `${window.location.origin}/login`
|
|
89
75
|
}
|
|
90
76
|
}
|
|
91
77
|
|
|
@@ -93,44 +79,50 @@ const principalLogin = (cookie: string, callback: any) => {
|
|
|
93
79
|
let url = getPrincipalUrl()
|
|
94
80
|
|
|
95
81
|
if (typeof window !== 'undefined') {
|
|
96
|
-
url +=
|
|
82
|
+
url += `?cookieValue=${cookie}&redirectUrl=${handleLocationHref()}`
|
|
97
83
|
}
|
|
98
84
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
85
|
+
axios
|
|
86
|
+
.get(url, { params: { credentials: 'include' } })
|
|
87
|
+
.then((res: any) => {
|
|
88
|
+
const { data } = res
|
|
89
|
+
if (data) {
|
|
90
|
+
const { returnCode, userAttr } = data
|
|
91
|
+
if (returnCode !== 0) {
|
|
92
|
+
jumpToLogin()
|
|
93
|
+
} else {
|
|
94
|
+
storeLoginUser(userAttr, callback)
|
|
95
|
+
}
|
|
107
96
|
} else {
|
|
108
|
-
|
|
97
|
+
jumpToLogin()
|
|
109
98
|
}
|
|
110
|
-
}
|
|
99
|
+
})
|
|
100
|
+
.catch((e) => {
|
|
101
|
+
console.error('principalLogin_exception', e)
|
|
111
102
|
jumpToLogin()
|
|
112
|
-
}
|
|
113
|
-
}).catch((e) => {
|
|
114
|
-
console.log('principalLogin_exception', e)
|
|
115
|
-
jumpToLogin()
|
|
116
|
-
})
|
|
103
|
+
})
|
|
117
104
|
}
|
|
118
105
|
|
|
119
106
|
const storeLoginUser = (userAttr: any, callback: any) => {
|
|
120
|
-
// console.log('storeLoginUser', userAttr)
|
|
121
|
-
|
|
122
107
|
if (userAttr) {
|
|
123
|
-
const user = JSON.stringify(userAttr, [
|
|
108
|
+
const user = JSON.stringify(userAttr, [
|
|
109
|
+
'city',
|
|
110
|
+
'company',
|
|
111
|
+
'department',
|
|
112
|
+
'displayName',
|
|
113
|
+
'employee',
|
|
114
|
+
'mail',
|
|
115
|
+
'name',
|
|
116
|
+
'sn',
|
|
117
|
+
])
|
|
124
118
|
setCookie(LOGIN_COOKIE_USER, user, null)
|
|
125
|
-
callback
|
|
119
|
+
callback?.(JSON.parse(user))
|
|
126
120
|
} else {
|
|
127
|
-
callback
|
|
121
|
+
callback?.()
|
|
128
122
|
}
|
|
129
123
|
}
|
|
130
124
|
|
|
131
125
|
const storeLogin = (cookie: any, cookieExpire: any, userAttr: any, callback: any) => {
|
|
132
|
-
// console.log('storeLogin_cookie', cookie)
|
|
133
|
-
|
|
134
126
|
if (cookie) {
|
|
135
127
|
setCookie(LOGIN_COOKIE_ID, cookie, cookieExpire)
|
|
136
128
|
}
|
|
@@ -138,51 +130,50 @@ const storeLogin = (cookie: any, cookieExpire: any, userAttr: any, callback: any
|
|
|
138
130
|
storeLoginUser(userAttr, callback)
|
|
139
131
|
}
|
|
140
132
|
|
|
141
|
-
const validateLogin = (ticket: string, name
|
|
133
|
+
const validateLogin = (ticket: string, name = '', callback: any) => {
|
|
142
134
|
let url = getValidateUrl()
|
|
143
135
|
|
|
144
136
|
if (typeof window !== 'undefined') {
|
|
145
|
-
url +=
|
|
137
|
+
url += `?ticket=${ticket}`
|
|
146
138
|
|
|
147
139
|
if (name !== '') {
|
|
148
|
-
url +=
|
|
140
|
+
url += `&name=${name}`
|
|
149
141
|
}
|
|
150
142
|
}
|
|
151
143
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
144
|
+
axios
|
|
145
|
+
.get(url, { params: { credentials: 'include' } })
|
|
146
|
+
.then((res: any) => {
|
|
147
|
+
if (res) {
|
|
148
|
+
const { data } = res
|
|
149
|
+
if (data) {
|
|
150
|
+
const { cookieValue, cookieExpire, returnCode, userAttr } = data
|
|
151
|
+
if (returnCode === 0) {
|
|
152
|
+
storeLogin(cookieValue, cookieExpire, userAttr, callback)
|
|
153
|
+
} else {
|
|
154
|
+
jumpToLogin()
|
|
155
|
+
}
|
|
162
156
|
} else {
|
|
163
157
|
jumpToLogin()
|
|
164
158
|
}
|
|
165
159
|
} else {
|
|
166
160
|
jumpToLogin()
|
|
167
161
|
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
console.log('validateLogin_exception', e)
|
|
173
|
-
})
|
|
162
|
+
})
|
|
163
|
+
.catch((e) => {
|
|
164
|
+
console.error('validateLogin_exception', e)
|
|
165
|
+
})
|
|
174
166
|
}
|
|
175
167
|
|
|
176
168
|
export const login = (callback: any) => {
|
|
177
169
|
const cookieLoginValue = getCookie(LOGIN_COOKIE_ID)
|
|
178
|
-
// console.log('cookieLoginValue', cookieLoginValue)
|
|
179
170
|
|
|
180
171
|
if (typeof window !== 'undefined') {
|
|
181
172
|
const locationHref = window.location.href
|
|
182
173
|
|
|
183
174
|
// 如果已经在登录页面,不需要进行登录检查
|
|
184
175
|
if (locationHref.indexOf('/login') !== -1) {
|
|
185
|
-
callback
|
|
176
|
+
callback?.()
|
|
186
177
|
return
|
|
187
178
|
}
|
|
188
179
|
|
|
@@ -204,42 +195,41 @@ export const login = (callback: any) => {
|
|
|
204
195
|
principalLogin(cookieLoginValue, callback)
|
|
205
196
|
}
|
|
206
197
|
} else {
|
|
207
|
-
callback
|
|
198
|
+
callback?.()
|
|
208
199
|
}
|
|
209
200
|
}
|
|
210
201
|
|
|
211
202
|
export const directLogin = (userName: string, userPassword: string, callback: any) => {
|
|
212
203
|
if (userName === '') {
|
|
213
|
-
return { success: false, message: '请输入用户名' }
|
|
204
|
+
return { success: false, message: '请输入用户名' }
|
|
214
205
|
}
|
|
215
206
|
if (userPassword === '') {
|
|
216
|
-
return { success: false, message: '请输入密码' }
|
|
207
|
+
return { success: false, message: '请输入密码' }
|
|
217
208
|
}
|
|
218
209
|
|
|
219
210
|
// 使用 encodeURIComponent 处理可能的特殊字符,然后再进行 Base64 编码
|
|
220
|
-
const safeStr = handleXSS(userName
|
|
221
|
-
const encodedName = btoa(encodeURIComponent(safeStr))
|
|
222
|
-
const url = `${getLocalApiPrefix()}/rest/sso/ticketCheck?ticket=XXX&name=${encodedName}
|
|
211
|
+
const safeStr = handleXSS(`${userName},${userPassword}`)
|
|
212
|
+
const encodedName = btoa(encodeURIComponent(safeStr))
|
|
213
|
+
const url = `${getLocalApiPrefix()}/rest/sso/ticketCheck?ticket=XXX&name=${encodedName}`
|
|
223
214
|
|
|
224
215
|
return fetch(url)
|
|
225
|
-
.then(response => response.json())
|
|
226
|
-
.then(data => {
|
|
216
|
+
.then((response) => response.json())
|
|
217
|
+
.then((data) => {
|
|
227
218
|
if (data && data.returnCode === 0) {
|
|
228
219
|
// 登录成功,设置cookie
|
|
229
220
|
if (typeof window !== 'undefined') {
|
|
230
|
-
storeLogin(data.cookieValue, data.cookieExpire, data.userAttr, callback)
|
|
231
|
-
return { success: true }
|
|
221
|
+
storeLogin(data.cookieValue, data.cookieExpire, data.userAttr, callback)
|
|
222
|
+
return { success: true }
|
|
232
223
|
}
|
|
233
224
|
}
|
|
234
|
-
return { success: false, message: '用户名或密码错误' }
|
|
225
|
+
return { success: false, message: '用户名或密码错误' }
|
|
226
|
+
})
|
|
227
|
+
.catch((error) => {
|
|
228
|
+
console.error('登录请求失败:', error)
|
|
229
|
+
return { success: false, message: '登录请求失败,请稍后重试' }
|
|
235
230
|
})
|
|
236
|
-
.catch(error => {
|
|
237
|
-
console.error('登录请求失败:', error);
|
|
238
|
-
return { success: false, message: '登录请求失败,请稍后重试' };
|
|
239
|
-
});
|
|
240
231
|
}
|
|
241
232
|
|
|
242
233
|
export const logout = () => {
|
|
243
234
|
jumpToLogin()
|
|
244
235
|
}
|
|
245
|
-
|
package/eslint.config.js
CHANGED
|
@@ -6,7 +6,8 @@ const prettier = require('eslint-plugin-prettier');
|
|
|
6
6
|
module.exports = [
|
|
7
7
|
js.configs.recommended,
|
|
8
8
|
{
|
|
9
|
-
files: ['src/**/*.{ts,tsx}'],
|
|
9
|
+
files: ['src/**/*.{ts,tsx}', 'client/**/*.{ts,tsx}', 'pages/**/*.{ts,tsx}'],
|
|
10
|
+
ignores: ['**/__tests__/**/*'],
|
|
10
11
|
languageOptions: {
|
|
11
12
|
parser: typescriptParser,
|
|
12
13
|
parserOptions: {
|
|
@@ -55,6 +56,42 @@ module.exports = [
|
|
|
55
56
|
'prettier/prettier': 'error'
|
|
56
57
|
}
|
|
57
58
|
},
|
|
59
|
+
{
|
|
60
|
+
files: ['**/__tests__/**/*.{ts,tsx}', '**/*.test.{ts,tsx}', '**/*.spec.{ts,tsx}'],
|
|
61
|
+
languageOptions: {
|
|
62
|
+
parser: typescriptParser,
|
|
63
|
+
parserOptions: {
|
|
64
|
+
ecmaVersion: 2022,
|
|
65
|
+
sourceType: 'module'
|
|
66
|
+
},
|
|
67
|
+
globals: {
|
|
68
|
+
describe: 'readonly',
|
|
69
|
+
test: 'readonly',
|
|
70
|
+
expect: 'readonly',
|
|
71
|
+
beforeEach: 'readonly',
|
|
72
|
+
afterEach: 'readonly',
|
|
73
|
+
beforeAll: 'readonly',
|
|
74
|
+
afterAll: 'readonly',
|
|
75
|
+
jest: 'readonly',
|
|
76
|
+
__dirname: 'readonly',
|
|
77
|
+
__filename: 'readonly',
|
|
78
|
+
process: 'readonly',
|
|
79
|
+
Buffer: 'readonly',
|
|
80
|
+
console: 'readonly'
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
plugins: {
|
|
84
|
+
'@typescript-eslint': typescript,
|
|
85
|
+
'prettier': prettier
|
|
86
|
+
},
|
|
87
|
+
rules: {
|
|
88
|
+
'no-console': 'off',
|
|
89
|
+
'no-undef': 'off',
|
|
90
|
+
'no-unused-vars': 'off',
|
|
91
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
92
|
+
'prettier/prettier': 'error'
|
|
93
|
+
}
|
|
94
|
+
},
|
|
58
95
|
{
|
|
59
96
|
files: ['**/*.js'],
|
|
60
97
|
languageOptions: {
|
package/generation/README.md
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
- [Styled-components](https://github.com/styled-components/styled-components) - CSS-in-JS 解决方案
|
|
9
9
|
- [GraphQL](https://graphql.org/) - API 查询语言
|
|
10
10
|
- [MySQL](https://www.mysql.com/) - 关系型数据库
|
|
11
|
+
- [Jest](https://jestjs.io/) - JavaScript 测试框架
|
|
11
12
|
- 安全登录系统 - 基于 bcrypt 加密
|
|
12
13
|
|
|
13
14
|
## 快速入门
|
|
@@ -21,6 +22,14 @@
|
|
|
21
22
|
| `npm run build` | 编译项目 |
|
|
22
23
|
| `npm run export` | 导出静态页面 |
|
|
23
24
|
|
|
25
|
+
### 测试命令
|
|
26
|
+
|
|
27
|
+
| 命令 | 说明 |
|
|
28
|
+
| ----------------------- | ---------------- |
|
|
29
|
+
| `npm test` | 运行所有测试 |
|
|
30
|
+
| `npm run test:watch` | 监视模式运行测试 |
|
|
31
|
+
| `npm run test:coverage` | 生成覆盖率报告 |
|
|
32
|
+
|
|
24
33
|
### 代码生成命令
|
|
25
34
|
|
|
26
35
|
| 命令 | 说明 |
|
|
@@ -30,10 +39,10 @@
|
|
|
30
39
|
|
|
31
40
|
### 项目维护命令
|
|
32
41
|
|
|
33
|
-
| 命令
|
|
34
|
-
|
|
|
35
|
-
| `npm run upgrade`
|
|
36
|
-
| `npm run generate-password [密码]`
|
|
42
|
+
| 命令 | 说明 |
|
|
43
|
+
| ---------------------------------- | ---------------- |
|
|
44
|
+
| `npm run upgrade` | 升级项目基础文件 |
|
|
45
|
+
| `npm run generate-password [密码]` | 生成安全密码哈希 |
|
|
37
46
|
|
|
38
47
|
## 参数说明
|
|
39
48
|
|
|
@@ -70,6 +79,7 @@
|
|
|
70
79
|
## 项目结构
|
|
71
80
|
|
|
72
81
|
```
|
|
82
|
+
├── __tests__/ # 测试文件
|
|
73
83
|
├── components/ # 公共组件
|
|
74
84
|
├── pages/ # 页面文件
|
|
75
85
|
│ ├── api/ # API 路由
|
|
@@ -80,6 +90,8 @@
|
|
|
80
90
|
│ ├── modules/ # GraphQL 解析器和模式
|
|
81
91
|
│ └── plugins/ # GraphQL 插件
|
|
82
92
|
├── styles/ # 全局样式
|
|
93
|
+
├── coverage/ # 测试覆盖率报告
|
|
94
|
+
├── jest.config.js # Jest 测试配置
|
|
83
95
|
├── next.config.js # Next.js 配置
|
|
84
96
|
├── mysql.config.js # MySQL 配置
|
|
85
97
|
└── project.config.js # 项目配置
|
|
@@ -180,8 +192,15 @@ module.exports = {
|
|
|
180
192
|
|
|
181
193
|
1. **创建新页面**:使用 `npm run create [controller] [action]` 命令
|
|
182
194
|
2. **启动开发服务器**:运行 `npm run dev`
|
|
183
|
-
3.
|
|
184
|
-
4.
|
|
195
|
+
3. **运行测试**:使用 `npm test` 运行测试,`npm run test:watch` 进行开发时的实时测试
|
|
196
|
+
4. **构建生产版本**:运行 `npm run build` 然后 `npm run start`
|
|
197
|
+
5. **导出静态网站**:运行 `npm run export`
|
|
198
|
+
|
|
199
|
+
### 测试开发
|
|
200
|
+
|
|
201
|
+
- 测试文件放在 `__tests__/` 目录下
|
|
202
|
+
- 测试文件以 `.test.js`、`.test.ts`、`.spec.js` 或 `.spec.ts` 结尾
|
|
203
|
+
- 查看测试覆盖率报告:运行 `npm run test:coverage` 后打开 `coverage/index.html`
|
|
185
204
|
|
|
186
205
|
## 更多资源
|
|
187
206
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example test file to demonstrate Jest configuration
|
|
3
|
+
* This file can be removed or modified according to your project needs
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
describe('Jest Configuration Test', () => {
|
|
7
|
+
test('Jest is properly configured', () => {
|
|
8
|
+
expect(true).toBe(true)
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
test('Basic math operations', () => {
|
|
12
|
+
expect(2 + 2).toBe(4)
|
|
13
|
+
expect(5 * 3).toBe(15)
|
|
14
|
+
expect(10 / 2).toBe(5)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('String operations', () => {
|
|
18
|
+
const testString = 'Hello, World!'
|
|
19
|
+
expect(testString).toContain('World')
|
|
20
|
+
expect(testString.length).toBe(13)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('Array operations', () => {
|
|
24
|
+
const testArray = [1, 2, 3, 4, 5]
|
|
25
|
+
expect(testArray).toHaveLength(5)
|
|
26
|
+
expect(testArray).toContain(3)
|
|
27
|
+
expect(testArray[0]).toBe(1)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('Object operations', () => {
|
|
31
|
+
const testObject = {
|
|
32
|
+
name: 'Test',
|
|
33
|
+
version: '1.0.0',
|
|
34
|
+
active: true
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
expect(testObject).toHaveProperty('name')
|
|
38
|
+
expect(testObject.name).toBe('Test')
|
|
39
|
+
expect(testObject.active).toBeTruthy()
|
|
40
|
+
})
|
|
41
|
+
})
|
|
@@ -5,7 +5,14 @@ let key = 1
|
|
|
5
5
|
|
|
6
6
|
export default [
|
|
7
7
|
{
|
|
8
|
-
key: key.toString(),
|
|
8
|
+
key: (++key).toString(),
|
|
9
|
+
text: '', // 空目录不显示,为了使用 SolutionOutlined 而不报错
|
|
10
|
+
url: '/',
|
|
11
|
+
icon: <SolutionOutlined rev={undefined} />,
|
|
12
|
+
subMenus: null
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
key: (++key).toString(),
|
|
9
16
|
text: '介绍',
|
|
10
17
|
url: '/',
|
|
11
18
|
icon: <BookOutlined rev={undefined} />,
|
|
@@ -23,5 +30,5 @@ export default [
|
|
|
23
30
|
url: '/template/manage'
|
|
24
31
|
}
|
|
25
32
|
]
|
|
26
|
-
}
|
|
33
|
+
}*/
|
|
27
34
|
]
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const js = require('@eslint/js');
|
|
2
|
+
const typescript = require('@typescript-eslint/eslint-plugin');
|
|
3
|
+
const typescriptParser = require('@typescript-eslint/parser');
|
|
4
|
+
const prettier = require('eslint-plugin-prettier');
|
|
5
|
+
|
|
6
|
+
module.exports = [
|
|
7
|
+
js.configs.recommended,
|
|
8
|
+
{
|
|
9
|
+
files: ['client/**/*.{ts,tsx}', 'pages/**/*.{ts,tsx}', 'src/**/*.{ts,tsx}'],
|
|
10
|
+
languageOptions: {
|
|
11
|
+
parser: typescriptParser,
|
|
12
|
+
parserOptions: {
|
|
13
|
+
ecmaVersion: 2022,
|
|
14
|
+
sourceType: 'module',
|
|
15
|
+
project: './tsconfig.json'
|
|
16
|
+
},
|
|
17
|
+
globals: {
|
|
18
|
+
__dirname: 'readonly',
|
|
19
|
+
__filename: 'readonly',
|
|
20
|
+
process: 'readonly',
|
|
21
|
+
Buffer: 'readonly',
|
|
22
|
+
console: 'readonly'
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
plugins: {
|
|
26
|
+
'@typescript-eslint': typescript,
|
|
27
|
+
'prettier': prettier
|
|
28
|
+
},
|
|
29
|
+
rules: {
|
|
30
|
+
'no-console': 'off',
|
|
31
|
+
'no-undef': 'off',
|
|
32
|
+
'no-unused-vars': 'off',
|
|
33
|
+
'prefer-const': 'warn',
|
|
34
|
+
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'warn',
|
|
35
|
+
'@typescript-eslint/no-var-requires': 'off',
|
|
36
|
+
'@typescript-eslint/no-explicit-any': 'warn',
|
|
37
|
+
'@typescript-eslint/no-unused-vars': ['warn', {
|
|
38
|
+
argsIgnorePattern: '^_',
|
|
39
|
+
varsIgnorePattern: '^_'
|
|
40
|
+
}],
|
|
41
|
+
'prettier/prettier': 'error',
|
|
42
|
+
'no-unreachable': 'error',
|
|
43
|
+
'no-duplicate-imports': 'error',
|
|
44
|
+
'prefer-template': 'warn',
|
|
45
|
+
'@typescript-eslint/prefer-optional-chain': 'warn'
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
files: ['**/__tests__/**/*.{ts,tsx,js}', '**/*.test.{ts,tsx,js}', '**/*.spec.{ts,tsx,js}'],
|
|
50
|
+
languageOptions: {
|
|
51
|
+
parser: typescriptParser,
|
|
52
|
+
parserOptions: {
|
|
53
|
+
ecmaVersion: 2022,
|
|
54
|
+
sourceType: 'module'
|
|
55
|
+
},
|
|
56
|
+
globals: {
|
|
57
|
+
describe: 'readonly',
|
|
58
|
+
test: 'readonly',
|
|
59
|
+
expect: 'readonly',
|
|
60
|
+
beforeEach: 'readonly',
|
|
61
|
+
afterEach: 'readonly',
|
|
62
|
+
beforeAll: 'readonly',
|
|
63
|
+
afterAll: 'readonly',
|
|
64
|
+
jest: 'readonly',
|
|
65
|
+
__dirname: 'readonly',
|
|
66
|
+
__filename: 'readonly',
|
|
67
|
+
process: 'readonly',
|
|
68
|
+
Buffer: 'readonly',
|
|
69
|
+
console: 'readonly'
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
plugins: {
|
|
73
|
+
'@typescript-eslint': typescript,
|
|
74
|
+
'prettier': prettier
|
|
75
|
+
},
|
|
76
|
+
rules: {
|
|
77
|
+
'no-console': 'off',
|
|
78
|
+
'no-undef': 'off',
|
|
79
|
+
'no-unused-vars': 'off',
|
|
80
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
81
|
+
'prettier/prettier': 'error'
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
files: ['**/*.js'],
|
|
86
|
+
languageOptions: {
|
|
87
|
+
ecmaVersion: 2022,
|
|
88
|
+
sourceType: 'commonjs',
|
|
89
|
+
globals: {
|
|
90
|
+
require: 'readonly',
|
|
91
|
+
module: 'readonly',
|
|
92
|
+
exports: 'readonly',
|
|
93
|
+
__dirname: 'readonly',
|
|
94
|
+
__filename: 'readonly',
|
|
95
|
+
process: 'readonly',
|
|
96
|
+
Buffer: 'readonly',
|
|
97
|
+
console: 'readonly'
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
rules: {
|
|
101
|
+
'no-console': 'off'
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
ignores: [
|
|
106
|
+
'node_modules/**',
|
|
107
|
+
'.next/**',
|
|
108
|
+
'coverage/**',
|
|
109
|
+
'*.config.js'
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
];
|
package/generation/gitignore
CHANGED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
testEnvironment: 'jsdom',
|
|
3
|
+
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
|
|
4
|
+
transform: {
|
|
5
|
+
'^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }]
|
|
6
|
+
},
|
|
7
|
+
transformIgnorePatterns: ['/node_modules/', '^.+\\.module\\.(css|sass|scss|less)$'],
|
|
8
|
+
moduleNameMapper: {
|
|
9
|
+
'^@/(.*)$': '<rootDir>/$1',
|
|
10
|
+
'^~/(.*)$': '<rootDir>/$1'
|
|
11
|
+
},
|
|
12
|
+
setupFiles: ['<rootDir>/jest.setup-globals.js'],
|
|
13
|
+
testMatch: [
|
|
14
|
+
'**/__tests__/**/*.(ts|tsx|js)',
|
|
15
|
+
'**/*.(test|spec).(ts|tsx|js)'
|
|
16
|
+
],
|
|
17
|
+
collectCoverage: true,
|
|
18
|
+
collectCoverageFrom: [
|
|
19
|
+
'client/**/*.{js,jsx,ts,tsx}',
|
|
20
|
+
'pages/**/*.{js,jsx,ts,tsx}',
|
|
21
|
+
'server/**/*.{js,jsx,ts,tsx}',
|
|
22
|
+
'!**/*.d.ts',
|
|
23
|
+
'!**/node_modules/**',
|
|
24
|
+
'!**/.next/**',
|
|
25
|
+
'!**/coverage/**',
|
|
26
|
+
'!**/*.config.js'
|
|
27
|
+
],
|
|
28
|
+
coverageDirectory: 'coverage',
|
|
29
|
+
coverageReporters: ['json', 'lcov', 'text', 'clover', 'html'],
|
|
30
|
+
coverageThreshold: {
|
|
31
|
+
global: {
|
|
32
|
+
branches: 70,
|
|
33
|
+
functions: 70,
|
|
34
|
+
lines: 70,
|
|
35
|
+
statements: 70
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
testPathIgnorePatterns: ['<rootDir>/.next/', '<rootDir>/node_modules/'],
|
|
39
|
+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node']
|
|
40
|
+
}
|
package/generation/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "nsgm-cli-project",
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"description": "",
|
|
5
|
-
"main": "
|
|
5
|
+
"main": "app.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"dev": "nsgm dev",
|
|
8
8
|
"build": "nsgm build",
|
|
@@ -15,8 +15,29 @@
|
|
|
15
15
|
"deletedb": "nsgm deletedb",
|
|
16
16
|
"generate-password": "node scripts/generate-password-hash.js",
|
|
17
17
|
"postversion": "git push && git push --tags",
|
|
18
|
-
"test": "
|
|
18
|
+
"test": "jest",
|
|
19
|
+
"test:watch": "jest --watch",
|
|
20
|
+
"test:coverage": "jest --coverage"
|
|
19
21
|
},
|
|
20
22
|
"author": "",
|
|
21
|
-
"license": "ISC"
|
|
23
|
+
"license": "ISC",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"nsgm-cli": "^2"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^20",
|
|
29
|
+
"@types/react": "^18",
|
|
30
|
+
"@types/lodash": "^4",
|
|
31
|
+
"typescript": "^5",
|
|
32
|
+
"jest": "^30",
|
|
33
|
+
"jest-environment-jsdom": "^30",
|
|
34
|
+
"@testing-library/jest-dom": "^6",
|
|
35
|
+
"@testing-library/react": "^14",
|
|
36
|
+
"@testing-library/user-event": "^14",
|
|
37
|
+
"@types/jest": "^30",
|
|
38
|
+
"eslint": "^9",
|
|
39
|
+
"eslint-config-prettier": "^10",
|
|
40
|
+
"eslint-plugin-prettier": "^5",
|
|
41
|
+
"prettier": "^3"
|
|
42
|
+
}
|
|
22
43
|
}
|