create-skybridge 0.0.0-dev.871732d → 0.0.0-dev.8b9ef00
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/index.d.ts +1 -1
- package/dist/index.js +20 -16
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +22 -0
- package/index.js +6 -1
- package/package.json +5 -2
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export declare function init(args?: string[]): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -3,11 +3,6 @@ import path from "node:path";
|
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import * as prompts from "@clack/prompts";
|
|
5
5
|
import mri from "mri";
|
|
6
|
-
const argv = mri(process.argv.slice(2), {
|
|
7
|
-
boolean: ["help", "overwrite"],
|
|
8
|
-
alias: { h: "help" },
|
|
9
|
-
});
|
|
10
|
-
const cwd = process.cwd();
|
|
11
6
|
const defaultProjectName = "skybridge-project";
|
|
12
7
|
// prettier-ignore
|
|
13
8
|
const helpMessage = `\
|
|
@@ -23,9 +18,13 @@ Examples:
|
|
|
23
18
|
create-skybridge my-app
|
|
24
19
|
create-skybridge . --overwrite
|
|
25
20
|
`;
|
|
26
|
-
async function init() {
|
|
21
|
+
export async function init(args = process.argv.slice(2)) {
|
|
22
|
+
const argv = mri(args, {
|
|
23
|
+
boolean: ["help", "overwrite"],
|
|
24
|
+
alias: { h: "help" },
|
|
25
|
+
});
|
|
27
26
|
const argTargetDir = argv._[0]
|
|
28
|
-
?
|
|
27
|
+
? sanitizeTargetDir(String(argv._[0]))
|
|
29
28
|
: undefined;
|
|
30
29
|
const argOverwrite = argv.overwrite;
|
|
31
30
|
const help = argv.help;
|
|
@@ -44,14 +43,14 @@ async function init() {
|
|
|
44
43
|
defaultValue: defaultProjectName,
|
|
45
44
|
placeholder: defaultProjectName,
|
|
46
45
|
validate: (value) => {
|
|
47
|
-
return value.length === 0 ||
|
|
46
|
+
return value.length === 0 || sanitizeTargetDir(value).length > 0
|
|
48
47
|
? undefined
|
|
49
48
|
: "Invalid project name";
|
|
50
49
|
},
|
|
51
50
|
});
|
|
52
51
|
if (prompts.isCancel(projectName))
|
|
53
52
|
return cancel();
|
|
54
|
-
targetDir =
|
|
53
|
+
targetDir = sanitizeTargetDir(projectName);
|
|
55
54
|
}
|
|
56
55
|
else {
|
|
57
56
|
targetDir = defaultProjectName;
|
|
@@ -95,7 +94,7 @@ async function init() {
|
|
|
95
94
|
return;
|
|
96
95
|
}
|
|
97
96
|
}
|
|
98
|
-
const root = path.join(cwd, targetDir);
|
|
97
|
+
const root = path.join(process.cwd(), targetDir);
|
|
99
98
|
// 3. Copy the repository
|
|
100
99
|
prompts.log.step(`Copying template...`);
|
|
101
100
|
try {
|
|
@@ -121,8 +120,17 @@ async function init() {
|
|
|
121
120
|
process.exit(1);
|
|
122
121
|
}
|
|
123
122
|
}
|
|
124
|
-
function
|
|
125
|
-
return targetDir
|
|
123
|
+
function sanitizeTargetDir(targetDir) {
|
|
124
|
+
return (targetDir
|
|
125
|
+
.trim()
|
|
126
|
+
// Only keep alphanumeric, dash, underscore, dot, @, /
|
|
127
|
+
.replace(/[^a-zA-Z0-9\-_.@/]/g, "")
|
|
128
|
+
// Prevent path traversal
|
|
129
|
+
.replace(/\.\./g, "")
|
|
130
|
+
// Collapse multiple slashes
|
|
131
|
+
.replace(/\/+/g, "/")
|
|
132
|
+
// Remove leading/trailing slashes
|
|
133
|
+
.replace(/^\/+|\/+$/g, ""));
|
|
126
134
|
}
|
|
127
135
|
function isEmpty(path) {
|
|
128
136
|
const files = fs.readdirSync(path);
|
|
@@ -139,7 +147,3 @@ function emptyDir(dir) {
|
|
|
139
147
|
fs.rmSync(path.resolve(dir, file), { recursive: true, force: true });
|
|
140
148
|
}
|
|
141
149
|
}
|
|
142
|
-
init().catch((e) => {
|
|
143
|
-
console.error(e);
|
|
144
|
-
process.exit(1);
|
|
145
|
-
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { afterEach, beforeEach, describe, it } from "vitest";
|
|
5
|
+
import { init } from "./index.js";
|
|
6
|
+
describe("create-skybridge", () => {
|
|
7
|
+
let tempDirName;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
tempDirName = `test-${randomBytes(2).toString("hex")}`;
|
|
10
|
+
});
|
|
11
|
+
afterEach(async () => {
|
|
12
|
+
await fs.rm(path.join(process.cwd(), tempDirName), {
|
|
13
|
+
recursive: true,
|
|
14
|
+
force: true,
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
it("should scaffold a new project", async () => {
|
|
18
|
+
const name = `../../${tempDirName}//project$`;
|
|
19
|
+
await init([name]);
|
|
20
|
+
await fs.access(path.join(process.cwd(), tempDirName, "project", ".gitignore"));
|
|
21
|
+
});
|
|
22
|
+
});
|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-skybridge",
|
|
3
|
-
"version": "0.0.0-dev.
|
|
3
|
+
"version": "0.0.0-dev.8b9ef00",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Alpic",
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
20
|
"build": "tsc",
|
|
21
|
+
"test": "pnpm run test:unit && pnpm run test:type && pnpm run test:format",
|
|
22
|
+
"test:unit": "vitest run",
|
|
21
23
|
"test:type": "tsc --noEmit",
|
|
22
24
|
"test:format": "biome ci",
|
|
23
25
|
"prepublishOnly": "pnpm run build"
|
|
@@ -28,6 +30,7 @@
|
|
|
28
30
|
},
|
|
29
31
|
"devDependencies": {
|
|
30
32
|
"@types/node": "^25.0.3",
|
|
31
|
-
"typescript": "^5.9.3"
|
|
33
|
+
"typescript": "^5.9.3",
|
|
34
|
+
"vitest": "^2.1.9"
|
|
32
35
|
}
|
|
33
36
|
}
|