@ghini/xstart 26.1.5211744 → 26.1.6175449
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/README.md +53 -31
- package/dist/index.d.ts +1 -1
- package/dist/index.js +32 -4
- package/dist/index.js.map +3 -3
- package/dist/utils.d.ts +16 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +10 -3
- package/src/index.ts +1 -1
- package/src/utils.ts +56 -0
- package/dist/start.d.ts +0 -3
- package/dist/start.d.ts.map +0 -1
- package/src/start.ts +0 -6
package/README.md
CHANGED
|
@@ -1,47 +1,69 @@
|
|
|
1
|
-
#
|
|
1
|
+
# TypeScript 2026 npm 库脚手架
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
基于 Node 24 原生 ESM,利用"源码直连"实现免 build 实时调试;通过 esbuild 抹除后缀并配合 publishConfig,兼顾开发爽感与发布标准。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 📦 创建新库
|
|
6
|
+
|
|
7
|
+
**PowerShell (Windows)**
|
|
8
|
+
|
|
9
|
+
```powershell
|
|
10
|
+
$lib = "YOUR_LIB_NAME"
|
|
11
|
+
git clone -b xstart git@github.com:xghini/mynpm.git $lib && cd $lib
|
|
12
|
+
(Get-Content package.json) -replace 'xstart', $lib | Set-Content package.json
|
|
13
|
+
(Get-Content README.md) -replace 'xstart', $lib | Set-Content README.md
|
|
14
|
+
Remove-Item -Recurse -Force .git
|
|
15
|
+
git init && git add . && git commit -m "init: $lib from xstart template"
|
|
16
|
+
git branch -M $lib && git remote add origin git@github.com:xghini/mynpm.git
|
|
17
|
+
git push -u origin $lib && pnpm i && pnpm pub
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Bash (Linux/macOS)**
|
|
6
21
|
|
|
7
22
|
```bash
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
23
|
+
lib="YOUR_LIB_NAME"
|
|
24
|
+
git clone -b xstart git@github.com:xghini/mynpm.git $lib && cd $lib
|
|
25
|
+
sed -i "s/xstart/$lib/g" package.json README.md
|
|
26
|
+
rm -rf .git
|
|
27
|
+
git init && git add . && git commit -m "init: $lib from xstart template"
|
|
28
|
+
git branch -M $lib && git remote add origin git@github.com:xghini/mynpm.git
|
|
29
|
+
git push -u origin $lib && pnpm i && pnpm pub
|
|
11
30
|
```
|
|
12
31
|
|
|
13
|
-
##
|
|
32
|
+
## 🚀 开发命令
|
|
14
33
|
|
|
15
|
-
```
|
|
16
|
-
pnpm
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
pnpm
|
|
34
|
+
```bash
|
|
35
|
+
pnpm test # 运行测试
|
|
36
|
+
pnpm test:watch # 监听模式
|
|
37
|
+
pnpm test:coverage # 覆盖率报告
|
|
38
|
+
pnpm typecheck # 类型检查
|
|
39
|
+
pnpm build # 编译 + 打包 + 更新版本号
|
|
40
|
+
pnpm pub # 构建 + 发布 + 提交
|
|
20
41
|
```
|
|
21
42
|
|
|
22
|
-
##
|
|
43
|
+
## 🛠️ 内置工具
|
|
23
44
|
|
|
24
|
-
|
|
45
|
+
```typescript
|
|
46
|
+
import {xpath, exefile, exedir} from '@ghini/xstart';
|
|
25
47
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
git init
|
|
32
|
-
git add .
|
|
33
|
-
git commit -m "Initial commit"
|
|
34
|
-
git branch -M xstart
|
|
35
|
-
git remote add origin git@github.com:xghini/mynpm.git
|
|
36
|
-
git push -u origin xstart
|
|
37
|
-
pnpm pub
|
|
48
|
+
xpath('./config.json'); // 相对于入口脚本解析路径
|
|
49
|
+
xpath('../data/file.txt'); // 自动处理 ../
|
|
50
|
+
xpath(); // 获取入口脚本目录
|
|
51
|
+
xpath('C:/abs/path'); // 绝对路径直接返回
|
|
52
|
+
xpath('file:///C:/path/file.ts'); // 自动剥离 file:/// 协议
|
|
38
53
|
```
|
|
39
54
|
|
|
40
|
-
💡
|
|
41
|
-
源码直连:package.json 中的 exports 在开发态指向 src/\*.ts,配合 Node.js 24 --experimental-strip-types 实现保存即生效,告别 tsc --watch。
|
|
55
|
+
## 💡 核心设计
|
|
42
56
|
|
|
43
|
-
|
|
57
|
+
- **源码直连**:开发态 exports 指向 `src/*.ts`,Node 24 原生支持直接运行 TypeScript
|
|
58
|
+
- **双模切换**:publishConfig 发布时自动切回 `dist/*.js`,确保兼容性
|
|
59
|
+
- **自动版本**:build.js 内置日期版本算法(如 26.1.5161805)
|
|
60
|
+
- **路径处理**:xpath 默认相对于入口脚本目录,支持 pm2 等场景通过 `KIT_EXEPATH` 环境变量覆盖
|
|
44
61
|
|
|
45
|
-
|
|
62
|
+
## 🔧 pnpm 迁移
|
|
46
63
|
|
|
47
|
-
|
|
64
|
+
```powershell
|
|
65
|
+
pnpm import
|
|
66
|
+
Remove-Item -Recurse -Force node_modules
|
|
67
|
+
Remove-Item package-lock.json
|
|
68
|
+
pnpm i
|
|
69
|
+
```
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './utils.ts';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,36 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
// src/utils.ts
|
|
2
|
+
import { normalize, join, isAbsolute, sep, dirname } from "node:path";
|
|
3
|
+
var exefile = process.env.KIT_EXEPATH || process.env.KIT_EXEFILE || process.argv[1] || "";
|
|
4
|
+
var exedir = dirname(exefile);
|
|
5
|
+
function xpath(targetPath = ".", basePath = exedir, separator = "/") {
|
|
6
|
+
const stripFileProtocol = (p) => {
|
|
7
|
+
if (p.startsWith("file:///")) {
|
|
8
|
+
return process.platform === "win32" ? p.slice(8) : p.slice(7);
|
|
9
|
+
}
|
|
10
|
+
return p;
|
|
11
|
+
};
|
|
12
|
+
let resolvedBase = stripFileProtocol(basePath);
|
|
13
|
+
if (!isAbsolute(resolvedBase)) {
|
|
14
|
+
resolvedBase = join(process.cwd(), resolvedBase);
|
|
15
|
+
}
|
|
16
|
+
let result;
|
|
17
|
+
const cleanTarget = stripFileProtocol(targetPath);
|
|
18
|
+
if (isAbsolute(cleanTarget)) {
|
|
19
|
+
result = normalize(cleanTarget);
|
|
20
|
+
} else {
|
|
21
|
+
result = normalize(join(resolvedBase, cleanTarget));
|
|
22
|
+
}
|
|
23
|
+
if (separator === "/" && sep === "\\") {
|
|
24
|
+
return result.split(sep).join("/");
|
|
25
|
+
}
|
|
26
|
+
if (separator === "\\" && sep === "/") {
|
|
27
|
+
return result.split(sep).join("\\");
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
4
30
|
}
|
|
5
31
|
export {
|
|
6
|
-
|
|
32
|
+
exedir,
|
|
33
|
+
exefile,
|
|
34
|
+
xpath
|
|
7
35
|
};
|
|
8
36
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/
|
|
4
|
-
"sourcesContent": ["//
|
|
5
|
-
"mappings": ";
|
|
3
|
+
"sources": ["../src/utils.ts"],
|
|
4
|
+
"sourcesContent": ["// src/utils.ts\nimport {normalize, join, isAbsolute, sep, dirname} from 'node:path';\n\nexport {xpath, exefile, exedir};\n\n/** \u6267\u884C\u6587\u4EF6\u8DEF\u5F84\uFF0C\u652F\u6301 pm2 \u7B49\u5DE5\u5177\u901A\u8FC7\u73AF\u5883\u53D8\u91CF\u8986\u76D6 */\nconst exefile = process.env.KIT_EXEPATH || process.env.KIT_EXEFILE || process.argv[1] || '';\n\n/** \u6267\u884C\u6587\u4EF6\u6240\u5728\u76EE\u5F55 */\nconst exedir = dirname(exefile);\n\n/**\n * \u5F3A\u5927\u53EF\u9760\u7684\u8DEF\u5F84\u5904\u7406\n * - \u76F8\u5BF9\u8DEF\u5F84\u5728\u540E\uFF0C\u7EDD\u5BF9\u8DEF\u5F84\u5728\u524D\uFF0C\u6700\u7EC8\u90FD\u8F6C\u6362\u4E3A\u7EDD\u5BF9\u8DEF\u5F84\n * - \u7EDF\u4E00\u5206\u9694\u7B26\uFF0C\u65B9\u4FBF\u6BD4\u8F83\u8DEF\u5F84\n * - \u81EA\u52A8\u5904\u7406 file:/// \u534F\u8BAE\u3001../\u88C1\u5207\u7B49\n * @param targetPath - \u76EE\u6807\u8DEF\u5F84\uFF08\u53EF\u4EE5\u662F\u76F8\u5BF9\u8DEF\u5F84\u6216\u7EDD\u5BF9\u8DEF\u5F84\uFF09\n * @param basePath - \u57FA\u51C6\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A process.cwd()\n * @param separator - \u8DEF\u5F84\u5206\u9694\u7B26\uFF0C\u9ED8\u8BA4\u4E3A '/'\n */\nfunction xpath(targetPath: string = '.', basePath: string = exedir, separator: '/' | '\\\\' = '/'): string {\n // \u5904\u7406 file:/// \u534F\u8BAE\n const stripFileProtocol = (p: string): string => {\n if (p.startsWith('file:///')) {\n // Windows: file:///C:/path \u2192 C:/path (\u53BB\u63898\u4E2A\u5B57\u7B26)\n // Unix: file:///path \u2192 /path (\u53BB\u63897\u4E2A\u5B57\u7B26)\n return process.platform === 'win32' ? p.slice(8) : p.slice(7);\n }\n return p;\n };\n\n // \u5904\u7406 basePath\n let resolvedBase = stripFileProtocol(basePath);\n if (!isAbsolute(resolvedBase)) {\n resolvedBase = join(process.cwd(), resolvedBase);\n }\n\n // \u5904\u7406 targetPath\n let result: string;\n const cleanTarget = stripFileProtocol(targetPath);\n\n if (isAbsolute(cleanTarget)) {\n result = normalize(cleanTarget);\n } else {\n result = normalize(join(resolvedBase, cleanTarget));\n }\n\n // \u7EDF\u4E00\u5206\u9694\u7B26\n if (separator === '/' && sep === '\\\\') {\n return result.split(sep).join('/');\n }\n if (separator === '\\\\' && sep === '/') {\n return result.split(sep).join('\\\\');\n }\n return result;\n}\n"],
|
|
5
|
+
"mappings": ";AACA,SAAQ,WAAW,MAAM,YAAY,KAAK,eAAc;AAKxD,IAAM,UAAU,QAAQ,IAAI,eAAe,QAAQ,IAAI,eAAe,QAAQ,KAAK,CAAC,KAAK;AAGzF,IAAM,SAAS,QAAQ,OAAO;AAW9B,SAAS,MAAM,aAAqB,KAAK,WAAmB,QAAQ,YAAwB,KAAa;AAEvG,QAAM,oBAAoB,CAAC,MAAsB;AAC/C,QAAI,EAAE,WAAW,UAAU,GAAG;AAG5B,aAAO,QAAQ,aAAa,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC;AAAA,IAC9D;AACA,WAAO;AAAA,EACT;AAGA,MAAI,eAAe,kBAAkB,QAAQ;AAC7C,MAAI,CAAC,WAAW,YAAY,GAAG;AAC7B,mBAAe,KAAK,QAAQ,IAAI,GAAG,YAAY;AAAA,EACjD;AAGA,MAAI;AACJ,QAAM,cAAc,kBAAkB,UAAU;AAEhD,MAAI,WAAW,WAAW,GAAG;AAC3B,aAAS,UAAU,WAAW;AAAA,EAChC,OAAO;AACL,aAAS,UAAU,KAAK,cAAc,WAAW,CAAC;AAAA,EACpD;AAGA,MAAI,cAAc,OAAO,QAAQ,MAAM;AACrC,WAAO,OAAO,MAAM,GAAG,EAAE,KAAK,GAAG;AAAA,EACnC;AACA,MAAI,cAAc,QAAQ,QAAQ,KAAK;AACrC,WAAO,OAAO,MAAM,GAAG,EAAE,KAAK,IAAI;AAAA,EACpC;AACA,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { xpath, exefile, exedir };
|
|
2
|
+
/** 执行文件路径,支持 pm2 等工具通过环境变量覆盖 */
|
|
3
|
+
declare const exefile: string;
|
|
4
|
+
/** 执行文件所在目录 */
|
|
5
|
+
declare const exedir: string;
|
|
6
|
+
/**
|
|
7
|
+
* 强大可靠的路径处理
|
|
8
|
+
* - 相对路径在后,绝对路径在前,最终都转换为绝对路径
|
|
9
|
+
* - 统一分隔符,方便比较路径
|
|
10
|
+
* - 自动处理 file:/// 协议、../裁切等
|
|
11
|
+
* @param targetPath - 目标路径(可以是相对路径或绝对路径)
|
|
12
|
+
* @param basePath - 基准路径,默认为 process.cwd()
|
|
13
|
+
* @param separator - 路径分隔符,默认为 '/'
|
|
14
|
+
*/
|
|
15
|
+
declare function xpath(targetPath?: string, basePath?: string, separator?: '/' | '\\'): string;
|
|
16
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAC,CAAC;AAEhC,gCAAgC;AAChC,QAAA,MAAM,OAAO,QAA8E,CAAC;AAE5F,eAAe;AACf,QAAA,MAAM,MAAM,QAAmB,CAAC;AAEhC;;;;;;;;GAQG;AACH,iBAAS,KAAK,CAAC,UAAU,GAAE,MAAY,EAAE,QAAQ,GAAE,MAAe,EAAE,SAAS,GAAE,GAAG,GAAG,IAAU,GAAG,MAAM,CAmCvG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghini/xstart",
|
|
3
|
-
"version": "26.1.
|
|
3
|
+
"version": "26.1.6175449",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Ghini",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,12 +19,19 @@
|
|
|
19
19
|
],
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "^25.0.3",
|
|
22
|
+
"@vitest/coverage-v8": "^4.0.16",
|
|
22
23
|
"esbuild": "^0.27.2",
|
|
23
|
-
"
|
|
24
|
+
"fast-check": "^4.5.3",
|
|
25
|
+
"typescript": "^5.9.3",
|
|
26
|
+
"vitest": "^4.0.16"
|
|
24
27
|
},
|
|
25
28
|
"scripts": {
|
|
26
29
|
"build": "node ./build.js",
|
|
27
30
|
"checkpub": "pnpm pack --dry-run",
|
|
28
|
-
"pub": "pnpm build && pnpm publish --no-git-checks && git add . && git commit -m 'update' && git push"
|
|
31
|
+
"pub": "pnpm build && pnpm publish --no-git-checks && git add . && git commit -m 'update' && git push",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"test:watch": "vitest",
|
|
34
|
+
"test:coverage": "vitest run --coverage",
|
|
35
|
+
"typecheck": "tsc --noEmit"
|
|
29
36
|
}
|
|
30
37
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
export * from './
|
|
2
|
+
export * from './utils.ts';
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// src/utils.ts
|
|
2
|
+
import {normalize, join, isAbsolute, sep, dirname} from 'node:path';
|
|
3
|
+
|
|
4
|
+
export {xpath, exefile, exedir};
|
|
5
|
+
|
|
6
|
+
/** 执行文件路径,支持 pm2 等工具通过环境变量覆盖 */
|
|
7
|
+
const exefile = process.env.KIT_EXEPATH || process.env.KIT_EXEFILE || process.argv[1] || '';
|
|
8
|
+
|
|
9
|
+
/** 执行文件所在目录 */
|
|
10
|
+
const exedir = dirname(exefile);
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 强大可靠的路径处理
|
|
14
|
+
* - 相对路径在后,绝对路径在前,最终都转换为绝对路径
|
|
15
|
+
* - 统一分隔符,方便比较路径
|
|
16
|
+
* - 自动处理 file:/// 协议、../裁切等
|
|
17
|
+
* @param targetPath - 目标路径(可以是相对路径或绝对路径)
|
|
18
|
+
* @param basePath - 基准路径,默认为 process.cwd()
|
|
19
|
+
* @param separator - 路径分隔符,默认为 '/'
|
|
20
|
+
*/
|
|
21
|
+
function xpath(targetPath: string = '.', basePath: string = exedir, separator: '/' | '\\' = '/'): string {
|
|
22
|
+
// 处理 file:/// 协议
|
|
23
|
+
const stripFileProtocol = (p: string): string => {
|
|
24
|
+
if (p.startsWith('file:///')) {
|
|
25
|
+
// Windows: file:///C:/path → C:/path (去掉8个字符)
|
|
26
|
+
// Unix: file:///path → /path (去掉7个字符)
|
|
27
|
+
return process.platform === 'win32' ? p.slice(8) : p.slice(7);
|
|
28
|
+
}
|
|
29
|
+
return p;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// 处理 basePath
|
|
33
|
+
let resolvedBase = stripFileProtocol(basePath);
|
|
34
|
+
if (!isAbsolute(resolvedBase)) {
|
|
35
|
+
resolvedBase = join(process.cwd(), resolvedBase);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 处理 targetPath
|
|
39
|
+
let result: string;
|
|
40
|
+
const cleanTarget = stripFileProtocol(targetPath);
|
|
41
|
+
|
|
42
|
+
if (isAbsolute(cleanTarget)) {
|
|
43
|
+
result = normalize(cleanTarget);
|
|
44
|
+
} else {
|
|
45
|
+
result = normalize(join(resolvedBase, cleanTarget));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 统一分隔符
|
|
49
|
+
if (separator === '/' && sep === '\\') {
|
|
50
|
+
return result.split(sep).join('/');
|
|
51
|
+
}
|
|
52
|
+
if (separator === '\\' && sep === '/') {
|
|
53
|
+
return result.split(sep).join('\\');
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
package/dist/start.d.ts
DELETED
package/dist/start.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../src/start.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,CAAC;AAEjB,iBAAS,KAAK,IAAI,IAAI,CAErB"}
|