Skip to content

Commit 5096e57

Browse files
cmtlytcmtlyt
andauthored
feat: feature/0.4.0 (#18)
* feat: feature/0.4.0 * style: types.ts --------- Co-authored-by: cmtlyt <cmt01964896@taobao.com>
1 parent 03737be commit 5096e57

File tree

17 files changed

+246
-76
lines changed

17 files changed

+246
-76
lines changed

src/constant/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ import type { ModuleType } from '../types';
22

33
export const NEED_READ_PROTOTYPE_TYPES = ['controller', 'service'];
44

5-
export const NEED_RETURN_TYPES = ['config', 'extend', 'middlewares', 'router', 'controller', 'service'];
5+
export const NEED_RETURN_TYPES = ['config', 'extend', 'routerSchema', 'service', 'middlewares', 'controller', 'router'];
66

77
export const MODULE_LOAD_ORDER: ModuleType[] = ['config', 'extend', 'routerSchema', 'service', 'middlewares', 'controller', 'router'];

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export * from './build';
77
export * from './constant';
88
export * from './define';
99

10-
export type { TeeOptions } from './types';
10+
export type { TeeMiddlewareCtx, TeeOptions } from './types';
1111
export { getEnv } from './utils';
1212

1313
export type { Defu as MergeConfig } from 'defu';
@@ -24,13 +24,13 @@ declare namespace TeeKoa {
2424

2525
interface Context extends Koa.DefaultContext {
2626
config: IComputedConfig;
27-
routerSchema: IRouterSchema;
2827
}
2928

3029
interface Application extends Koa<Koa.DefaultState, Context>, IExtend {
3130
middlewares: IMiddlewares;
3231
controller: IController;
3332
service: IService;
33+
routerSchema: IRouterSchema;
3434
}
3535

3636
interface AppOptions {

src/types.ts

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type KoaRouter from '@koa/router';
22
import type { Jiti } from 'jiti';
33
import type { Server } from 'node:http';
4-
54
import type TeeKoa from '.';
65

76
export { TeeKoa };
@@ -11,6 +10,11 @@ export { TeeKoa };
1110
*/
1211
export type ModuleType = 'controller' | 'service' | 'middlewares' | 'router' | 'config' | 'extend' | 'routerSchema';
1312

13+
export interface ModuleInfo {
14+
content: any;
15+
[key: string]: any;
16+
}
17+
1418
export interface FileInfo {
1519
/**
1620
* 模块类型
@@ -35,7 +39,7 @@ export interface FileInfo {
3539
/**
3640
* 模块内容
3741
*/
38-
module?: any;
42+
moduleInfo?: ModuleInfo;
3943
}
4044

4145
export type FileInfoMap = Record<ModuleType, FileInfo[]>;
@@ -91,7 +95,7 @@ export interface GenerateTypeOptions {
9195
/**
9296
* 模块加载完成钩子
9397
*/
94-
onModulesLoaded?: (type: string, modules: FileInfo[]) => any;
98+
onModulesLoaded?: (type: string, modules: DeepRequired<FileInfo>[]) => any;
9599
};
96100
}
97101

@@ -146,9 +150,9 @@ export interface ModuleHook {
146150
/**
147151
* 模块加载完成钩子
148152
*
149-
* 用于将模块内容注入到上下文, 只有在内置模块无法处理时调用
153+
* 用于将模块内容注入到上下文
150154
*
151-
* 返回 true 表示已处理, 返回 false 则表示未处理并跳出警告
155+
* 返回 true 表示已处理不进行默认处理, 返回 false 则表示未处理并执行默认处理, 如果不存在默认处理方式则跳出警告
152156
*/
153157
loaded?: (ctx: ModuleLoadedContext) => boolean | Promise<boolean>;
154158
/**
@@ -161,6 +165,15 @@ export interface ModuleHook {
161165
parser?: (ctx: ModuleHandlerContext) => any | Promise<any>;
162166
}
163167

168+
export interface TypeInfo {
169+
[key: string]: string | TypeInfo;
170+
}
171+
172+
export interface GenerateTypeExtendsConfig {
173+
importContent?: string | ((typeInfoMap: TypeInfo) => string | Promise<string>);
174+
typeContent?: string | ((typeInfoMap: TypeInfo) => string | Promise<string>);
175+
}
176+
164177
export interface GenerateTypeConfig {
165178
/**
166179
* 自定义需要返回值类型的模块
@@ -171,6 +184,8 @@ export interface GenerateTypeConfig {
171184
* @default false
172185
*/
173186
useAbsolutePath?: boolean;
187+
extendsInfo?: GenerateTypeExtendsConfig;
188+
getInterface?: (moduleType: string, typeInfoMap: TypeInfo) => void | string | boolean | Promise<string | void | boolean>;
174189
}
175190

176191
export interface ConfigFile {
@@ -208,7 +223,16 @@ export interface ConfigFile {
208223
generateTypeConfig?: GenerateTypeConfig;
209224
}
210225

226+
export interface RouterInfo {
227+
filePath: string;
228+
path: string | RegExp;
229+
schema?: any;
230+
schemaPath: string;
231+
prefix?: string;
232+
}
233+
211234
export interface Storage {
235+
routerInfoMap: Record<string, RouterInfo>;
212236
/**
213237
* 应用实例
214238
*/
@@ -267,3 +291,5 @@ export interface DevOptions {
267291
}
268292

269293
export type TeeOptions<T extends string> = TeeKoa.SetupOptionMap[T];
294+
295+
export type TeeMiddlewareCtx = Parameters<TeeKoa.Application['middleware'][number]>[0];

src/utils/config.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { FileInfo, TeeKoa } from '../types';
1+
import type { DeepRequired, FileInfo, TeeKoa } from '../types';
22
import process from 'node:process';
33
import { defu } from '.';
44
import { consola } from './consola';
@@ -14,12 +14,12 @@ export function getEnv(app: TeeKoa.Application) {
1414
return app.env || 'local';
1515
}
1616

17-
export function configMerge(app: TeeKoa.Application, configs: FileInfo[]) {
17+
export function configMerge(app: TeeKoa.Application, configs: DeepRequired<FileInfo>[]) {
1818
const {
1919
default: defaultConfig = { config: {}, relativePath: '' },
2020
...envConfigMap
2121
} = configs.reduce((result, item) => {
22-
const { nameSep, module, relativePath } = item;
22+
const { nameSep, moduleInfo: { content: module }, relativePath } = item;
2323
const name = nameSep.at(-1)!;
2424
try {
2525
if (name.includes('Default'))

src/utils/data-map.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import type KoaRouter from '@koa/router';
2+
import type { DeepRequired, FileInfo } from '../types';
3+
import { getStorage } from '../storage';
4+
5+
export function createRouterSchemaInfoMap(moduleInfo: DeepRequired<FileInfo>) {
6+
const { moduleInfo: { content: module }, path } = moduleInfo;
7+
8+
const routerInfoMap = getStorage('routerInfoMap', {});
9+
10+
for (const key in module) {
11+
const schema = module[key];
12+
routerInfoMap[key] = {
13+
...routerInfoMap[key],
14+
schema,
15+
schemaPath: path,
16+
};
17+
}
18+
}
19+
20+
export function createRouterInfoMap(moduleInfo: DeepRequired<FileInfo>) {
21+
const { moduleInfo: { content: module }, path } = moduleInfo;
22+
23+
const routerInfoMap = getStorage('routerInfoMap', {});
24+
25+
const router = module as KoaRouter;
26+
27+
router.stack.forEach((item) => {
28+
routerInfoMap[String(item.path)] = {
29+
...routerInfoMap[String(item.path)],
30+
filePath: path,
31+
path: item.path,
32+
};
33+
});
34+
}

src/utils/generate-type.ts

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import type { FileInfo, FileInfoMap, ModuleType } from '../types';
1+
import type { FileInfo, FileInfoMap, ModuleType, TypeInfo } from '../types';
2+
import { isNull } from '@cmtlyt/base';
23
import { readPackageJSON } from 'pkg-types';
34
import { pascalCase } from 'scule';
45
import { NEED_READ_PROTOTYPE_TYPES, NEED_RETURN_TYPES } from '../constant';
@@ -14,10 +15,6 @@ export function getItemType(item: Pick<FileInfo, 'type' | 'relativePath' | 'path
1415
return `typeof import('${path}')['default']${NEED_READ_PROTOTYPE_TYPES.includes(item.type) ? `['prototype']` : ''}`;
1516
}
1617

17-
interface TypeInfo {
18-
[key: string]: string | TypeInfo;
19-
}
20-
2118
function generateTypeInfo(fileInfoMap: FileInfoMap) {
2219
const { ignoreModules } = getStorage('config');
2320
const typeInfo: TypeInfo = {};
@@ -55,12 +52,63 @@ function generateType(typeInfoMap: TypeInfo, indent = 0) {
5552
return typeList.join('\n');
5653
}
5754

55+
// function getObjectFlatValues(typeInfoMap: TypeInfo, propName: string) {
56+
// const result = typeInfoMap[propName];
57+
// if (!result)
58+
// return [];
59+
// if (typeof result === 'string')
60+
// return [result];
61+
// const names: string[] = [];
62+
// for (const name in result) {
63+
// names.push(...getObjectFlatValues(result, name));
64+
// }
65+
// return names;
66+
// }
67+
68+
// function routerSchemaTypeMerge(typeInfoMap: TypeInfo) {
69+
// const allExtendsTypes = getObjectFlatValues(typeInfoMap, 'routerSchema');
70+
71+
// if (!allExtendsTypes.length)
72+
// return '';
73+
74+
// delete typeInfoMap.routerSchema;
75+
76+
// return `interface IRouterSchema extends ${allExtendsTypes.join(', ')}, Record<string, any> {}`;
77+
// }
78+
5879
export async function generateTypeString(fileInfo: FileInfoMap) {
5980
const { name } = await readPackageJSON(import.meta.url);
81+
const { generateTypeConfig: { extendsInfo, getInterface } } = getStorage('config');
82+
const originTypeInfoMap = generateTypeInfo(fileInfo);
83+
const typeInfoMap = { ...originTypeInfoMap };
84+
85+
const userTypeContent = [];
6086

61-
const typeInfoMap = generateTypeInfo(fileInfo);
87+
for (const type in typeInfoMap) {
88+
const _interface = await getInterface(type, typeInfoMap[type] as TypeInfo);
89+
if (!_interface)
90+
continue;
91+
delete typeInfoMap[type];
92+
userTypeContent.push(_interface);
93+
}
94+
95+
const routerSchemaTypeContent = ''; // routerSchemaTypeMerge(typeInfoMap);
6296

6397
const typeContent = generateType(typeInfoMap);
6498

65-
return `import { MergeConfig } from '@cmtlyt/tee';\nexport {};\ndeclare module '${name}' {\n${typeContent}\n #{configType}\n}`;
99+
let computedType = `import { MergeConfig } from '${name}';\n#{extendsImport}\nexport {};\ndeclare module '${name}' {\n${typeContent}\n ${userTypeContent.join('\n')}\n ${routerSchemaTypeContent}\n #{configType}\n #{extendsType}\n}`;
100+
101+
if (extendsInfo) {
102+
const { importContent, typeContent } = extendsInfo;
103+
if (!isNull(importContent)) {
104+
const content = typeof importContent === 'string' ? importContent : await importContent(typeInfoMap);
105+
computedType = computedType.replace('#{extendsImport}', content);
106+
}
107+
if (!isNull(typeContent)) {
108+
const content = typeof typeContent === 'string' ? typeContent : await typeContent(typeInfoMap);
109+
computedType = computedType.replace('#{extendsType}', content);
110+
}
111+
}
112+
113+
return computedType;
66114
}

src/utils/get-info.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,19 @@ export async function getFileInfoMap({ sourceDir = 'src' }) {
2020

2121
const fileInfoMap = files.reduce((fileInfo, path) => {
2222
const relativePath = path.slice(srcPath.length).replace(/^[\\/]/, '');
23-
const [type, ...names] = relativePath.replace(/\.[^.]*$/, '').split(/[\\/]/);
24-
if (!names?.length)
23+
const [type, ...nameSep] = relativePath
24+
.replace(/\.[^.]*$/, '')
25+
.replace(/\./g, '-')
26+
.split(/[\\/]/)
27+
.map(item => camelCase(item));
28+
if (!nameSep?.length)
2529
return fileInfo;
2630
(fileInfo[type as ModuleType] ||= []).push({
2731
type: type as ModuleType,
2832
path,
2933
relativePath,
30-
name: camelCase(names.join('-').replace(/\./g, '-')),
31-
nameSep: names.map(name => camelCase(name)),
34+
name: camelCase(nameSep.join('-')),
35+
nameSep,
3236
});
3337
return fileInfo;
3438
}, {} as FileInfoMap);

0 commit comments

Comments
 (0)