@chatbi-v/mocks 1.0.1 → 2.0.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/dist/adapter.js +69 -59
- package/dist/index.cjs +83 -59
- package/dist/index.mjs +83 -59
- package/dist/interceptor.js +3 -2
- package/dist/strategies.js +11 -2
- package/dist/types.d.ts +2 -0
- package/dist/utils.d.ts +2 -3
- package/dist/utils.js +13 -9
- package/package.json +3 -3
package/dist/adapter.js
CHANGED
|
@@ -36,73 +36,81 @@ export class MockAdapter {
|
|
|
36
36
|
* @returns Promise 返回模拟的响应数据
|
|
37
37
|
*/
|
|
38
38
|
async request(config, endpointConfig) {
|
|
39
|
-
|
|
39
|
+
// 优先使用接口定义的 delay,否则使用全局默认 delay
|
|
40
|
+
const delay = endpointConfig?.delay ?? this.delay;
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
40
42
|
setTimeout(() => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
schema
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
43
|
+
try {
|
|
44
|
+
if (!endpointConfig || !endpointConfig.responseSchema) {
|
|
45
|
+
logger.warn(`未找到响应架构配置: ${config.url}`);
|
|
46
|
+
resolve({});
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
let schema = endpointConfig.responseSchema;
|
|
50
|
+
let mockData;
|
|
51
|
+
// 支持函数式 schema,允许根据请求参数动态生成 schema
|
|
52
|
+
if (typeof schema === 'function') {
|
|
53
|
+
schema = schema(config);
|
|
54
|
+
}
|
|
55
|
+
// 构造有效配置对象,合并 endpointConfig 顶层属性
|
|
56
|
+
const effectiveConfig = {
|
|
57
|
+
type: endpointConfig.type,
|
|
58
|
+
status: endpointConfig.status || 200,
|
|
59
|
+
pageEvent: endpointConfig.pageEvent,
|
|
60
|
+
responseSchema: schema,
|
|
61
|
+
...(typeof schema === 'object' ? schema : {}),
|
|
62
|
+
};
|
|
63
|
+
// 0. 处理非 200 状态码
|
|
64
|
+
if (effectiveConfig.status !== 200) {
|
|
65
|
+
const error = new Error(`Request failed with status code ${effectiveConfig.status}`);
|
|
66
|
+
error.response = {
|
|
67
|
+
status: effectiveConfig.status,
|
|
68
|
+
data: Mock.mock(schema),
|
|
69
|
+
headers: {},
|
|
70
|
+
};
|
|
71
|
+
reject(error);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// 1. 字符串 Schema:直接作为结果返回(极少情况)
|
|
75
|
+
if (typeof schema === 'string') {
|
|
76
|
+
mockData = schema;
|
|
77
|
+
}
|
|
78
|
+
// 2. 遗留的高级 Schema (通过 _type 字段识别)
|
|
79
|
+
else if (this.isLegacySchema(schema)) {
|
|
80
|
+
const strategy = MockAdapter.strategies[schema._type];
|
|
81
|
+
if (strategy) {
|
|
82
|
+
const chunks = strategy.generate(schema);
|
|
83
|
+
// 将流式块合并为单个字符串,并清理 SSE 格式标记
|
|
84
|
+
mockData = chunks
|
|
85
|
+
.join('')
|
|
86
|
+
.replace(/event: data\ndata: /g, '')
|
|
87
|
+
.replace(/\n\n/g, '');
|
|
88
|
+
try {
|
|
89
|
+
mockData = JSON.parse(mockData);
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
// 忽略解析错误,保持原始数据格式
|
|
93
|
+
}
|
|
75
94
|
}
|
|
76
|
-
|
|
77
|
-
|
|
95
|
+
else {
|
|
96
|
+
logger.warn(`未找到对应的策略类型: ${schema._type}`);
|
|
97
|
+
mockData = {};
|
|
78
98
|
}
|
|
79
99
|
}
|
|
100
|
+
// 3. 通用策略模式
|
|
80
101
|
else {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
// 3. 新版 Schema (通过 type: 'json' | 'sse' | 'sse-page' 识别)
|
|
86
|
-
else if (this.isNewConfig(effectiveConfig)) {
|
|
87
|
-
const type = effectiveConfig.type || 'json';
|
|
88
|
-
const strategy = StrategyFactory.getStrategy(type);
|
|
89
|
-
// 对于 request() 调用,我们只处理 'json' 类型
|
|
90
|
-
if (type === 'json') {
|
|
102
|
+
const type = effectiveConfig.type || 'json';
|
|
103
|
+
const strategy = StrategyFactory.getStrategy(type);
|
|
91
104
|
mockData = strategy.process(effectiveConfig, config.params || config.data);
|
|
92
105
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
106
|
+
logger.info(`Request: ${config.method} ${config.url}`, config.data || config.params);
|
|
107
|
+
logger.info(`Response:`, mockData);
|
|
108
|
+
resolve(mockData);
|
|
97
109
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
mockData = Mock.mock(schema);
|
|
110
|
+
catch (error) {
|
|
111
|
+
reject(error);
|
|
101
112
|
}
|
|
102
|
-
|
|
103
|
-
logger.info(`Response:`, mockData);
|
|
104
|
-
resolve(mockData);
|
|
105
|
-
}, this.delay);
|
|
113
|
+
}, delay);
|
|
106
114
|
});
|
|
107
115
|
}
|
|
108
116
|
/**
|
|
@@ -114,6 +122,8 @@ export class MockAdapter {
|
|
|
114
122
|
async stream(config, callbacks, endpointConfig) {
|
|
115
123
|
const { onMessage, onFinish, onError } = callbacks;
|
|
116
124
|
const signal = config.signal;
|
|
125
|
+
// 优先使用接口定义的 delay,否则使用全局默认 delay
|
|
126
|
+
const delay = endpointConfig?.delay ?? this.delay;
|
|
117
127
|
return new Promise((resolve) => {
|
|
118
128
|
// 如果请求已被取消,直接结束
|
|
119
129
|
if (signal && signal.aborted) {
|
|
@@ -227,7 +237,7 @@ export class MockAdapter {
|
|
|
227
237
|
onError(error);
|
|
228
238
|
resolve();
|
|
229
239
|
}
|
|
230
|
-
},
|
|
240
|
+
}, delay);
|
|
231
241
|
});
|
|
232
242
|
}
|
|
233
243
|
/**
|
package/dist/index.cjs
CHANGED
|
@@ -527,14 +527,20 @@ function processTemplate(data, context) {
|
|
|
527
527
|
}
|
|
528
528
|
return data;
|
|
529
529
|
}
|
|
530
|
-
function flatEvents(eventsSchema,
|
|
530
|
+
function flatEvents(eventsSchema, requestData = {}) {
|
|
531
|
+
const context = {
|
|
532
|
+
$query: requestData,
|
|
533
|
+
// Backward compatibility
|
|
534
|
+
$body: requestData,
|
|
535
|
+
$param: requestData?.param || requestData
|
|
536
|
+
};
|
|
531
537
|
import_mockjs.default.Random.extend({
|
|
532
|
-
$query:
|
|
533
|
-
|
|
534
|
-
|
|
538
|
+
$query: () => context.$query,
|
|
539
|
+
$body: () => context.$body,
|
|
540
|
+
$param: () => context.$param
|
|
535
541
|
});
|
|
536
542
|
const compiled = import_mockjs.default.mock(eventsSchema);
|
|
537
|
-
return Object.values(compiled).flat().map((event) => processTemplate(event,
|
|
543
|
+
return Object.values(compiled).flat().map((event) => processTemplate(event, context)).sort((a, b) => {
|
|
538
544
|
const delayA = typeof a.delay === "number" ? a.delay : parseInt(String(a.delay || 0));
|
|
539
545
|
const delayB = typeof b.delay === "number" ? b.delay : parseInt(String(b.delay || 0));
|
|
540
546
|
return delayA - delayB;
|
|
@@ -642,9 +648,19 @@ var SsePageStrategy = class {
|
|
|
642
648
|
if (!ssePageConfig.responseSchema) return [];
|
|
643
649
|
const events = flatEvents(ssePageConfig.responseSchema, requestParams);
|
|
644
650
|
if (ssePageConfig.pageEvent) {
|
|
645
|
-
|
|
651
|
+
const context = {
|
|
652
|
+
$query: requestParams,
|
|
653
|
+
// Backward compatibility
|
|
654
|
+
$body: requestParams,
|
|
655
|
+
$param: requestParams?.param || requestParams
|
|
656
|
+
};
|
|
657
|
+
import_mockjs2.default.Random.extend({
|
|
658
|
+
$query: () => context.$query,
|
|
659
|
+
$body: () => context.$body,
|
|
660
|
+
$param: () => context.$param
|
|
661
|
+
});
|
|
646
662
|
let pageEvent = import_mockjs2.default.mock(ssePageConfig.pageEvent);
|
|
647
|
-
pageEvent = processTemplate(pageEvent,
|
|
663
|
+
pageEvent = processTemplate(pageEvent, context);
|
|
648
664
|
let maxDelay = 0;
|
|
649
665
|
if (events.length > 0) {
|
|
650
666
|
const lastEvent = events[events.length - 1];
|
|
@@ -710,58 +726,64 @@ var MockAdapter = class _MockAdapter {
|
|
|
710
726
|
* @returns Promise 返回模拟的响应数据
|
|
711
727
|
*/
|
|
712
728
|
async request(config, endpointConfig) {
|
|
713
|
-
|
|
729
|
+
const delay = endpointConfig?.delay ?? this.delay;
|
|
730
|
+
return new Promise((resolve, reject) => {
|
|
714
731
|
setTimeout(() => {
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
let schema = endpointConfig.responseSchema;
|
|
721
|
-
let mockData2;
|
|
722
|
-
if (typeof schema === "function") {
|
|
723
|
-
schema = schema(config);
|
|
724
|
-
}
|
|
725
|
-
const effectiveConfig = {
|
|
726
|
-
type: endpointConfig.type,
|
|
727
|
-
pageEvent: endpointConfig.pageEvent,
|
|
728
|
-
responseSchema: schema,
|
|
729
|
-
...typeof schema === "object" ? schema : {}
|
|
730
|
-
};
|
|
731
|
-
if (typeof schema === "string") {
|
|
732
|
-
mockData2 = schema;
|
|
733
|
-
} else if (this.isLegacySchema(schema)) {
|
|
734
|
-
const strategy = _MockAdapter.strategies[schema._type];
|
|
735
|
-
if (strategy) {
|
|
736
|
-
const chunks = strategy.generate(schema);
|
|
737
|
-
mockData2 = chunks.join("").replace(/event: data\ndata: /g, "").replace(/\n\n/g, "");
|
|
738
|
-
try {
|
|
739
|
-
mockData2 = JSON.parse(mockData2);
|
|
740
|
-
} catch (e) {
|
|
741
|
-
}
|
|
742
|
-
} else {
|
|
743
|
-
logger.warn(`\u672A\u627E\u5230\u5BF9\u5E94\u7684\u7B56\u7565\u7C7B\u578B: ${schema._type}`);
|
|
744
|
-
mockData2 = {};
|
|
732
|
+
try {
|
|
733
|
+
if (!endpointConfig || !endpointConfig.responseSchema) {
|
|
734
|
+
logger.warn(`\u672A\u627E\u5230\u54CD\u5E94\u67B6\u6784\u914D\u7F6E: ${config.url}`);
|
|
735
|
+
resolve({});
|
|
736
|
+
return;
|
|
745
737
|
}
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
738
|
+
let schema = endpointConfig.responseSchema;
|
|
739
|
+
let mockData2;
|
|
740
|
+
if (typeof schema === "function") {
|
|
741
|
+
schema = schema(config);
|
|
742
|
+
}
|
|
743
|
+
const effectiveConfig = {
|
|
744
|
+
type: endpointConfig.type,
|
|
745
|
+
status: endpointConfig.status || 200,
|
|
746
|
+
pageEvent: endpointConfig.pageEvent,
|
|
747
|
+
responseSchema: schema,
|
|
748
|
+
...typeof schema === "object" ? schema : {}
|
|
749
|
+
};
|
|
750
|
+
if (effectiveConfig.status !== 200) {
|
|
751
|
+
const error = new Error(`Request failed with status code ${effectiveConfig.status}`);
|
|
752
|
+
error.response = {
|
|
753
|
+
status: effectiveConfig.status,
|
|
754
|
+
data: import_mockjs3.default.mock(schema),
|
|
755
|
+
headers: {}
|
|
756
|
+
};
|
|
757
|
+
reject(error);
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
if (typeof schema === "string") {
|
|
761
|
+
mockData2 = schema;
|
|
762
|
+
} else if (this.isLegacySchema(schema)) {
|
|
763
|
+
const strategy = _MockAdapter.strategies[schema._type];
|
|
764
|
+
if (strategy) {
|
|
765
|
+
const chunks = strategy.generate(schema);
|
|
766
|
+
mockData2 = chunks.join("").replace(/event: data\ndata: /g, "").replace(/\n\n/g, "");
|
|
767
|
+
try {
|
|
768
|
+
mockData2 = JSON.parse(mockData2);
|
|
769
|
+
} catch (e) {
|
|
770
|
+
}
|
|
771
|
+
} else {
|
|
772
|
+
logger.warn(`\u672A\u627E\u5230\u5BF9\u5E94\u7684\u7B56\u7565\u7C7B\u578B: ${schema._type}`);
|
|
773
|
+
mockData2 = {};
|
|
774
|
+
}
|
|
754
775
|
} else {
|
|
755
|
-
|
|
756
|
-
|
|
776
|
+
const type = effectiveConfig.type || "json";
|
|
777
|
+
const strategy = StrategyFactory.getStrategy(type);
|
|
778
|
+
mockData2 = strategy.process(effectiveConfig, config.params || config.data);
|
|
757
779
|
}
|
|
758
|
-
|
|
759
|
-
|
|
780
|
+
logger.info(`Request: ${config.method} ${config.url}`, config.data || config.params);
|
|
781
|
+
logger.info(`Response:`, mockData2);
|
|
782
|
+
resolve(mockData2);
|
|
783
|
+
} catch (error) {
|
|
784
|
+
reject(error);
|
|
760
785
|
}
|
|
761
|
-
|
|
762
|
-
logger.info(`Response:`, mockData2);
|
|
763
|
-
resolve(mockData2);
|
|
764
|
-
}, this.delay);
|
|
786
|
+
}, delay);
|
|
765
787
|
});
|
|
766
788
|
}
|
|
767
789
|
/**
|
|
@@ -773,6 +795,7 @@ var MockAdapter = class _MockAdapter {
|
|
|
773
795
|
async stream(config, callbacks, endpointConfig) {
|
|
774
796
|
const { onMessage, onFinish, onError } = callbacks;
|
|
775
797
|
const signal = config.signal;
|
|
798
|
+
const delay = endpointConfig?.delay ?? this.delay;
|
|
776
799
|
return new Promise((resolve) => {
|
|
777
800
|
if (signal && signal.aborted) {
|
|
778
801
|
if (onFinish) onFinish();
|
|
@@ -822,9 +845,9 @@ var MockAdapter = class _MockAdapter {
|
|
|
822
845
|
);
|
|
823
846
|
break;
|
|
824
847
|
}
|
|
825
|
-
const
|
|
848
|
+
const delay2 = typeof event.delay === "number" ? event.delay : parseInt(String(event.delay || 0));
|
|
826
849
|
const elapsed = import_core2.dateUtils.now() - startTime;
|
|
827
|
-
const remaining = Math.max(0,
|
|
850
|
+
const remaining = Math.max(0, delay2 - elapsed);
|
|
828
851
|
if (remaining > 0) {
|
|
829
852
|
await sleep(remaining);
|
|
830
853
|
}
|
|
@@ -880,7 +903,7 @@ data: ${JSON.stringify(event.data)}
|
|
|
880
903
|
if (onError) onError(error);
|
|
881
904
|
resolve();
|
|
882
905
|
}
|
|
883
|
-
},
|
|
906
|
+
}, delay);
|
|
884
907
|
});
|
|
885
908
|
}
|
|
886
909
|
/**
|
|
@@ -932,13 +955,14 @@ function installFetchMock(schema) {
|
|
|
932
955
|
console.log(`[Mock] Intercepted ${method} ${url}`, rule);
|
|
933
956
|
await sleep(rule.delay || 0);
|
|
934
957
|
const type = rule.type || "json";
|
|
958
|
+
const status = rule.status || 200;
|
|
935
959
|
const strategy = StrategyFactory.getStrategy(type);
|
|
936
960
|
const urlObj = new URL(url, window.location.origin);
|
|
937
961
|
const query = Object.fromEntries(urlObj.searchParams);
|
|
938
962
|
const result = strategy.process(rule, query);
|
|
939
963
|
if (type === "json") {
|
|
940
964
|
return new Response(JSON.stringify(result), {
|
|
941
|
-
status
|
|
965
|
+
status,
|
|
942
966
|
headers: { "Content-Type": "application/json" }
|
|
943
967
|
});
|
|
944
968
|
}
|
|
@@ -946,7 +970,7 @@ function installFetchMock(schema) {
|
|
|
946
970
|
const events = result;
|
|
947
971
|
const stream = eventsToStream(events);
|
|
948
972
|
return new Response(stream, {
|
|
949
|
-
status
|
|
973
|
+
status,
|
|
950
974
|
headers: { "Content-Type": "text/event-stream" }
|
|
951
975
|
});
|
|
952
976
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -497,14 +497,20 @@ function processTemplate(data, context) {
|
|
|
497
497
|
}
|
|
498
498
|
return data;
|
|
499
499
|
}
|
|
500
|
-
function flatEvents(eventsSchema,
|
|
500
|
+
function flatEvents(eventsSchema, requestData = {}) {
|
|
501
|
+
const context = {
|
|
502
|
+
$query: requestData,
|
|
503
|
+
// Backward compatibility
|
|
504
|
+
$body: requestData,
|
|
505
|
+
$param: requestData?.param || requestData
|
|
506
|
+
};
|
|
501
507
|
Mock.Random.extend({
|
|
502
|
-
$query:
|
|
503
|
-
|
|
504
|
-
|
|
508
|
+
$query: () => context.$query,
|
|
509
|
+
$body: () => context.$body,
|
|
510
|
+
$param: () => context.$param
|
|
505
511
|
});
|
|
506
512
|
const compiled = Mock.mock(eventsSchema);
|
|
507
|
-
return Object.values(compiled).flat().map((event) => processTemplate(event,
|
|
513
|
+
return Object.values(compiled).flat().map((event) => processTemplate(event, context)).sort((a, b) => {
|
|
508
514
|
const delayA = typeof a.delay === "number" ? a.delay : parseInt(String(a.delay || 0));
|
|
509
515
|
const delayB = typeof b.delay === "number" ? b.delay : parseInt(String(b.delay || 0));
|
|
510
516
|
return delayA - delayB;
|
|
@@ -612,9 +618,19 @@ var SsePageStrategy = class {
|
|
|
612
618
|
if (!ssePageConfig.responseSchema) return [];
|
|
613
619
|
const events = flatEvents(ssePageConfig.responseSchema, requestParams);
|
|
614
620
|
if (ssePageConfig.pageEvent) {
|
|
615
|
-
|
|
621
|
+
const context = {
|
|
622
|
+
$query: requestParams,
|
|
623
|
+
// Backward compatibility
|
|
624
|
+
$body: requestParams,
|
|
625
|
+
$param: requestParams?.param || requestParams
|
|
626
|
+
};
|
|
627
|
+
Mock2.Random.extend({
|
|
628
|
+
$query: () => context.$query,
|
|
629
|
+
$body: () => context.$body,
|
|
630
|
+
$param: () => context.$param
|
|
631
|
+
});
|
|
616
632
|
let pageEvent = Mock2.mock(ssePageConfig.pageEvent);
|
|
617
|
-
pageEvent = processTemplate(pageEvent,
|
|
633
|
+
pageEvent = processTemplate(pageEvent, context);
|
|
618
634
|
let maxDelay = 0;
|
|
619
635
|
if (events.length > 0) {
|
|
620
636
|
const lastEvent = events[events.length - 1];
|
|
@@ -680,58 +696,64 @@ var MockAdapter = class _MockAdapter {
|
|
|
680
696
|
* @returns Promise 返回模拟的响应数据
|
|
681
697
|
*/
|
|
682
698
|
async request(config, endpointConfig) {
|
|
683
|
-
|
|
699
|
+
const delay = endpointConfig?.delay ?? this.delay;
|
|
700
|
+
return new Promise((resolve, reject) => {
|
|
684
701
|
setTimeout(() => {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
let schema = endpointConfig.responseSchema;
|
|
691
|
-
let mockData2;
|
|
692
|
-
if (typeof schema === "function") {
|
|
693
|
-
schema = schema(config);
|
|
694
|
-
}
|
|
695
|
-
const effectiveConfig = {
|
|
696
|
-
type: endpointConfig.type,
|
|
697
|
-
pageEvent: endpointConfig.pageEvent,
|
|
698
|
-
responseSchema: schema,
|
|
699
|
-
...typeof schema === "object" ? schema : {}
|
|
700
|
-
};
|
|
701
|
-
if (typeof schema === "string") {
|
|
702
|
-
mockData2 = schema;
|
|
703
|
-
} else if (this.isLegacySchema(schema)) {
|
|
704
|
-
const strategy = _MockAdapter.strategies[schema._type];
|
|
705
|
-
if (strategy) {
|
|
706
|
-
const chunks = strategy.generate(schema);
|
|
707
|
-
mockData2 = chunks.join("").replace(/event: data\ndata: /g, "").replace(/\n\n/g, "");
|
|
708
|
-
try {
|
|
709
|
-
mockData2 = JSON.parse(mockData2);
|
|
710
|
-
} catch (e) {
|
|
711
|
-
}
|
|
712
|
-
} else {
|
|
713
|
-
logger.warn(`\u672A\u627E\u5230\u5BF9\u5E94\u7684\u7B56\u7565\u7C7B\u578B: ${schema._type}`);
|
|
714
|
-
mockData2 = {};
|
|
702
|
+
try {
|
|
703
|
+
if (!endpointConfig || !endpointConfig.responseSchema) {
|
|
704
|
+
logger.warn(`\u672A\u627E\u5230\u54CD\u5E94\u67B6\u6784\u914D\u7F6E: ${config.url}`);
|
|
705
|
+
resolve({});
|
|
706
|
+
return;
|
|
715
707
|
}
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
708
|
+
let schema = endpointConfig.responseSchema;
|
|
709
|
+
let mockData2;
|
|
710
|
+
if (typeof schema === "function") {
|
|
711
|
+
schema = schema(config);
|
|
712
|
+
}
|
|
713
|
+
const effectiveConfig = {
|
|
714
|
+
type: endpointConfig.type,
|
|
715
|
+
status: endpointConfig.status || 200,
|
|
716
|
+
pageEvent: endpointConfig.pageEvent,
|
|
717
|
+
responseSchema: schema,
|
|
718
|
+
...typeof schema === "object" ? schema : {}
|
|
719
|
+
};
|
|
720
|
+
if (effectiveConfig.status !== 200) {
|
|
721
|
+
const error = new Error(`Request failed with status code ${effectiveConfig.status}`);
|
|
722
|
+
error.response = {
|
|
723
|
+
status: effectiveConfig.status,
|
|
724
|
+
data: Mock3.mock(schema),
|
|
725
|
+
headers: {}
|
|
726
|
+
};
|
|
727
|
+
reject(error);
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
if (typeof schema === "string") {
|
|
731
|
+
mockData2 = schema;
|
|
732
|
+
} else if (this.isLegacySchema(schema)) {
|
|
733
|
+
const strategy = _MockAdapter.strategies[schema._type];
|
|
734
|
+
if (strategy) {
|
|
735
|
+
const chunks = strategy.generate(schema);
|
|
736
|
+
mockData2 = chunks.join("").replace(/event: data\ndata: /g, "").replace(/\n\n/g, "");
|
|
737
|
+
try {
|
|
738
|
+
mockData2 = JSON.parse(mockData2);
|
|
739
|
+
} catch (e) {
|
|
740
|
+
}
|
|
741
|
+
} else {
|
|
742
|
+
logger.warn(`\u672A\u627E\u5230\u5BF9\u5E94\u7684\u7B56\u7565\u7C7B\u578B: ${schema._type}`);
|
|
743
|
+
mockData2 = {};
|
|
744
|
+
}
|
|
724
745
|
} else {
|
|
725
|
-
|
|
726
|
-
|
|
746
|
+
const type = effectiveConfig.type || "json";
|
|
747
|
+
const strategy = StrategyFactory.getStrategy(type);
|
|
748
|
+
mockData2 = strategy.process(effectiveConfig, config.params || config.data);
|
|
727
749
|
}
|
|
728
|
-
|
|
729
|
-
|
|
750
|
+
logger.info(`Request: ${config.method} ${config.url}`, config.data || config.params);
|
|
751
|
+
logger.info(`Response:`, mockData2);
|
|
752
|
+
resolve(mockData2);
|
|
753
|
+
} catch (error) {
|
|
754
|
+
reject(error);
|
|
730
755
|
}
|
|
731
|
-
|
|
732
|
-
logger.info(`Response:`, mockData2);
|
|
733
|
-
resolve(mockData2);
|
|
734
|
-
}, this.delay);
|
|
756
|
+
}, delay);
|
|
735
757
|
});
|
|
736
758
|
}
|
|
737
759
|
/**
|
|
@@ -743,6 +765,7 @@ var MockAdapter = class _MockAdapter {
|
|
|
743
765
|
async stream(config, callbacks, endpointConfig) {
|
|
744
766
|
const { onMessage, onFinish, onError } = callbacks;
|
|
745
767
|
const signal = config.signal;
|
|
768
|
+
const delay = endpointConfig?.delay ?? this.delay;
|
|
746
769
|
return new Promise((resolve) => {
|
|
747
770
|
if (signal && signal.aborted) {
|
|
748
771
|
if (onFinish) onFinish();
|
|
@@ -792,9 +815,9 @@ var MockAdapter = class _MockAdapter {
|
|
|
792
815
|
);
|
|
793
816
|
break;
|
|
794
817
|
}
|
|
795
|
-
const
|
|
818
|
+
const delay2 = typeof event.delay === "number" ? event.delay : parseInt(String(event.delay || 0));
|
|
796
819
|
const elapsed = dateUtils2.now() - startTime;
|
|
797
|
-
const remaining = Math.max(0,
|
|
820
|
+
const remaining = Math.max(0, delay2 - elapsed);
|
|
798
821
|
if (remaining > 0) {
|
|
799
822
|
await sleep(remaining);
|
|
800
823
|
}
|
|
@@ -850,7 +873,7 @@ data: ${JSON.stringify(event.data)}
|
|
|
850
873
|
if (onError) onError(error);
|
|
851
874
|
resolve();
|
|
852
875
|
}
|
|
853
|
-
},
|
|
876
|
+
}, delay);
|
|
854
877
|
});
|
|
855
878
|
}
|
|
856
879
|
/**
|
|
@@ -902,13 +925,14 @@ function installFetchMock(schema) {
|
|
|
902
925
|
console.log(`[Mock] Intercepted ${method} ${url}`, rule);
|
|
903
926
|
await sleep(rule.delay || 0);
|
|
904
927
|
const type = rule.type || "json";
|
|
928
|
+
const status = rule.status || 200;
|
|
905
929
|
const strategy = StrategyFactory.getStrategy(type);
|
|
906
930
|
const urlObj = new URL(url, window.location.origin);
|
|
907
931
|
const query = Object.fromEntries(urlObj.searchParams);
|
|
908
932
|
const result = strategy.process(rule, query);
|
|
909
933
|
if (type === "json") {
|
|
910
934
|
return new Response(JSON.stringify(result), {
|
|
911
|
-
status
|
|
935
|
+
status,
|
|
912
936
|
headers: { "Content-Type": "application/json" }
|
|
913
937
|
});
|
|
914
938
|
}
|
|
@@ -916,7 +940,7 @@ function installFetchMock(schema) {
|
|
|
916
940
|
const events = result;
|
|
917
941
|
const stream = eventsToStream(events);
|
|
918
942
|
return new Response(stream, {
|
|
919
|
-
status
|
|
943
|
+
status,
|
|
920
944
|
headers: { "Content-Type": "text/event-stream" }
|
|
921
945
|
});
|
|
922
946
|
}
|
package/dist/interceptor.js
CHANGED
|
@@ -30,6 +30,7 @@ export function installFetchMock(schema) {
|
|
|
30
30
|
await sleep(rule.delay || 0);
|
|
31
31
|
// Determine type (default 'json' if not present)
|
|
32
32
|
const type = rule.type || 'json';
|
|
33
|
+
const status = rule.status || 200;
|
|
33
34
|
const strategy = StrategyFactory.getStrategy(type);
|
|
34
35
|
// Parse query params for strategies that need them
|
|
35
36
|
const urlObj = new URL(url, window.location.origin);
|
|
@@ -38,7 +39,7 @@ export function installFetchMock(schema) {
|
|
|
38
39
|
/* 1. JSON Response */
|
|
39
40
|
if (type === 'json') {
|
|
40
41
|
return new Response(JSON.stringify(result), {
|
|
41
|
-
status
|
|
42
|
+
status,
|
|
42
43
|
headers: { 'Content-Type': 'application/json' },
|
|
43
44
|
});
|
|
44
45
|
}
|
|
@@ -47,7 +48,7 @@ export function installFetchMock(schema) {
|
|
|
47
48
|
const events = result; // Strategy returns MockEvent[]
|
|
48
49
|
const stream = eventsToStream(events);
|
|
49
50
|
return new Response(stream, {
|
|
50
|
-
status
|
|
51
|
+
status,
|
|
51
52
|
headers: { 'Content-Type': 'text/event-stream' }
|
|
52
53
|
});
|
|
53
54
|
}
|
package/dist/strategies.js
CHANGED
|
@@ -83,11 +83,20 @@ export class SsePageStrategy {
|
|
|
83
83
|
const events = flatEvents(ssePageConfig.responseSchema, requestParams);
|
|
84
84
|
// 2. Generate page event if exists
|
|
85
85
|
if (ssePageConfig.pageEvent) {
|
|
86
|
-
|
|
86
|
+
const context = {
|
|
87
|
+
$query: requestParams, // Backward compatibility
|
|
88
|
+
$body: requestParams,
|
|
89
|
+
$param: requestParams?.param || requestParams
|
|
90
|
+
};
|
|
91
|
+
Mock.Random.extend({
|
|
92
|
+
$query: () => context.$query,
|
|
93
|
+
$body: () => context.$body,
|
|
94
|
+
$param: () => context.$param
|
|
95
|
+
});
|
|
87
96
|
// First let Mock.js process standard templates (like @integer)
|
|
88
97
|
let pageEvent = Mock.mock(ssePageConfig.pageEvent);
|
|
89
98
|
// Then process custom {{}} templates
|
|
90
|
-
pageEvent = processTemplate(pageEvent,
|
|
99
|
+
pageEvent = processTemplate(pageEvent, context);
|
|
91
100
|
// Calculate max delay from existing events to ensure page event is last
|
|
92
101
|
let maxDelay = 0;
|
|
93
102
|
if (events.length > 0) {
|
package/dist/types.d.ts
CHANGED
package/dist/utils.d.ts
CHANGED
|
@@ -2,18 +2,17 @@ import { MockEvent } from './types';
|
|
|
2
2
|
export declare const sleep: (ms: number) => Promise<unknown>;
|
|
3
3
|
/**
|
|
4
4
|
* Process string templates like "{{$query.pageNo * 10}}" in object values.
|
|
5
|
-
*
|
|
5
|
+
* Supports $query (for backward compatibility), $body, and $param.
|
|
6
6
|
*/
|
|
7
7
|
export declare function processTemplate(data: any, context: Record<string, any>): any;
|
|
8
8
|
/**
|
|
9
9
|
* Flatten eventsSchema into a sorted array of events.
|
|
10
|
-
* It also extends Mock.Random with $query to access URL parameters.
|
|
11
10
|
*
|
|
12
11
|
* Supports Mock.js array generation rules in keys, e.g.:
|
|
13
12
|
* { 'data|8-12': [{ event: 'data', ... }] }
|
|
14
13
|
* -> generates 8 to 12 data events.
|
|
15
14
|
*/
|
|
16
|
-
export declare function flatEvents(eventsSchema: Record<string, MockEvent[]>,
|
|
15
|
+
export declare function flatEvents(eventsSchema: Record<string, MockEvent[]>, requestData?: any): MockEvent[];
|
|
17
16
|
/**
|
|
18
17
|
* Convert an array of events into a ReadableStream (for SSE).
|
|
19
18
|
*/
|
package/dist/utils.js
CHANGED
|
@@ -3,7 +3,7 @@ import Mock from 'mockjs';
|
|
|
3
3
|
export const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
4
4
|
/**
|
|
5
5
|
* Process string templates like "{{$query.pageNo * 10}}" in object values.
|
|
6
|
-
*
|
|
6
|
+
* Supports $query (for backward compatibility), $body, and $param.
|
|
7
7
|
*/
|
|
8
8
|
export function processTemplate(data, context) {
|
|
9
9
|
if (typeof data === 'string') {
|
|
@@ -38,26 +38,30 @@ export function processTemplate(data, context) {
|
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
40
|
* Flatten eventsSchema into a sorted array of events.
|
|
41
|
-
* It also extends Mock.Random with $query to access URL parameters.
|
|
42
41
|
*
|
|
43
42
|
* Supports Mock.js array generation rules in keys, e.g.:
|
|
44
43
|
* { 'data|8-12': [{ event: 'data', ... }] }
|
|
45
44
|
* -> generates 8 to 12 data events.
|
|
46
45
|
*/
|
|
47
|
-
export function flatEvents(eventsSchema,
|
|
48
|
-
//
|
|
46
|
+
export function flatEvents(eventsSchema, requestData = {}) {
|
|
47
|
+
// Construct context for template processing
|
|
48
|
+
const context = {
|
|
49
|
+
$query: requestData, // Backward compatibility
|
|
50
|
+
$body: requestData,
|
|
51
|
+
$param: requestData?.param || requestData
|
|
52
|
+
};
|
|
53
|
+
// Extend Mock.Random to support templates
|
|
49
54
|
Mock.Random.extend({
|
|
50
|
-
$query:
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
$query: () => context.$query,
|
|
56
|
+
$body: () => context.$body,
|
|
57
|
+
$param: () => context.$param
|
|
53
58
|
});
|
|
54
59
|
// Generate data using Mock.mock
|
|
55
|
-
// This handles keys like 'data|8-12' to generate arrays
|
|
56
60
|
const compiled = Mock.mock(eventsSchema);
|
|
57
61
|
// Flatten and sort by delay
|
|
58
62
|
return Object.values(compiled)
|
|
59
63
|
.flat()
|
|
60
|
-
.map(event => processTemplate(event,
|
|
64
|
+
.map(event => processTemplate(event, context))
|
|
61
65
|
.sort((a, b) => {
|
|
62
66
|
const delayA = typeof a.delay === 'number' ? a.delay : parseInt(String(a.delay || 0));
|
|
63
67
|
const delayB = typeof b.delay === 'number' ? b.delay : parseInt(String(b.delay || 0));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chatbi-v/mocks",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"main": "dist/index.cjs",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"mockjs": "^1.1.0",
|
|
22
|
-
"@chatbi-v/core": "
|
|
22
|
+
"@chatbi-v/core": "2.0.0"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
|
-
"@chatbi-v/cli": "1.0.
|
|
25
|
+
"@chatbi-v/cli": "1.0.9"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/mockjs": "^1.0.10",
|