@ynight/cli 0.0.0-stage → 0.0.1
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/LICENSE +21 -0
- package/README.md +251 -2
- package/config/client.json +14 -0
- package/config/server.json +16 -0
- package/dist/bin.d.ts +26 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +114 -0
- package/dist/bin.js.map +1 -0
- package/dist/commands.d.ts +38 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +225 -0
- package/dist/commands.js.map +1 -0
- package/dist/dev-entry.d.ts +2 -0
- package/dist/dev-entry.d.ts.map +1 -0
- package/dist/dev-entry.js +348 -0
- package/dist/dev-entry.js.map +1 -0
- package/dist/dev-proxy.d.ts +21 -0
- package/dist/dev-proxy.d.ts.map +1 -0
- package/dist/dev-proxy.js +98 -0
- package/dist/dev-proxy.js.map +1 -0
- package/dist/dev-watcher.d.ts +24 -0
- package/dist/dev-watcher.d.ts.map +1 -0
- package/dist/dev-watcher.js +242 -0
- package/dist/dev-watcher.js.map +1 -0
- package/dist/generate-types.d.ts +14 -0
- package/dist/generate-types.d.ts.map +1 -0
- package/dist/generate-types.js +190 -0
- package/dist/generate-types.js.map +1 -0
- package/dist/output-safety.d.ts +47 -0
- package/dist/output-safety.d.ts.map +1 -0
- package/dist/output-safety.js +145 -0
- package/dist/output-safety.js.map +1 -0
- package/dist/project-config.d.ts +72 -0
- package/dist/project-config.d.ts.map +1 -0
- package/dist/project-config.js +221 -0
- package/dist/project-config.js.map +1 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +84 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +176 -0
- package/dist/utils.js.map +1 -0
- package/dist/webpack-build.d.ts +87 -0
- package/dist/webpack-build.d.ts.map +1 -0
- package/dist/webpack-build.js +475 -0
- package/dist/webpack-build.js.map +1 -0
- package/package.json +64 -3
- package/tsconfig/client.json +3 -0
- package/tsconfig/server.json +3 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.installDevProxy = installDevProxy;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const node_http_1 = tslib_1.__importDefault(require("node:http"));
|
|
6
|
+
/**
|
|
7
|
+
* 在开发模式下,仅把前端 HMR 与开发产物相关的请求代理到 Webpack Dev Server,
|
|
8
|
+
* 其余请求(业务 API、页面 HTML、静态资源中需鉴权的部分)继续交给 Koa 框架处理。
|
|
9
|
+
*
|
|
10
|
+
* 路由策略(仅放行下列请求方法与路径前缀):
|
|
11
|
+
* - 仅处理 `GET` / `HEAD`;
|
|
12
|
+
* - `/__webpack_hmr` webpack-hot-middleware 长连接(SSE);
|
|
13
|
+
* - `/dist/dev/...` 开发模式下的 js/css/asset 产物;
|
|
14
|
+
* - `/assets/...` 静态资源(虽然通常会经过框架校验,但开发期以原始
|
|
15
|
+
* 文件形式由 webpack-dev-middleware 接管更高效)。
|
|
16
|
+
*
|
|
17
|
+
* 设计动机:保持单一域名,便于在登录态 Cookie / CSRF 等安全约束下做 HMR;
|
|
18
|
+
* 仅放行最关键的几个前缀,避免暴露完整 webpack-dev-server。
|
|
19
|
+
*
|
|
20
|
+
* @param managed 当前被管理的 Koa 应用(带 `app.middleware`)。
|
|
21
|
+
* @param port Webpack Dev Server 监听端口(来自 `config.dev.webPort`)。
|
|
22
|
+
* @returns 卸载代理中间件的清理函数;通常在切换前后端实例时调用。
|
|
23
|
+
*/
|
|
24
|
+
function installDevProxy(managed, port) {
|
|
25
|
+
// 待关闭请求表:用于在卸载代理时立刻终止长连接 / 未完成的上行请求。
|
|
26
|
+
const pending = new Map();
|
|
27
|
+
const proxyMiddleware = async (ctx, next) => {
|
|
28
|
+
// 路径/方法白名单:只有命中规则的请求才转发到 webpack-dev-server。
|
|
29
|
+
if (!['GET', 'HEAD'].includes(ctx.method) ||
|
|
30
|
+
!(ctx.path === '/__webpack_hmr' ||
|
|
31
|
+
ctx.path.startsWith('/dist/dev/') ||
|
|
32
|
+
ctx.path.startsWith('/assets/'))) {
|
|
33
|
+
await next();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
// 接管响应:ctx.respond = false 后由我们直接写回 res。
|
|
37
|
+
ctx.respond = false;
|
|
38
|
+
await new Promise(resolve => {
|
|
39
|
+
// settled 用于幂等收尾:上游结束 / 异常 / 客户端断开 三个事件都可能先发生。
|
|
40
|
+
let settled = false;
|
|
41
|
+
const upstream = node_http_1.default.request(
|
|
42
|
+
// 始终指向本机回环,避免外网访问开发服务;端口来自 dev.webPort。
|
|
43
|
+
{ host: '127.0.0.1', port, path: ctx.url, method: ctx.method }, response => {
|
|
44
|
+
// 直接转发上游响应头和响应体。
|
|
45
|
+
ctx.res.writeHead(response.statusCode ?? 502, response.headers);
|
|
46
|
+
response.pipe(ctx.res);
|
|
47
|
+
response.once('error', fail);
|
|
48
|
+
response.once('end', finish);
|
|
49
|
+
});
|
|
50
|
+
// finish:幂等清理,避免重复 resolve / destroy。
|
|
51
|
+
const finish = () => {
|
|
52
|
+
if (settled) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
settled = true;
|
|
56
|
+
upstream.destroy();
|
|
57
|
+
pending.delete(upstream);
|
|
58
|
+
ctx.res.removeListener('close', finish);
|
|
59
|
+
resolve();
|
|
60
|
+
};
|
|
61
|
+
// fail:异常路径,写 502 与友好提示后退出 Promise。
|
|
62
|
+
const fail = () => {
|
|
63
|
+
if (settled) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
// 头未发出时主动写 502,否则依赖下游处理。
|
|
67
|
+
if (!ctx.res.headersSent) {
|
|
68
|
+
ctx.res.writeHead(502, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
69
|
+
}
|
|
70
|
+
if (!ctx.res.writableEnded) {
|
|
71
|
+
ctx.res.end('前端开发服务暂时不可用');
|
|
72
|
+
}
|
|
73
|
+
finish();
|
|
74
|
+
};
|
|
75
|
+
pending.set(upstream, finish);
|
|
76
|
+
// 客户端提前断开时同样走 finish,释放上游 socket。
|
|
77
|
+
ctx.res.once('close', finish);
|
|
78
|
+
upstream.once('error', fail);
|
|
79
|
+
upstream.end();
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
// unshift:保证代理中间件最先匹配,避免被框架业务中间件抢先处理。
|
|
83
|
+
managed.app.middleware.unshift(proxyMiddleware);
|
|
84
|
+
return () => {
|
|
85
|
+
// 卸载代理中间件:仅移除本次安装的实例,避免误删其他中间件。
|
|
86
|
+
const middlewareIndex = managed.app.middleware.indexOf(proxyMiddleware);
|
|
87
|
+
if (middlewareIndex !== -1) {
|
|
88
|
+
managed.app.middleware.splice(middlewareIndex, 1);
|
|
89
|
+
}
|
|
90
|
+
// 主动中断所有进行中的上行请求,防止重新加载阶段出现悬挂连接。
|
|
91
|
+
for (const [request, finish] of pending) {
|
|
92
|
+
request.destroy();
|
|
93
|
+
finish();
|
|
94
|
+
}
|
|
95
|
+
pending.clear();
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=dev-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-proxy.js","sourceRoot":"","sources":["../src/dev-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ElpisConfig } from '@ynight/framework/server';
|
|
2
|
+
export interface ProjectWatchEvent {
|
|
3
|
+
event: 'add' | 'change' | 'unlink';
|
|
4
|
+
path: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ProjectWatcher {
|
|
7
|
+
/**
|
|
8
|
+
* 配置文件改变后刷新监听范围。监听器本身保持事件驱动,不重新扫描整个项目。
|
|
9
|
+
*/
|
|
10
|
+
refresh(config: ElpisConfig): Promise<void>;
|
|
11
|
+
/** 关闭底层文件监听器并释放文件描述符。 */
|
|
12
|
+
close(): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* 创建项目级事件监听器。
|
|
16
|
+
*
|
|
17
|
+
* 监听策略:
|
|
18
|
+
* - 通过操作系统文件事件监听变化,不以固定时间间隔扫描目录;
|
|
19
|
+
* - 只关注业务源目录和影响服务加载的关键文件;
|
|
20
|
+
* - 配置变化后重建监听器,使动态 businessDir / model.dir 立即生效;
|
|
21
|
+
* - 不监听 `.elpis`、`dist`、`node_modules` 等生成目录,避免自触发循环。
|
|
22
|
+
*/
|
|
23
|
+
export declare function watchProject(root: string, config: ElpisConfig, onChange: (event: ProjectWatchEvent) => void, onError: (error: unknown) => void): Promise<ProjectWatcher>;
|
|
24
|
+
//# sourceMappingURL=dev-watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-watcher.d.ts","sourceRoot":"","sources":["../src/dev-watcher.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,yBAAyB;IACzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AA2QD;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,EAC5C,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAChC,OAAO,CAAC,cAAc,CAAC,CA6BzB"}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.watchProject = watchProject;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
6
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
7
|
+
const chokidar_1 = tslib_1.__importDefault(require("chokidar"));
|
|
8
|
+
const SOURCE_FILE = /\.(?:ts|js|cjs)$/;
|
|
9
|
+
const CONFIG_FILES = ['elpis.config.ts', 'elpis.config.js', 'elpis.config.cjs'];
|
|
10
|
+
function resolveWatchRoots(root, config) {
|
|
11
|
+
return [
|
|
12
|
+
node_path_1.default.resolve(root, config.server?.businessDir ?? 'server'),
|
|
13
|
+
node_path_1.default.resolve(root, config.model?.dir ?? 'model'),
|
|
14
|
+
node_path_1.default.resolve(root, 'shared'),
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
function resolveWatchFiles(root, config) {
|
|
18
|
+
return [
|
|
19
|
+
...CONFIG_FILES.map(file => node_path_1.default.resolve(root, file)),
|
|
20
|
+
node_path_1.default.resolve(root, 'tsconfig.server.json'),
|
|
21
|
+
...(config.server?.entry ? [node_path_1.default.resolve(root, config.server.entry)] : []),
|
|
22
|
+
...(config.model?.controlContracts ? [node_path_1.default.resolve(root, config.model.controlContracts)] : []),
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
function resolveWatchTarget(candidate, root) {
|
|
26
|
+
let current = node_path_1.default.resolve(candidate);
|
|
27
|
+
// 配置路径可能是项目根外的绝对路径;不让向上回退越过真实项目根。
|
|
28
|
+
if (!isWithin(current, root)) {
|
|
29
|
+
return root;
|
|
30
|
+
}
|
|
31
|
+
while (current !== root && !node_fs_1.default.existsSync(current)) {
|
|
32
|
+
current = node_path_1.default.dirname(current);
|
|
33
|
+
}
|
|
34
|
+
return current;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 生成监听目标。已存在的业务目录单独递归监听;不存在的目录/文件只监听最近的
|
|
38
|
+
* 已存在父目录,并由 ignored 规则沿着配置路径放行,避免把整个临时目录递归打开。
|
|
39
|
+
*/
|
|
40
|
+
function resolveWatchPlan(root, config) {
|
|
41
|
+
const roots = resolveWatchRoots(root, config);
|
|
42
|
+
const files = resolveWatchFiles(root, config);
|
|
43
|
+
const targets = new Set();
|
|
44
|
+
const shallowTargets = new Set();
|
|
45
|
+
for (const directory of roots) {
|
|
46
|
+
if (node_fs_1.default.existsSync(directory) && node_fs_1.default.statSync(directory).isDirectory()) {
|
|
47
|
+
targets.add(directory);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
const parent = resolveWatchTarget(directory, root);
|
|
51
|
+
targets.add(parent);
|
|
52
|
+
shallowTargets.add(parent);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
for (const file of files) {
|
|
56
|
+
// 配置文件采用 first-existing 语义:已有一种扩展名时,不为其它候选文件
|
|
57
|
+
// 把项目根目录提升为递归监听目标。
|
|
58
|
+
if (CONFIG_FILES.includes(node_path_1.default.basename(file)) &&
|
|
59
|
+
!node_fs_1.default.existsSync(file) &&
|
|
60
|
+
CONFIG_FILES.some(candidate => node_fs_1.default.existsSync(node_path_1.default.resolve(root, candidate)))) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (node_fs_1.default.existsSync(file)) {
|
|
64
|
+
targets.add(file);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
const parent = resolveWatchTarget(file, root);
|
|
68
|
+
targets.add(parent);
|
|
69
|
+
shallowTargets.add(parent);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// 已有递归目录覆盖了某个浅层父目录时,不需要重复声明浅层规则。
|
|
73
|
+
for (const parent of shallowTargets) {
|
|
74
|
+
if ([...targets].some(target => target !== parent && isWithin(parent, target))) {
|
|
75
|
+
shallowTargets.delete(parent);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return { targets: [...targets], shallowTargets: [...shallowTargets] };
|
|
79
|
+
}
|
|
80
|
+
function isWithin(candidate, parent) {
|
|
81
|
+
return candidate === parent || candidate.startsWith(parent + node_path_1.default.sep);
|
|
82
|
+
}
|
|
83
|
+
function mapConfigPath(value, logicalRoot, physicalRoot) {
|
|
84
|
+
if (!node_path_1.default.isAbsolute(value)) {
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
const resolved = node_path_1.default.resolve(value);
|
|
88
|
+
return isWithin(resolved, logicalRoot)
|
|
89
|
+
? node_path_1.default.resolve(physicalRoot, node_path_1.default.relative(logicalRoot, resolved))
|
|
90
|
+
: value;
|
|
91
|
+
}
|
|
92
|
+
function mapConfigToPhysicalRoot(config, logicalRoot, physicalRoot) {
|
|
93
|
+
const mapped = { ...config };
|
|
94
|
+
if (config.server) {
|
|
95
|
+
mapped.server = { ...config.server };
|
|
96
|
+
if (config.server.businessDir !== undefined) {
|
|
97
|
+
mapped.server.businessDir = mapConfigPath(config.server.businessDir, logicalRoot, physicalRoot);
|
|
98
|
+
}
|
|
99
|
+
if (config.server.entry !== undefined) {
|
|
100
|
+
mapped.server.entry = mapConfigPath(config.server.entry, logicalRoot, physicalRoot);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (config.model) {
|
|
104
|
+
mapped.model = { ...config.model };
|
|
105
|
+
if (config.model.dir !== undefined) {
|
|
106
|
+
mapped.model.dir = mapConfigPath(config.model.dir, logicalRoot, physicalRoot);
|
|
107
|
+
}
|
|
108
|
+
if (config.model.controlContracts !== undefined) {
|
|
109
|
+
mapped.model.controlContracts = mapConfigPath(config.model.controlContracts, logicalRoot, physicalRoot);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return mapped;
|
|
113
|
+
}
|
|
114
|
+
function mapWatchEventPath(eventPath, logicalRoot, physicalRoot) {
|
|
115
|
+
const resolved = node_path_1.default.resolve(eventPath);
|
|
116
|
+
return isWithin(resolved, physicalRoot)
|
|
117
|
+
? node_path_1.default.resolve(logicalRoot, node_path_1.default.relative(physicalRoot, resolved))
|
|
118
|
+
: resolved;
|
|
119
|
+
}
|
|
120
|
+
function isDirectoryCandidate(root, config, candidate, stats) {
|
|
121
|
+
if (stats) {
|
|
122
|
+
return stats.isDirectory();
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
return node_fs_1.default.statSync(candidate).isDirectory();
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
const normalized = node_path_1.default.resolve(candidate);
|
|
129
|
+
// chokidar 可能在新目录完成 stat 前调用 ignored;此时用配置路径判断,
|
|
130
|
+
// 避免带点号的目录(如 business.v1)或其新建子目录被当成文件提前过滤。
|
|
131
|
+
return resolveWatchRoots(root, config).some(watchRoot => normalized === watchRoot ||
|
|
132
|
+
isWithin(watchRoot, normalized) ||
|
|
133
|
+
isWithin(normalized, watchRoot));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function ignoredPath(root, config, candidate, isDirectory, shallowTargets = []) {
|
|
137
|
+
const normalized = node_path_1.default.resolve(candidate);
|
|
138
|
+
const ignoredDirectoryNames = new Set(['.git', '.elpis', 'node_modules', 'dist', 'logs']);
|
|
139
|
+
const relative = node_path_1.default.relative(root, normalized);
|
|
140
|
+
if (relative && relative.split(node_path_1.default.sep).some(part => ignoredDirectoryNames.has(part))) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
const roots = resolveWatchRoots(root, config);
|
|
144
|
+
const files = resolveWatchFiles(root, config);
|
|
145
|
+
if (isDirectory) {
|
|
146
|
+
// 浅层父目录只为发现缺失的配置目录服务。沿配置路径继续放行,
|
|
147
|
+
// 其余目录在这里截断,避免临时目录中的大量无关子目录触发 EMFILE。
|
|
148
|
+
if (shallowTargets.some(shallow => normalized !== shallow && isWithin(shallow, normalized))) {
|
|
149
|
+
const existingRoots = roots.filter(directory => {
|
|
150
|
+
try {
|
|
151
|
+
return node_fs_1.default.statSync(directory).isDirectory();
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
if (existingRoots.some(directory => normalized !== directory && isWithin(normalized, directory))) {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
if (!roots.some(watchRoot => isWithin(normalized, watchRoot) || isWithin(watchRoot, normalized)) &&
|
|
161
|
+
!files.some(file => isWithin(normalized, file))) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// 保留项目根到业务目录之间的路径,以便 chokidar 能继续向下监听。
|
|
166
|
+
return (!roots.some(watchRoot => isWithin(normalized, watchRoot) || isWithin(watchRoot, normalized)) && normalized !== root);
|
|
167
|
+
}
|
|
168
|
+
return !(files.includes(normalized) ||
|
|
169
|
+
(SOURCE_FILE.test(normalized) && roots.some(watchRoot => isWithin(normalized, watchRoot))));
|
|
170
|
+
}
|
|
171
|
+
async function openWatcher(root, config, onChange, onError) {
|
|
172
|
+
const plan = resolveWatchPlan(root, config);
|
|
173
|
+
const { targets, shallowTargets } = plan;
|
|
174
|
+
const watcher = chokidar_1.default.watch(targets, {
|
|
175
|
+
// 初始生成由 dev-entry 负责,避免启动时把所有已有文件当作变更事件。
|
|
176
|
+
ignoreInitial: true,
|
|
177
|
+
followSymlinks: false,
|
|
178
|
+
persistent: true,
|
|
179
|
+
// 不启用 awaitWriteFinish:它内部会轮询文件大小,防抖由上层统一处理。
|
|
180
|
+
ignored: (candidate, stats) => ignoredPath(root, config, candidate, isDirectoryCandidate(root, config, candidate, stats), shallowTargets),
|
|
181
|
+
});
|
|
182
|
+
watcher.on('add', filePath => onChange({ event: 'add', path: node_path_1.default.resolve(filePath) }));
|
|
183
|
+
watcher.on('change', filePath => onChange({ event: 'change', path: node_path_1.default.resolve(filePath) }));
|
|
184
|
+
watcher.on('unlink', filePath => onChange({ event: 'unlink', path: node_path_1.default.resolve(filePath) }));
|
|
185
|
+
watcher.on('error', onError);
|
|
186
|
+
await new Promise((resolve, reject) => {
|
|
187
|
+
const ready = () => {
|
|
188
|
+
cleanup();
|
|
189
|
+
resolve();
|
|
190
|
+
};
|
|
191
|
+
const fail = (error) => {
|
|
192
|
+
cleanup();
|
|
193
|
+
void watcher.close().finally(() => reject(error));
|
|
194
|
+
};
|
|
195
|
+
const cleanup = () => {
|
|
196
|
+
watcher.removeListener('ready', ready);
|
|
197
|
+
watcher.removeListener('error', fail);
|
|
198
|
+
};
|
|
199
|
+
watcher.once('ready', ready);
|
|
200
|
+
watcher.once('error', fail);
|
|
201
|
+
});
|
|
202
|
+
return watcher;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 创建项目级事件监听器。
|
|
206
|
+
*
|
|
207
|
+
* 监听策略:
|
|
208
|
+
* - 通过操作系统文件事件监听变化,不以固定时间间隔扫描目录;
|
|
209
|
+
* - 只关注业务源目录和影响服务加载的关键文件;
|
|
210
|
+
* - 配置变化后重建监听器,使动态 businessDir / model.dir 立即生效;
|
|
211
|
+
* - 不监听 `.elpis`、`dist`、`node_modules` 等生成目录,避免自触发循环。
|
|
212
|
+
*/
|
|
213
|
+
async function watchProject(root, config, onChange, onError) {
|
|
214
|
+
const logicalRoot = node_path_1.default.resolve(root);
|
|
215
|
+
const physicalRoot = node_fs_1.default.realpathSync(logicalRoot);
|
|
216
|
+
const physicalConfig = mapConfigToPhysicalRoot(config, logicalRoot, physicalRoot);
|
|
217
|
+
const emitChange = (event) => onChange({
|
|
218
|
+
...event,
|
|
219
|
+
path: mapWatchEventPath(event.path, logicalRoot, physicalRoot),
|
|
220
|
+
});
|
|
221
|
+
let watcher = await openWatcher(physicalRoot, physicalConfig, emitChange, onError);
|
|
222
|
+
let closed = false;
|
|
223
|
+
return {
|
|
224
|
+
async refresh(nextConfig) {
|
|
225
|
+
if (closed) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const previous = watcher;
|
|
229
|
+
const nextPhysicalConfig = mapConfigToPhysicalRoot(nextConfig, logicalRoot, physicalRoot);
|
|
230
|
+
watcher = await openWatcher(physicalRoot, nextPhysicalConfig, emitChange, onError);
|
|
231
|
+
await previous.close();
|
|
232
|
+
},
|
|
233
|
+
async close() {
|
|
234
|
+
if (closed) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
closed = true;
|
|
238
|
+
await watcher.close();
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=dev-watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-watcher.js","sourceRoot":"","sources":["../src/dev-watcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ElpisMode } from '@ynight/framework/server';
|
|
2
|
+
/**
|
|
3
|
+
* 生成业务模块的类型声明文件 `.elpis/types/application.d.ts`。
|
|
4
|
+
*
|
|
5
|
+
* 通过给 `@ynight/framework/server` 模块声明合并接口,业务侧即可在
|
|
6
|
+
* `app.service('user').foo()` 等链式调用上拿到具体类型提示。
|
|
7
|
+
*
|
|
8
|
+
* @param root 业务工程根目录。
|
|
9
|
+
* @param check 是否只校验不写文件;为 `true` 时若已过期会抛出错误,便于 CI 阻断。
|
|
10
|
+
* @param mode 运行模式(development / production),影响配置文件加载。
|
|
11
|
+
* @returns 文件是否发生变化;`check` 模式下为 `false`。
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateTypes(root: string, check?: boolean, mode?: ElpisMode): boolean;
|
|
14
|
+
//# sourceMappingURL=generate-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-types.d.ts","sourceRoot":"","sources":["../src/generate-types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAgL1D;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,KAAK,UAAQ,EACb,IAAI,GAAE,SAAyB,GAC9B,OAAO,CA6CT"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateTypes = generateTypes;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
6
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
7
|
+
const project_config_1 = require("./project-config");
|
|
8
|
+
const utils_1 = require("./utils");
|
|
9
|
+
const output_safety_1 = require("./output-safety");
|
|
10
|
+
/**
|
|
11
|
+
* 把业务文件路径转换为"模块路径段",最终用于声明对象的层级键名。
|
|
12
|
+
*
|
|
13
|
+
* 转换规则:
|
|
14
|
+
* 1. 取相对根目录的路径,去掉扩展名;
|
|
15
|
+
* 2. 按目录分段;
|
|
16
|
+
* 3. 每段 `camelCase` 后再做 `.` 拆分(允许文件名本身已含 `.` 形成多级键)。
|
|
17
|
+
*
|
|
18
|
+
* 例如 `server/service/user-profile.ts` → `['userProfile']`;
|
|
19
|
+
* `server/service/user.profile.ts` → `['user', 'profile']`。
|
|
20
|
+
*/
|
|
21
|
+
function moduleParts(filePath, root) {
|
|
22
|
+
return node_path_1.default
|
|
23
|
+
.relative(root, filePath)
|
|
24
|
+
.replace(/\.(?:ts|js|cjs)$/, '')
|
|
25
|
+
.split(node_path_1.default.sep)
|
|
26
|
+
.flatMap(part => (0, utils_1.camelCase)(part).split('.'));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 把单个业务文件插入到声明树中,必要时创建中间分支节点。
|
|
30
|
+
*
|
|
31
|
+
* 冲突检测:
|
|
32
|
+
* - 当前层级已存在同名 `leaf`,新文件路径又与之不同 → 命名冲突;
|
|
33
|
+
* - 当前层级已存在子节点,但同时又要插入 `leaf` → 命名冲突;
|
|
34
|
+
* - 任一冲突都会立即抛出,确保类型生成结果唯一可预测。
|
|
35
|
+
*/
|
|
36
|
+
function insertDeclaration(root, parts, filePath, folder, sourceRoot) {
|
|
37
|
+
let current = root;
|
|
38
|
+
parts.forEach((part, index) => {
|
|
39
|
+
const isLeaf = index === parts.length - 1;
|
|
40
|
+
let next = current.children.get(part);
|
|
41
|
+
if (!next) {
|
|
42
|
+
// 没有则创建一个空分支;后续可能是叶子,也可能是中间节点。
|
|
43
|
+
next = { children: new Map() };
|
|
44
|
+
current.children.set(part, next);
|
|
45
|
+
}
|
|
46
|
+
if (isLeaf) {
|
|
47
|
+
// 已经存在文件或子节点,意味着同名冲突。
|
|
48
|
+
if (next.leaf || next.children.size > 0) {
|
|
49
|
+
throw new Error(`业务模块命名冲突: ${folder}.${parts.join('.')}`);
|
|
50
|
+
}
|
|
51
|
+
next.leaf = {
|
|
52
|
+
filePath,
|
|
53
|
+
importName: moduleImportName(filePath, sourceRoot, folder),
|
|
54
|
+
};
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// 中间节点却挂着 leaf,意味着"目录"已经是一个文件了。
|
|
58
|
+
if (next.leaf) {
|
|
59
|
+
throw new Error(`业务模块命名冲突: ${folder}.${parts.slice(0, index + 1).join('.')}`);
|
|
60
|
+
}
|
|
61
|
+
current = next;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 把源文件绝对路径转换为生成代码里 `import type` 使用的相对模块路径。
|
|
66
|
+
*
|
|
67
|
+
* 路径基准为 `<root>/.elpis/types`,与生成产物在同目录下,便于 TS 解析。
|
|
68
|
+
* 跨平台兼容:把路径分隔符统一替换为 `/`。
|
|
69
|
+
*/
|
|
70
|
+
function importPath(sourceRoot, filePath) {
|
|
71
|
+
const relative = node_path_1.default
|
|
72
|
+
.relative(node_path_1.default.resolve(sourceRoot, '.elpis/types'), filePath)
|
|
73
|
+
.replace(/\.(?:ts|js|cjs)$/, '')
|
|
74
|
+
.split(node_path_1.default.sep)
|
|
75
|
+
.join('/');
|
|
76
|
+
// `path.relative` 在跨盘时不会加 `./`,需手动补全。
|
|
77
|
+
return relative.startsWith('.') ? relative : `./${relative}`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 把声明树渲染为接口体文本(递归)。
|
|
81
|
+
*
|
|
82
|
+
* 输出形如 `import type ServiceName from './path';` 与
|
|
83
|
+
* `serviceName: InstanceType<typeof ServiceName>;`,
|
|
84
|
+
* 这样消费方既能得到类型提示,也能避免循环依赖问题。
|
|
85
|
+
*
|
|
86
|
+
* 属性名非法时回退为 JSON 字符串,保持语法合法。
|
|
87
|
+
*/
|
|
88
|
+
function renderBranch(branch, sourceRoot, indent, imports) {
|
|
89
|
+
const lines = [];
|
|
90
|
+
for (const [name, node] of branch.children) {
|
|
91
|
+
// 属性名不合法(如数字开头)时用字符串字面量代替。
|
|
92
|
+
const property = /^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name);
|
|
93
|
+
if (node.leaf) {
|
|
94
|
+
imports.push(`import type ${node.leaf.importName} from ${JSON.stringify(importPath(sourceRoot, node.leaf.filePath))};`);
|
|
95
|
+
lines.push(`${indent}${property}: InstanceType<typeof ${node.leaf.importName}>;`);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
lines.push(`${indent}${property}: {`);
|
|
99
|
+
lines.push(...renderBranch(node, sourceRoot, `${indent} `, imports));
|
|
100
|
+
lines.push(`${indent}};`);
|
|
101
|
+
}
|
|
102
|
+
return lines;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 扫描指定业务目录(如 `server/service`)并生成对应声明体。
|
|
106
|
+
*
|
|
107
|
+
* 内部维护一棵声明树,确保不同业务模块不会因为路径命名重合而互相覆盖。
|
|
108
|
+
*
|
|
109
|
+
* @param sourceRoot 业务工程根目录。
|
|
110
|
+
* @param folder 相对于 sourceRoot 的目录名(如 `server/service`)。
|
|
111
|
+
*/
|
|
112
|
+
function moduleImportName(filePath, root, folder) {
|
|
113
|
+
const prefix = folder
|
|
114
|
+
.split(node_path_1.default.sep)
|
|
115
|
+
.map(utils_1.camelCase)
|
|
116
|
+
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
|
117
|
+
.join('');
|
|
118
|
+
const suffix = moduleParts(filePath, root)
|
|
119
|
+
.map(part => (part ? part.charAt(0).toUpperCase() + part.slice(1) : ''))
|
|
120
|
+
.join('');
|
|
121
|
+
return `${prefix}${suffix || 'Module'}`;
|
|
122
|
+
}
|
|
123
|
+
function declaration(sourceRoot, folder) {
|
|
124
|
+
const root = node_path_1.default.resolve(sourceRoot, folder);
|
|
125
|
+
const tree = { children: new Map() };
|
|
126
|
+
for (const filePath of (0, utils_1.findFiles)(root)) {
|
|
127
|
+
insertDeclaration(tree, moduleParts(filePath, root), filePath, folder, root);
|
|
128
|
+
}
|
|
129
|
+
// 缩进 4 空格与生成产物中的接口体对齐。
|
|
130
|
+
const imports = [];
|
|
131
|
+
return { imports, lines: renderBranch(tree, sourceRoot, ' ', imports) };
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 生成业务模块的类型声明文件 `.elpis/types/application.d.ts`。
|
|
135
|
+
*
|
|
136
|
+
* 通过给 `@ynight/framework/server` 模块声明合并接口,业务侧即可在
|
|
137
|
+
* `app.service('user').foo()` 等链式调用上拿到具体类型提示。
|
|
138
|
+
*
|
|
139
|
+
* @param root 业务工程根目录。
|
|
140
|
+
* @param check 是否只校验不写文件;为 `true` 时若已过期会抛出错误,便于 CI 阻断。
|
|
141
|
+
* @param mode 运行模式(development / production),影响配置文件加载。
|
|
142
|
+
* @returns 文件是否发生变化;`check` 模式下为 `false`。
|
|
143
|
+
*/
|
|
144
|
+
function generateTypes(root, check = false, mode = 'development') {
|
|
145
|
+
const config = (0, project_config_1.loadProjectConfig)(root, mode);
|
|
146
|
+
const businessDir = config.server?.businessDir ?? 'server';
|
|
147
|
+
const output = (0, output_safety_1.safeGeneratedPath)(root, '.elpis/types/application.d.ts');
|
|
148
|
+
const services = declaration(root, node_path_1.default.join(businessDir, 'service'));
|
|
149
|
+
const controllers = declaration(root, node_path_1.default.join(businessDir, 'controller'));
|
|
150
|
+
const middlewares = declaration(root, node_path_1.default.join(businessDir, 'middleware'));
|
|
151
|
+
const imports = [
|
|
152
|
+
...new Set([...services.imports, ...controllers.imports, ...middlewares.imports]),
|
|
153
|
+
].sort();
|
|
154
|
+
const lines = [
|
|
155
|
+
// 提示此文件是自动生成,避免业务同学手动修改后被覆盖产生困惑。
|
|
156
|
+
'// 此文件由 @ynight/cli 生成,请勿手工修改。',
|
|
157
|
+
...imports,
|
|
158
|
+
// 通过 declare module 给框架包内的接口合并业务实现,符合 TS 声明合并协议。
|
|
159
|
+
"declare module '@ynight/framework/server' {",
|
|
160
|
+
' interface BusinessServices {',
|
|
161
|
+
...services.lines,
|
|
162
|
+
' }',
|
|
163
|
+
' interface BusinessControllers {',
|
|
164
|
+
...controllers.lines,
|
|
165
|
+
' }',
|
|
166
|
+
' interface BusinessMiddlewares {',
|
|
167
|
+
...middlewares.lines,
|
|
168
|
+
' }',
|
|
169
|
+
'}',
|
|
170
|
+
// 标记为模块文件,避免脚本上下文被合并到全局。
|
|
171
|
+
'export {};',
|
|
172
|
+
'',
|
|
173
|
+
];
|
|
174
|
+
const content = lines.join('\n');
|
|
175
|
+
const current = node_fs_1.default.existsSync(output) ? node_fs_1.default.readFileSync(output, 'utf8') : undefined;
|
|
176
|
+
if (check) {
|
|
177
|
+
// check 模式下仅做差分比对,避免无谓的写入。
|
|
178
|
+
if (current !== content) {
|
|
179
|
+
throw new Error(`生成类型已过期,请执行: elpis generate:types\n文件: ${output}`);
|
|
180
|
+
}
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(output), { recursive: true });
|
|
184
|
+
// 内容未变化时不写盘,避免触发 IDE 重新加载与 git diff。
|
|
185
|
+
if (current !== content) {
|
|
186
|
+
node_fs_1.default.writeFileSync(output, content);
|
|
187
|
+
}
|
|
188
|
+
return current !== content;
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=generate-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-types.js","sourceRoot":"","sources":["../src/generate-types.ts"],"names":[],"mappings":"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"}
|