@zhin.js/core 1.0.21 → 1.0.22
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/CHANGELOG.md +8 -0
- package/package.json +4 -4
- package/tests/config.test.ts +176 -0
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.22",
|
|
4
4
|
"description": "Zhin机器人核心框架",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"segment-matcher": "latest",
|
|
33
33
|
"toml": "^3.0.0",
|
|
34
34
|
"yaml": "^2.3.4",
|
|
35
|
-
"@zhin.js/database": "1.0.
|
|
36
|
-
"@zhin.js/logger": "0.1.
|
|
37
|
-
"@zhin.js/schema": "1.0.
|
|
35
|
+
"@zhin.js/database": "1.0.9",
|
|
36
|
+
"@zhin.js/logger": "0.1.6",
|
|
37
|
+
"@zhin.js/schema": "1.0.6"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^24.3.0",
|
package/tests/config.test.ts
CHANGED
|
@@ -147,4 +147,180 @@ describe('ConfigLoader', () => {
|
|
|
147
147
|
expect(loader.data.value).toBeTruthy()
|
|
148
148
|
})
|
|
149
149
|
})
|
|
150
|
+
|
|
151
|
+
describe('File operations', () => {
|
|
152
|
+
it('should save and load JSON config', () => {
|
|
153
|
+
const jsonPath = path.join(process.cwd(), 'test-config.json')
|
|
154
|
+
const config = {
|
|
155
|
+
name: 'test',
|
|
156
|
+
value: 123
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const loader = new ConfigLoader(jsonPath, config)
|
|
160
|
+
loader.save(jsonPath)
|
|
161
|
+
|
|
162
|
+
expect(fs.existsSync(jsonPath)).toBe(true)
|
|
163
|
+
|
|
164
|
+
const content = fs.readFileSync(jsonPath, 'utf-8')
|
|
165
|
+
const parsed = JSON.parse(content)
|
|
166
|
+
expect(parsed.name).toBe('test')
|
|
167
|
+
expect(parsed.value).toBe(123)
|
|
168
|
+
|
|
169
|
+
fs.unlinkSync(jsonPath)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
it('should save and load YAML config', () => {
|
|
173
|
+
const yamlPath = path.join(process.cwd(), 'test-config.yml')
|
|
174
|
+
const config = {
|
|
175
|
+
name: 'test',
|
|
176
|
+
value: 123
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const loader = new ConfigLoader(yamlPath, config)
|
|
180
|
+
loader.save(yamlPath)
|
|
181
|
+
|
|
182
|
+
expect(fs.existsSync(yamlPath)).toBe(true)
|
|
183
|
+
|
|
184
|
+
fs.unlinkSync(yamlPath)
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
it('should auto-save on property change', () => {
|
|
188
|
+
const config = {
|
|
189
|
+
value: 'initial'
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const loader = new ConfigLoader(testConfigPath, config)
|
|
193
|
+
loader.save(testConfigPath)
|
|
194
|
+
|
|
195
|
+
// 修改属性应该触发自动保存
|
|
196
|
+
const proxiedData = loader.data
|
|
197
|
+
proxiedData.value = 'changed'
|
|
198
|
+
|
|
199
|
+
// 重新读取文件验证保存
|
|
200
|
+
const content = fs.readFileSync(testConfigPath, 'utf-8')
|
|
201
|
+
const parsed = JSON.parse(content)
|
|
202
|
+
expect(parsed.value).toBe('changed')
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
it('should auto-save on property deletion', () => {
|
|
206
|
+
const config = {
|
|
207
|
+
value: 'test',
|
|
208
|
+
other: 'keep'
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const loader = new ConfigLoader(testConfigPath, config)
|
|
212
|
+
loader.save(testConfigPath)
|
|
213
|
+
|
|
214
|
+
// 删除属性应该触发自动保存
|
|
215
|
+
const proxiedData = loader.data as any
|
|
216
|
+
delete proxiedData.value
|
|
217
|
+
|
|
218
|
+
// 重新读取文件验证保存
|
|
219
|
+
const content = fs.readFileSync(testConfigPath, 'utf-8')
|
|
220
|
+
const parsed = JSON.parse(content)
|
|
221
|
+
expect(parsed.value).toBeUndefined()
|
|
222
|
+
expect(parsed.other).toBe('keep')
|
|
223
|
+
})
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
describe('ConfigService', () => {
|
|
227
|
+
it('should load and cache configs', async () => {
|
|
228
|
+
const { ConfigService } = await import('../src/built/config')
|
|
229
|
+
const service = new ConfigService()
|
|
230
|
+
|
|
231
|
+
const config = { test: 'value' }
|
|
232
|
+
service.load('test-config.json', config)
|
|
233
|
+
|
|
234
|
+
expect(service.configs.has('test-config.json')).toBe(true)
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
it('should throw error for unsupported format', async () => {
|
|
238
|
+
const { ConfigService } = await import('../src/built/config')
|
|
239
|
+
const service = new ConfigService()
|
|
240
|
+
|
|
241
|
+
expect(() => {
|
|
242
|
+
service.load('test.txt', {})
|
|
243
|
+
}).toThrow('不支持的配置文件格式')
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
it('should get config data', async () => {
|
|
247
|
+
const { ConfigService } = await import('../src/built/config')
|
|
248
|
+
const service = new ConfigService()
|
|
249
|
+
|
|
250
|
+
const config = { test: 'value' }
|
|
251
|
+
service.load(testConfigPath, config)
|
|
252
|
+
|
|
253
|
+
const data = service.get(testConfigPath)
|
|
254
|
+
expect(data.test).toBe('value')
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
it('should get raw config data', async () => {
|
|
258
|
+
const { ConfigService } = await import('../src/built/config')
|
|
259
|
+
const service = new ConfigService()
|
|
260
|
+
|
|
261
|
+
const config = { test: '${VAR}' }
|
|
262
|
+
service.load(testConfigPath, config)
|
|
263
|
+
|
|
264
|
+
const raw = service.getRaw(testConfigPath)
|
|
265
|
+
expect(raw.test).toBe('${VAR}')
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
it('should update config data', async () => {
|
|
269
|
+
const { ConfigService } = await import('../src/built/config')
|
|
270
|
+
const service = new ConfigService()
|
|
271
|
+
|
|
272
|
+
const config = { test: 'initial' }
|
|
273
|
+
service.load(testConfigPath, config)
|
|
274
|
+
|
|
275
|
+
service.set(testConfigPath, { test: 'updated' })
|
|
276
|
+
|
|
277
|
+
const data = service.get(testConfigPath)
|
|
278
|
+
expect(data.test).toBe('updated')
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
it('should throw error when getting non-existent config', async () => {
|
|
282
|
+
const { ConfigService } = await import('../src/built/config')
|
|
283
|
+
const service = new ConfigService()
|
|
284
|
+
|
|
285
|
+
service.load(testConfigPath, { test: 'value' })
|
|
286
|
+
service.configs.delete(testConfigPath) // 手动删除以模拟不存在的情况
|
|
287
|
+
|
|
288
|
+
// 由于 get 会自动加载,我们需要测试 set
|
|
289
|
+
expect(() => {
|
|
290
|
+
service.set('non-existent.json', {})
|
|
291
|
+
}).toThrow('配置文件 non-existent.json 未加载')
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
it('should auto-load config if not cached', async () => {
|
|
295
|
+
const { ConfigService } = await import('../src/built/config')
|
|
296
|
+
const service = new ConfigService()
|
|
297
|
+
|
|
298
|
+
const config = { test: 'value' }
|
|
299
|
+
// 先保存文件
|
|
300
|
+
const loader = new ConfigLoader(testConfigPath, config)
|
|
301
|
+
loader.save(testConfigPath)
|
|
302
|
+
|
|
303
|
+
// 不预先加载,直接 get
|
|
304
|
+
const data = service.get(testConfigPath, config)
|
|
305
|
+
expect(data.test).toBe('value')
|
|
306
|
+
expect(service.configs.has(testConfigPath)).toBe(true)
|
|
307
|
+
})
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
describe('Extension detection', () => {
|
|
311
|
+
it('should detect .json extension', () => {
|
|
312
|
+
const loader = new ConfigLoader('config.json', {})
|
|
313
|
+
expect(loader.extension).toBe('.json')
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
it('should detect .yml extension', () => {
|
|
317
|
+
const loader = new ConfigLoader('config.yml', {})
|
|
318
|
+
expect(loader.extension).toBe('.yml')
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
it('should detect .yaml extension', () => {
|
|
322
|
+
const loader = new ConfigLoader('config.yaml', {})
|
|
323
|
+
expect(loader.extension).toBe('.yaml')
|
|
324
|
+
})
|
|
325
|
+
})
|
|
150
326
|
})
|