test(create): vitest and package name normalization

Made-with: Cursor
This commit is contained in:
zuiidea
2026-04-14 22:30:41 +08:00
parent 0185201cbd
commit 831aef8a7b
3 changed files with 46 additions and 0 deletions
@@ -0,0 +1,12 @@
import { describe, expect, it } from "vitest";
import { normalizePackageName } from "./normalize-package-name.js";
describe("normalizePackageName", () => {
it("lowercases and replaces spaces", () => {
expect(normalizePackageName("My App")).toBe("my-app");
});
it("rejects leading dot", () => {
expect(() => normalizePackageName(".bad")).toThrow(/cannot start/);
});
});
@@ -0,0 +1,26 @@
import { CliError } from "../errors.js";
/**
* npm package name rules (simplified): lowercase, URL-safe, no leading dot, segments 1-214.
*/
export function normalizePackageName(input: string): string {
const trimmed = input.trim().toLowerCase();
if (!trimmed) {
throw new CliError("Project name cannot be empty", "INVALID_INPUT");
}
if (trimmed.startsWith(".") || trimmed.startsWith("_")) {
throw new CliError(
"Project name cannot start with . or _",
"INVALID_INPUT"
);
}
const safe = trimmed
.replace(/\s+/g, "-")
.replace(/[^a-z0-9-._~]/g, "-")
.replace(/-+/g, "-")
.replace(/^-+|-+$/g, "");
if (!safe || safe.length > 214) {
throw new CliError("Project name is invalid or too long", "INVALID_INPUT");
}
return safe;
}
+8
View File
@@ -0,0 +1,8 @@
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
environment: "node",
include: ["src/**/*.test.ts"],
},
});