@qlover/create-app 0.11.0 → 1.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/CHANGELOG.md +18 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +3 -3
- package/dist/templates/next-app/eslint.config.mjs +76 -1
- package/dist/templates/next-app/next.config.ts +4 -3
- package/dist/templates/next-app/package.json +15 -11
- package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +2 -3
- package/dist/templates/next-app/src/base/cases/DialogErrorPlugin.ts +6 -4
- package/dist/templates/next-app/src/base/cases/RequestEncryptPlugin.ts +14 -10
- package/dist/templates/next-app/src/base/cases/StringEncryptor.ts +2 -2
- package/dist/templates/next-app/src/base/port/I18nServiceInterface.ts +1 -4
- package/dist/templates/next-app/src/base/services/I18nService.ts +6 -2
- package/dist/templates/next-app/src/base/services/adminApi/AdminApiRequester.ts +11 -7
- package/dist/templates/next-app/src/base/services/adminApi/AdminLocalesApi.ts +11 -10
- package/dist/templates/next-app/src/base/services/adminApi/AdminUserApi.ts +16 -12
- package/dist/templates/next-app/src/base/services/appApi/AppApiPlugin.ts +19 -19
- package/dist/templates/next-app/src/base/services/appApi/AppApiRequester.ts +26 -21
- package/dist/templates/next-app/src/base/services/appApi/AppUserApi.ts +15 -6
- package/dist/templates/next-app/src/base/services/appApi/AppUserApiBootstrap.ts +12 -14
- package/dist/templates/next-app/src/core/bootstraps/BootstrapServer.ts +34 -17
- package/dist/templates/next-app/src/server/NextApiServer.ts +10 -4
- package/dist/templates/next-app/src/server/PasswordEncrypt.ts +2 -2
- package/dist/templates/next-app/src/server/controllers/UserController.ts +2 -2
- package/dist/templates/next-app/src/server/port/ServerInterface.ts +2 -2
- package/dist/templates/next-app/src/server/services/AdminAuthPlugin.ts +6 -7
- package/dist/templates/next-app/src/server/services/UserService.ts +2 -2
- package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +11 -47
- package/dist/templates/react-app/__tests__/__mocks__/MockDialogHandler.ts +3 -2
- package/dist/templates/react-app/__tests__/__mocks__/createMockGlobals.ts +6 -1
- package/dist/templates/react-app/__tests__/src/base/cases/I18nKeyErrorPlugin.test.ts +21 -61
- package/dist/templates/react-app/__tests__/src/base/cases/RequestLogger.test.ts +29 -51
- package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapClient.test.ts +8 -26
- package/dist/templates/react-app/__tests__/src/main.test.tsx +2 -2
- package/dist/templates/react-app/config/IOCIdentifier.ts +1 -1
- package/dist/templates/react-app/docs/en/test-guide.md +5 -5
- package/dist/templates/react-app/docs/zh/test-guide.md +5 -5
- package/dist/templates/react-app/eslint.config.mjs +79 -7
- package/dist/templates/react-app/package.json +4 -3
- package/dist/templates/react-app/src/base/apis/AiApi.ts +20 -12
- package/dist/templates/react-app/src/base/apis/feApi/FeApi.ts +14 -5
- package/dist/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +29 -13
- package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +35 -34
- package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +23 -17
- package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +11 -5
- package/dist/templates/react-app/src/base/cases/RequestLanguages.ts +19 -6
- package/dist/templates/react-app/src/base/cases/RequestLogger.ts +11 -11
- package/dist/templates/react-app/src/base/services/BaseLayoutService.ts +11 -5
- package/dist/templates/react-app/src/base/services/I18nService.ts +3 -0
- package/dist/templates/react-app/src/base/services/IdentifierService.ts +24 -0
- package/dist/templates/react-app/src/base/services/UserBootstrap.ts +9 -7
- package/dist/templates/react-app/src/base/services/UserService.ts +4 -5
- package/dist/templates/react-app/src/core/clientIoc/ClientIOCRegister.ts +6 -7
- package/dist/templates/react-app/src/main.tsx +1 -1
- package/dist/templates/react-app/src/pages/auth/LoginPage.tsx +5 -5
- package/dist/templates/react-app/src/pages/base/ExecutorPage.tsx +3 -1
- package/dist/templates/react-app/src/pages/base/JSONStoragePage.tsx +6 -2
- package/dist/templates/react-app/src/pages/base/MessagePage.tsx +34 -3
- package/dist/templates/react-app/src/uikit/bridges/ExecutorPageBridge.ts +13 -7
- package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +6 -1
- package/dist/templates/react-app/src/uikit/components/MessageBaseList.tsx +26 -11
- package/dist/templates/react-app/src/uikit/components/chatMessage/ChatMessageBridge.ts +7 -1
- package/dist/templates/react-app/src/uikit/components/chatMessage/FocusBar.tsx +3 -1
- package/dist/templates/react-app/src/uikit/components/chatMessage/MessageApi.ts +16 -7
- package/dist/templates/react-app/src/vite-env.d.ts +1 -1
- package/dist/templates/react-app/tsconfig.e2e.json +5 -2
- package/dist/templates/react-app/tsconfig.json +7 -0
- package/dist/templates/react-app/tsconfig.node.json +4 -2
- package/dist/templates/react-app/tsconfig.test.json +4 -1
- package/package.json +4 -3
- package/dist/templates/react-app/src/base/cases/AppError.ts +0 -10
- package/dist/templates/react-app/src/base/port/ProcesserExecutorInterface.ts +0 -20
- package/dist/templates/react-app/src/base/services/UserGatewayPlugin.ts +0 -20
|
@@ -10,17 +10,14 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { MockLogger } from '@__mocks__/MockLogger';
|
|
13
|
+
import {
|
|
14
|
+
ExecutorContextImpl,
|
|
15
|
+
type RequestAdapterFetchConfig,
|
|
16
|
+
type RequestAdapterResponse
|
|
17
|
+
} from '@qlover/fe-corekit';
|
|
13
18
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
14
19
|
import { RequestLogger } from '@/base/cases/RequestLogger';
|
|
15
|
-
import type {
|
|
16
|
-
ApiCatchPluginConfig,
|
|
17
|
-
ApiCatchPluginResponse
|
|
18
|
-
} from '@qlover/corekit-bridge';
|
|
19
|
-
import type {
|
|
20
|
-
ExecutorContext,
|
|
21
|
-
RequestAdapterFetchConfig,
|
|
22
|
-
RequestAdapterResponse
|
|
23
|
-
} from '@qlover/fe-corekit';
|
|
20
|
+
import type { ApiCatchPluginResponse } from '@qlover/corekit-bridge';
|
|
24
21
|
|
|
25
22
|
describe('RequestLogger', () => {
|
|
26
23
|
let logger: MockLogger;
|
|
@@ -46,16 +43,11 @@ describe('RequestLogger', () => {
|
|
|
46
43
|
|
|
47
44
|
describe('onBefore', () => {
|
|
48
45
|
it('should log request details before execution', () => {
|
|
49
|
-
const context
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
},
|
|
55
|
-
returnValue: undefined,
|
|
56
|
-
hooksRuntimes: {}
|
|
57
|
-
};
|
|
58
|
-
|
|
46
|
+
const context = new ExecutorContextImpl({
|
|
47
|
+
method: 'GET',
|
|
48
|
+
url: 'https://api.example.com/data',
|
|
49
|
+
headers: { 'Content-Type': 'application/json' }
|
|
50
|
+
});
|
|
59
51
|
requestLogger.onBefore(context);
|
|
60
52
|
|
|
61
53
|
expect(logger.log).toHaveBeenCalledWith(
|
|
@@ -70,17 +62,12 @@ describe('RequestLogger', () => {
|
|
|
70
62
|
describe('onSuccess', () => {
|
|
71
63
|
it('should log successful response', async () => {
|
|
72
64
|
const response = { data: { id: 1 }, status: 200 };
|
|
73
|
-
const context
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
headers: { 'Content-Type': 'application/json' }
|
|
80
|
-
},
|
|
81
|
-
returnValue: response,
|
|
82
|
-
hooksRuntimes: {}
|
|
83
|
-
};
|
|
65
|
+
const context = new ExecutorContextImpl({
|
|
66
|
+
method: 'POST',
|
|
67
|
+
url: 'https://api.example.com/create',
|
|
68
|
+
headers: { 'Content-Type': 'application/json' }
|
|
69
|
+
});
|
|
70
|
+
context.setReturnValue(response);
|
|
84
71
|
|
|
85
72
|
await requestLogger.onSuccess(context);
|
|
86
73
|
|
|
@@ -111,17 +98,12 @@ describe('RequestLogger', () => {
|
|
|
111
98
|
response: new Response(),
|
|
112
99
|
apiCatchResult: apiError
|
|
113
100
|
};
|
|
114
|
-
const context
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
headers: {}
|
|
121
|
-
},
|
|
122
|
-
returnValue: response,
|
|
123
|
-
hooksRuntimes: {}
|
|
124
|
-
};
|
|
101
|
+
const context = new ExecutorContextImpl({
|
|
102
|
+
method: 'GET',
|
|
103
|
+
url: 'https://api.example.com/error',
|
|
104
|
+
headers: {}
|
|
105
|
+
});
|
|
106
|
+
context.setReturnValue(response);
|
|
125
107
|
|
|
126
108
|
await requestLogger.onSuccess(context);
|
|
127
109
|
|
|
@@ -137,16 +119,12 @@ describe('RequestLogger', () => {
|
|
|
137
119
|
describe('onError', () => {
|
|
138
120
|
it('should log request error', () => {
|
|
139
121
|
const error = new Error('Network error');
|
|
140
|
-
const context
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
error,
|
|
147
|
-
returnValue: undefined,
|
|
148
|
-
hooksRuntimes: {}
|
|
149
|
-
};
|
|
122
|
+
const context = new ExecutorContextImpl({
|
|
123
|
+
method: 'PUT',
|
|
124
|
+
url: 'https://api.example.com/update',
|
|
125
|
+
headers: {}
|
|
126
|
+
});
|
|
127
|
+
context.setError(error);
|
|
150
128
|
|
|
151
129
|
requestLogger.onError(context);
|
|
152
130
|
|
|
@@ -19,7 +19,6 @@ import type {
|
|
|
19
19
|
IOCContainerInterface,
|
|
20
20
|
IOCFunctionInterface
|
|
21
21
|
} from '@qlover/corekit-bridge';
|
|
22
|
-
import type { ExecutorPlugin } from '@qlover/fe-corekit';
|
|
23
22
|
|
|
24
23
|
describe('BootstrapClient', () => {
|
|
25
24
|
describe('bootstrap start flow', () => {
|
|
@@ -98,18 +97,19 @@ describe('BootstrapClient', () => {
|
|
|
98
97
|
});
|
|
99
98
|
|
|
100
99
|
it('should handle bootstrap UserApiBootstarp', async () => {
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
const mockOnExec = vi.fn().mockResolvedValue(undefined);
|
|
101
|
+
const mockUserBootstrap: BootstrapExecutorPlugin = {
|
|
102
|
+
pluginName: 'TestUserBootstrap',
|
|
103
|
+
onExec: mockOnExec
|
|
104
104
|
};
|
|
105
105
|
// 将 mock 函数提取出来,以便验证是否被调用
|
|
106
106
|
const mockRegister = vi
|
|
107
107
|
.fn()
|
|
108
108
|
.mockImplementationOnce(
|
|
109
109
|
(
|
|
110
|
-
|
|
110
|
+
_ioc: IOCFunctionInterface<IOCIdentifierMap, IOCContainerInterface>
|
|
111
111
|
) => {
|
|
112
|
-
return [
|
|
112
|
+
return [mockUserBootstrap];
|
|
113
113
|
}
|
|
114
114
|
);
|
|
115
115
|
|
|
@@ -121,20 +121,6 @@ describe('BootstrapClient', () => {
|
|
|
121
121
|
root: mockRoot,
|
|
122
122
|
bootHref: mockRoot.location.href,
|
|
123
123
|
ioc: testIOC,
|
|
124
|
-
iocRegister: {
|
|
125
|
-
register: vi
|
|
126
|
-
.fn()
|
|
127
|
-
.mockImplementationOnce(
|
|
128
|
-
(
|
|
129
|
-
ioc: IOCFunctionInterface<
|
|
130
|
-
IOCIdentifierMap,
|
|
131
|
-
IOCContainerInterface
|
|
132
|
-
>
|
|
133
|
-
) => {
|
|
134
|
-
ioc.bind(I.UserServiceInterface, mockUserService as any);
|
|
135
|
-
}
|
|
136
|
-
)
|
|
137
|
-
},
|
|
138
124
|
RegistryClass: TestBootstrapsRegistry
|
|
139
125
|
};
|
|
140
126
|
|
|
@@ -142,12 +128,8 @@ describe('BootstrapClient', () => {
|
|
|
142
128
|
const ioc = testIOC.getIoc();
|
|
143
129
|
expect(ioc).toBeDefined();
|
|
144
130
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
expect(userService).toBeDefined();
|
|
148
|
-
expect(userService).toEqual(mockUserService);
|
|
149
|
-
expect(userService.pluginName).toBe('TestUserService');
|
|
150
|
-
expect(userService.onBefore).toBeCalled();
|
|
131
|
+
expect(mockRegister).toBeCalled();
|
|
132
|
+
expect(mockOnExec).toBeCalled();
|
|
151
133
|
});
|
|
152
134
|
});
|
|
153
135
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BootstrapClient } from '@/core/bootstraps/BootstrapClient';
|
|
2
2
|
|
|
3
|
-
// Mock BootstrapApp
|
|
3
|
+
// Mock BootstrapApp - must return a resolved promise to prevent hanging
|
|
4
4
|
vi.mock('@/core/bootstraps/BootstrapClient', () => ({
|
|
5
5
|
BootstrapClient: {
|
|
6
|
-
main: vi.fn()
|
|
6
|
+
main: vi.fn().mockResolvedValue({})
|
|
7
7
|
}
|
|
8
8
|
}));
|
|
9
9
|
|
|
@@ -81,7 +81,7 @@ export interface IOCIdentifierMap {
|
|
|
81
81
|
[IOCIdentifier.RouteServiceInterface]: RouteService;
|
|
82
82
|
[IOCIdentifier.UserServiceInterface]: UserService;
|
|
83
83
|
[IOCIdentifier.I18nKeyErrorPlugin]: I18nKeyErrorPlugin;
|
|
84
|
-
[IOCIdentifier.FeApiCommonPlugin]:
|
|
84
|
+
[IOCIdentifier.FeApiCommonPlugin]: FeCorekit.RequestPlugin;
|
|
85
85
|
[IOCIdentifier.ApiMockPlugin]: CorekitBridge.ApiMockPlugin;
|
|
86
86
|
[IOCIdentifier.ApiCatchPlugin]: CorekitBridge.ApiCatchPlugin;
|
|
87
87
|
[IOCIdentifier.ThemeService]: CorekitBridge.ThemeService;
|
|
@@ -652,7 +652,7 @@ describe('TypeSafetyTests', () => {
|
|
|
652
652
|
|
|
653
653
|
it('should infer correct return types', () => {
|
|
654
654
|
const result = getData();
|
|
655
|
-
|
|
655
|
+
|
|
656
656
|
// Verify return type
|
|
657
657
|
expectTypeOf(result).toEqualTypeOf<{ id: number; name: string }>();
|
|
658
658
|
expectTypeOf(result).not.toEqualTypeOf<{ id: string; name: string }>();
|
|
@@ -682,7 +682,7 @@ describe('Generic Type Tests', () => {
|
|
|
682
682
|
}
|
|
683
683
|
|
|
684
684
|
const storage = new Storage<User>();
|
|
685
|
-
|
|
685
|
+
|
|
686
686
|
// Verify generic type
|
|
687
687
|
expectTypeOf(storage.store).parameter(0).toMatchTypeOf<User>();
|
|
688
688
|
expectTypeOf(storage.store).returns.toMatchTypeOf<User>();
|
|
@@ -755,7 +755,7 @@ describe('Type Narrowing Tests', () => {
|
|
|
755
755
|
}
|
|
756
756
|
|
|
757
757
|
const value: unknown = 'test';
|
|
758
|
-
|
|
758
|
+
|
|
759
759
|
if (isString(value)) {
|
|
760
760
|
// Within this scope, value should be narrowed to string type
|
|
761
761
|
expectTypeOf(value).toEqualTypeOf<string>();
|
|
@@ -763,7 +763,7 @@ describe('Type Narrowing Tests', () => {
|
|
|
763
763
|
});
|
|
764
764
|
|
|
765
765
|
it('should validate discriminated unions', () => {
|
|
766
|
-
type Shape =
|
|
766
|
+
type Shape =
|
|
767
767
|
| { kind: 'circle'; radius: number }
|
|
768
768
|
| { kind: 'rectangle'; width: number; height: number };
|
|
769
769
|
|
|
@@ -812,7 +812,7 @@ describe('Combined Runtime and Type Tests', () => {
|
|
|
812
812
|
describe('Type Inference Tests', () => {
|
|
813
813
|
it('should infer types correctly', () => {
|
|
814
814
|
const data = { id: 1, name: 'John' };
|
|
815
|
-
|
|
815
|
+
|
|
816
816
|
// Verify inferred type
|
|
817
817
|
expectTypeOf(data).toEqualTypeOf<{ id: number; name: string }>();
|
|
818
818
|
expectTypeOf(data.id).toEqualTypeOf<number>();
|
|
@@ -652,7 +652,7 @@ describe('TypeSafetyTests', () => {
|
|
|
652
652
|
|
|
653
653
|
it('should infer correct return types', () => {
|
|
654
654
|
const result = getData();
|
|
655
|
-
|
|
655
|
+
|
|
656
656
|
// 验证返回值类型
|
|
657
657
|
expectTypeOf(result).toEqualTypeOf<{ id: number; name: string }>();
|
|
658
658
|
expectTypeOf(result).not.toEqualTypeOf<{ id: string; name: string }>();
|
|
@@ -682,7 +682,7 @@ describe('Generic Type Tests', () => {
|
|
|
682
682
|
}
|
|
683
683
|
|
|
684
684
|
const storage = new Storage<User>();
|
|
685
|
-
|
|
685
|
+
|
|
686
686
|
// 验证泛型类型
|
|
687
687
|
expectTypeOf(storage.store).parameter(0).toMatchTypeOf<User>();
|
|
688
688
|
expectTypeOf(storage.store).returns.toMatchTypeOf<User>();
|
|
@@ -755,7 +755,7 @@ describe('Type Narrowing Tests', () => {
|
|
|
755
755
|
}
|
|
756
756
|
|
|
757
757
|
const value: unknown = 'test';
|
|
758
|
-
|
|
758
|
+
|
|
759
759
|
if (isString(value)) {
|
|
760
760
|
// 在此作用域内,value 应该被窄化为 string 类型
|
|
761
761
|
expectTypeOf(value).toEqualTypeOf<string>();
|
|
@@ -763,7 +763,7 @@ describe('Type Narrowing Tests', () => {
|
|
|
763
763
|
});
|
|
764
764
|
|
|
765
765
|
it('should validate discriminated unions', () => {
|
|
766
|
-
type Shape =
|
|
766
|
+
type Shape =
|
|
767
767
|
| { kind: 'circle'; radius: number }
|
|
768
768
|
| { kind: 'rectangle'; width: number; height: number };
|
|
769
769
|
|
|
@@ -812,7 +812,7 @@ describe('Combined Runtime and Type Tests', () => {
|
|
|
812
812
|
describe('Type Inference Tests', () => {
|
|
813
813
|
it('should infer types correctly', () => {
|
|
814
814
|
const data = { id: 1, name: 'John' };
|
|
815
|
-
|
|
815
|
+
|
|
816
816
|
// 验证推断的类型
|
|
817
817
|
expectTypeOf(data).toEqualTypeOf<{ id: number; name: string }>();
|
|
818
818
|
expectTypeOf(data.id).toEqualTypeOf<number>();
|
|
@@ -92,17 +92,14 @@ const eslintConfig = [
|
|
|
92
92
|
'storybook-static/**'
|
|
93
93
|
]
|
|
94
94
|
},
|
|
95
|
+
|
|
95
96
|
{
|
|
96
97
|
files: ['**/*.{js,jsx,ts,tsx}'],
|
|
97
98
|
languageOptions: {
|
|
98
99
|
parser: tseslint.parser,
|
|
99
100
|
parserOptions: {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
'./tsconfig.node.json',
|
|
103
|
-
'./tsconfig.test.json',
|
|
104
|
-
'./tsconfig.e2e.json'
|
|
105
|
-
],
|
|
101
|
+
// Note: 'project' is removed here to avoid conflict with projectService in the type-checked config below
|
|
102
|
+
// TypeScript files will get type information from the recommendedTypeChecked config
|
|
106
103
|
tsconfigRootDir: __dirname
|
|
107
104
|
}
|
|
108
105
|
},
|
|
@@ -116,7 +113,7 @@ const eslintConfig = [
|
|
|
116
113
|
rules: {
|
|
117
114
|
'@qlover-eslint/ts-class-method-return': 'error',
|
|
118
115
|
'@qlover-eslint/ts-class-member-accessibility': 'error',
|
|
119
|
-
'@qlover-eslint/ts-class-override': '
|
|
116
|
+
'@qlover-eslint/ts-class-override': 'off',
|
|
120
117
|
'@qlover-eslint/require-root-testid': [
|
|
121
118
|
'error',
|
|
122
119
|
{
|
|
@@ -202,6 +199,81 @@ const eslintConfig = [
|
|
|
202
199
|
'import/no-default-export': 'error'
|
|
203
200
|
}
|
|
204
201
|
},
|
|
202
|
+
|
|
203
|
+
// TypeScript files with type checking for ts-class-override rule
|
|
204
|
+
// The ts-class-override rule requires full type information to accurately detect:
|
|
205
|
+
// - Methods that override parent class methods (via extends)
|
|
206
|
+
// - Methods that implement interface methods (via implements)
|
|
207
|
+
// Without type checking, the rule falls back to AST-based heuristics which are less accurate
|
|
208
|
+
// This separate config block enables type checking only for TypeScript files to provide
|
|
209
|
+
// accurate override detection while maintaining good performance
|
|
210
|
+
...tseslint.configs.recommendedTypeChecked.map((config) => ({
|
|
211
|
+
...config,
|
|
212
|
+
files: ['src/**/*.{ts,tsx}'],
|
|
213
|
+
ignores: [
|
|
214
|
+
'**/dist/**',
|
|
215
|
+
'**/build/**',
|
|
216
|
+
'**/ts-build/**',
|
|
217
|
+
'**/node_modules/**',
|
|
218
|
+
'**/.nx/**',
|
|
219
|
+
'**/.cache/**',
|
|
220
|
+
'**/coverage/**',
|
|
221
|
+
'**/*.d.ts',
|
|
222
|
+
'**/*.config.ts',
|
|
223
|
+
'**/*.test.ts',
|
|
224
|
+
'**/__mocks__/**',
|
|
225
|
+
'**/__tests__/**',
|
|
226
|
+
'**/*.spec.ts',
|
|
227
|
+
...(config.ignores || [])
|
|
228
|
+
],
|
|
229
|
+
languageOptions: {
|
|
230
|
+
...config.languageOptions,
|
|
231
|
+
parserOptions: {
|
|
232
|
+
...config.languageOptions?.parserOptions,
|
|
233
|
+
project: './tsconfig.app.json',
|
|
234
|
+
tsconfigRootDir: __dirname
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
plugins: {
|
|
238
|
+
...config.plugins,
|
|
239
|
+
'@qlover-eslint': qloverEslint
|
|
240
|
+
},
|
|
241
|
+
rules: {
|
|
242
|
+
...config.rules,
|
|
243
|
+
// Enable ts-class-override rule with full type information
|
|
244
|
+
// This rule is disabled in the base config above and only enabled here where
|
|
245
|
+
// type information is available, ensuring accurate detection of override relationships
|
|
246
|
+
'@qlover-eslint/ts-class-override': 'error',
|
|
247
|
+
// Disable other type-checked rules to avoid performance impact
|
|
248
|
+
// We only need type checking for ts-class-override, so we disable other
|
|
249
|
+
// type-aware rules that would slow down linting without providing value
|
|
250
|
+
'@typescript-eslint/ban-ts-comment': 'off',
|
|
251
|
+
'@typescript-eslint/restrict-template-expressions': 'off',
|
|
252
|
+
'@typescript-eslint/no-unsafe-assignment': 'off',
|
|
253
|
+
'@typescript-eslint/no-unnecessary-type-assertion': 'off',
|
|
254
|
+
'@typescript-eslint/no-redundant-type-constituents': 'off',
|
|
255
|
+
'@typescript-eslint/no-unsafe-return': 'off',
|
|
256
|
+
'@typescript-eslint/no-empty-object-type': 'off',
|
|
257
|
+
'@typescript-eslint/no-unsafe-call': 'off',
|
|
258
|
+
'@typescript-eslint/no-unsafe-member-access': 'off',
|
|
259
|
+
'@typescript-eslint/no-unsafe-argument': 'off',
|
|
260
|
+
'@typescript-eslint/no-unsafe-enum-comparison': 'off',
|
|
261
|
+
'@typescript-eslint/no-unsafe-literal-comparison': 'off',
|
|
262
|
+
'@typescript-eslint/no-unsafe-nullish-coalescing': 'off',
|
|
263
|
+
'@typescript-eslint/no-unsafe-optional-chaining': 'off',
|
|
264
|
+
'@typescript-eslint/unbound-method': 'off',
|
|
265
|
+
'@typescript-eslint/await-thenable': 'off',
|
|
266
|
+
'@typescript-eslint/no-floating-promises': 'off',
|
|
267
|
+
'@typescript-eslint/no-misused-promises': 'off',
|
|
268
|
+
'@typescript-eslint/require-await': 'off',
|
|
269
|
+
'@typescript-eslint/no-base-to-string': 'off',
|
|
270
|
+
'@typescript-eslint/prefer-promise-reject-errors': 'off',
|
|
271
|
+
'@typescript-eslint/no-duplicate-type-constituents': 'off',
|
|
272
|
+
// Disable @typescript-eslint/no-unused-vars as we use unused-imports/no-unused-vars instead
|
|
273
|
+
'@typescript-eslint/no-unused-vars': 'off',
|
|
274
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
275
|
+
}
|
|
276
|
+
})),
|
|
205
277
|
{
|
|
206
278
|
// TODO: antd override theme need use import type
|
|
207
279
|
files: ['src/base/types/deprecated-antd.d.ts'],
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"build:staging": "npm run lint && vite build --mode staging",
|
|
37
37
|
"build:prod": "npm run lint && vite build --mode production",
|
|
38
38
|
"build:analyze": "vite build --mode production && start dist/stats.html",
|
|
39
|
-
"lint": "eslint
|
|
40
|
-
"lint:fix": "eslint
|
|
39
|
+
"lint": "eslint",
|
|
40
|
+
"lint:fix": "eslint --ext .ts,.tsx --fix",
|
|
41
41
|
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,css,scss,md}\"",
|
|
42
42
|
"format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json,css,scss,md}\"",
|
|
43
43
|
"fix": "npm run lint:fix && npm run format",
|
|
@@ -52,7 +52,8 @@
|
|
|
52
52
|
"test:e2e:chromium": "playwright test --project=chromium",
|
|
53
53
|
"test:e2e:firefox": "playwright test --project=firefox",
|
|
54
54
|
"test:e2e:webkit": "playwright test --project=webkit",
|
|
55
|
-
"test:e2e:report": "playwright show-report playwright-report"
|
|
55
|
+
"test:e2e:report": "playwright show-report playwright-report",
|
|
56
|
+
"type-check": "tsc --build"
|
|
56
57
|
},
|
|
57
58
|
"dependencies": {
|
|
58
59
|
"@brain-toolkit/antd-blocks": "^0.0.1",
|
|
@@ -1,22 +1,30 @@
|
|
|
1
1
|
import { IOCIdentifier } from '@config/IOCIdentifier';
|
|
2
|
+
import { type BootstrapExecutorPlugin } from '@qlover/corekit-bridge';
|
|
2
3
|
import {
|
|
3
|
-
|
|
4
|
-
RequestCommonPlugin
|
|
5
|
-
} from '@qlover/corekit-bridge';
|
|
6
|
-
import {
|
|
7
|
-
FetchURLPlugin,
|
|
4
|
+
LifecycleExecutor,
|
|
8
5
|
RequestAdapterFetch,
|
|
9
|
-
|
|
6
|
+
RequestExecutor,
|
|
7
|
+
RequestPlugin,
|
|
8
|
+
ResponsePlugin
|
|
10
9
|
} from '@qlover/fe-corekit';
|
|
11
10
|
import { RequestLogger } from '../cases/RequestLogger';
|
|
12
11
|
import type { AppConfig } from '../cases/AppConfig';
|
|
12
|
+
import type {
|
|
13
|
+
ExecutorContextInterface,
|
|
14
|
+
RequestAdapterFetchConfig
|
|
15
|
+
} from '@qlover/fe-corekit';
|
|
13
16
|
|
|
14
17
|
const apiApiAdapter = new RequestAdapterFetch({
|
|
15
18
|
responseType: 'json'
|
|
16
19
|
});
|
|
17
20
|
|
|
18
21
|
// 使用 RequestScheduler
|
|
19
|
-
const apiApi = new
|
|
22
|
+
const apiApi = new RequestExecutor(
|
|
23
|
+
apiApiAdapter,
|
|
24
|
+
new LifecycleExecutor<
|
|
25
|
+
ExecutorContextInterface<RequestAdapterFetchConfig, unknown>
|
|
26
|
+
>()
|
|
27
|
+
);
|
|
20
28
|
|
|
21
29
|
// 直接使用 adapter
|
|
22
30
|
// const apiApi = apiApiAdapter;
|
|
@@ -29,15 +37,15 @@ export const AiApiBootstarp: BootstrapExecutorPlugin = {
|
|
|
29
37
|
// dynamic set baseURL
|
|
30
38
|
apiApiAdapter.config.baseURL = appConfig.aiApiBaseUrl;
|
|
31
39
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
new RequestCommonPlugin({
|
|
40
|
+
apiApi.use(
|
|
41
|
+
new RequestPlugin({
|
|
35
42
|
tokenPrefix: appConfig.aiApiTokenPrefix,
|
|
36
43
|
token: appConfig.aiApiToken
|
|
37
44
|
})
|
|
38
45
|
);
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
apiApi.use(ioc.get(ResponsePlugin));
|
|
47
|
+
apiApi.use(ioc.get(IOCIdentifier.ApiMockPlugin));
|
|
48
|
+
apiApi.use(ioc.get(RequestLogger));
|
|
41
49
|
}
|
|
42
50
|
};
|
|
43
51
|
|
|
@@ -1,17 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ExecutorContextInterface,
|
|
3
|
+
LifecycleExecutor,
|
|
4
|
+
RequestAdapterFetch,
|
|
5
|
+
RequestExecutor
|
|
6
|
+
} from '@qlover/fe-corekit';
|
|
2
7
|
import { inject, injectable } from 'inversify';
|
|
3
8
|
import { FeApiAdapter } from './FeApiAdapter';
|
|
4
9
|
import { FeApiConfig } from './FeApiBootstarp';
|
|
5
10
|
import { FeApiGetIpInfo } from './FeApiType';
|
|
6
11
|
|
|
7
12
|
@injectable()
|
|
8
|
-
export class FeApi extends
|
|
13
|
+
export class FeApi extends RequestExecutor<
|
|
14
|
+
FeApiConfig,
|
|
15
|
+
ExecutorContextInterface<FeApiConfig>
|
|
16
|
+
> {
|
|
9
17
|
constructor(@inject(FeApiAdapter) adapter: RequestAdapterFetch) {
|
|
10
|
-
super(
|
|
18
|
+
super(
|
|
19
|
+
adapter,
|
|
20
|
+
new LifecycleExecutor<ExecutorContextInterface<FeApiConfig, unknown>>()
|
|
21
|
+
);
|
|
11
22
|
}
|
|
12
23
|
|
|
13
|
-
public stop(_config: FeApiConfig): void {}
|
|
14
|
-
|
|
15
24
|
public async getIpInfo(): Promise<FeApiGetIpInfo['response']> {
|
|
16
25
|
return this.get('http://ip-api.com/json/') as unknown as Promise<
|
|
17
26
|
FeApiGetIpInfo['response']
|
|
@@ -1,18 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { I } from '@config/IOCIdentifier';
|
|
2
2
|
import {
|
|
3
3
|
type BootstrapContext,
|
|
4
4
|
type BootstrapExecutorPlugin,
|
|
5
5
|
type ApiMockPluginConfig,
|
|
6
6
|
ApiPickDataPlugin
|
|
7
7
|
} from '@qlover/corekit-bridge';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
RequestPlugin,
|
|
10
|
+
ResponsePlugin,
|
|
11
|
+
type RequestAdapterConfig,
|
|
12
|
+
type RequestAdapterResponse
|
|
13
|
+
} from '@qlover/fe-corekit';
|
|
14
|
+
import type { AppConfig } from '@/base/cases/AppConfig';
|
|
9
15
|
import { RequestLogger } from '@/base/cases/RequestLogger';
|
|
16
|
+
import type { UserService } from '@/base/services/UserService';
|
|
10
17
|
import { FeApi } from './FeApi';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
18
|
+
|
|
19
|
+
export interface RequestTransactionInterface<Request, Response> {
|
|
20
|
+
request: Request;
|
|
21
|
+
response: Response;
|
|
22
|
+
}
|
|
16
23
|
|
|
17
24
|
/**
|
|
18
25
|
* FeApiConfig
|
|
@@ -22,8 +29,8 @@ import type {
|
|
|
22
29
|
*
|
|
23
30
|
* extends:
|
|
24
31
|
*/
|
|
25
|
-
export
|
|
26
|
-
|
|
32
|
+
export type FeApiConfig<Request = unknown> = RequestAdapterConfig<Request> &
|
|
33
|
+
ApiMockPluginConfig & {};
|
|
27
34
|
|
|
28
35
|
/**
|
|
29
36
|
* FeApiResponse
|
|
@@ -59,12 +66,21 @@ export interface FeApiTransaction<
|
|
|
59
66
|
export class FeApiBootstarp implements BootstrapExecutorPlugin {
|
|
60
67
|
public readonly pluginName = 'FeApiBootstarp';
|
|
61
68
|
|
|
69
|
+
/**
|
|
70
|
+
* @override
|
|
71
|
+
*/
|
|
62
72
|
public onBefore({ parameters: { ioc } }: BootstrapContext): void {
|
|
73
|
+
const appConfig = ioc.get<AppConfig>(I.AppConfig);
|
|
63
74
|
ioc
|
|
64
75
|
.get<FeApi>(FeApi)
|
|
65
|
-
.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
76
|
+
.use(
|
|
77
|
+
new RequestPlugin({
|
|
78
|
+
tokenPrefix: appConfig.openAiTokenPrefix,
|
|
79
|
+
token: () => ioc.get<UserService>(I.UserServiceInterface).getToken()
|
|
80
|
+
})
|
|
81
|
+
)
|
|
82
|
+
.use(ioc.get(ResponsePlugin))
|
|
83
|
+
.use(ioc.get(RequestLogger))
|
|
84
|
+
.use(ioc.get(ApiPickDataPlugin));
|
|
69
85
|
}
|
|
70
86
|
}
|