lee-spec-kit 0.1.0 → 0.1.2

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.
Files changed (2) hide show
  1. package/dist/index.js +109 -1
  2. package/package.json +9 -11
package/dist/index.js CHANGED
@@ -38,6 +38,101 @@ function getTemplatesDir() {
38
38
  return path4.join(rootDir, "templates");
39
39
  }
40
40
 
41
+ // src/utils/validation.ts
42
+ var VALID_PROJECT_TYPES = ["single", "fullstack"];
43
+ var VALID_LANGUAGES = ["ko", "en"];
44
+ var VALID_REPO_TYPES = ["be", "fe"];
45
+ function validateSafeName(name) {
46
+ if (!name || name.trim().length === 0) {
47
+ return { valid: false, error: "\uC774\uB984\uC740 \uBE44\uC5B4\uC788\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4." };
48
+ }
49
+ if (name.length > 100) {
50
+ return { valid: false, error: "\uC774\uB984\uC740 100\uC790\uB97C \uCD08\uACFC\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4." };
51
+ }
52
+ if (name.includes("..") || name.includes("/") || name.includes("\\")) {
53
+ return {
54
+ valid: false,
55
+ error: "\uC774\uB984\uC5D0 '..' \uB610\uB294 \uACBD\uB85C \uAD6C\uBD84\uC790\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."
56
+ };
57
+ }
58
+ if (name.includes("\0")) {
59
+ return { valid: false, error: "\uC774\uB984\uC5D0 null \uBB38\uC790\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4." };
60
+ }
61
+ const safePattern = /^[\w가-힣\-]+$/;
62
+ if (!safePattern.test(name)) {
63
+ return {
64
+ valid: false,
65
+ error: "\uC774\uB984\uC5D0\uB294 \uC601\uBB38, \uC22B\uC790, \uD558\uC774\uD508, \uC5B8\uB354\uC2A4\uCF54\uC5B4, \uD55C\uAE00\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4."
66
+ };
67
+ }
68
+ const reservedNames = [
69
+ ".",
70
+ "..",
71
+ "con",
72
+ "prn",
73
+ "aux",
74
+ "nul",
75
+ "com1",
76
+ "com2",
77
+ "com3",
78
+ "com4",
79
+ "lpt1",
80
+ "lpt2",
81
+ "lpt3",
82
+ "lpt4"
83
+ ];
84
+ if (reservedNames.includes(name.toLowerCase())) {
85
+ return { valid: false, error: "\uC608\uC57D\uB41C \uC774\uB984\uC740 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4." };
86
+ }
87
+ return { valid: true };
88
+ }
89
+ function validateProjectType(type) {
90
+ if (!VALID_PROJECT_TYPES.includes(type)) {
91
+ return {
92
+ valid: false,
93
+ error: `\uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785\uC740 ${VALID_PROJECT_TYPES.join(", ")} \uC911 \uD558\uB098\uC5EC\uC57C \uD569\uB2C8\uB2E4.`
94
+ };
95
+ }
96
+ return { valid: true };
97
+ }
98
+ function validateLanguage(lang) {
99
+ if (!VALID_LANGUAGES.includes(lang)) {
100
+ return {
101
+ valid: false,
102
+ error: `\uC5B8\uC5B4\uB294 ${VALID_LANGUAGES.join(", ")} \uC911 \uD558\uB098\uC5EC\uC57C \uD569\uB2C8\uB2E4.`
103
+ };
104
+ }
105
+ return { valid: true };
106
+ }
107
+ function validateRepoType(repo) {
108
+ if (!VALID_REPO_TYPES.includes(repo)) {
109
+ return {
110
+ valid: false,
111
+ error: `\uB808\uD3EC\uC9C0\uD1A0\uB9AC \uD0C0\uC785\uC740 ${VALID_REPO_TYPES.join(", ")} \uC911 \uD558\uB098\uC5EC\uC57C \uD569\uB2C8\uB2E4.`
112
+ };
113
+ }
114
+ return { valid: true };
115
+ }
116
+ function validateFeatureId(id) {
117
+ if (!id || id.trim().length === 0) {
118
+ return { valid: false, error: "Feature ID\uB294 \uBE44\uC5B4\uC788\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4." };
119
+ }
120
+ const featureIdPattern = /^F\d{3,}$/;
121
+ if (!featureIdPattern.test(id)) {
122
+ return {
123
+ valid: false,
124
+ error: "Feature ID\uB294 'F' + \uC22B\uC790 \uD615\uC2DD\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4 (\uC608: F001)."
125
+ };
126
+ }
127
+ return { valid: true };
128
+ }
129
+ function assertValid(result, context) {
130
+ if (!result.valid) {
131
+ const message = context ? `${context}: ${result.error}` : result.error ?? "\uAC80\uC99D \uC2E4\uD328";
132
+ throw new Error(message);
133
+ }
134
+ }
135
+
41
136
  // src/commands/init.ts
42
137
  function initCommand(program2) {
43
138
  program2.command("init").description("Initialize project documentation structure").option("-n, --name <name>", "Project name (default: current folder name)").option("-t, --type <type>", "Project type: single | fullstack").option("-l, --lang <lang>", "Language: ko | en (default: ko)").option("-d, --dir <dir>", "Target directory (default: ./docs)", "./docs").option("-y, --yes", "Skip prompts and use defaults").action(async (options) => {
@@ -111,6 +206,9 @@ async function runInit(options) {
111
206
  if (!projectType) {
112
207
  projectType = "single";
113
208
  }
209
+ assertValid(validateSafeName(projectName), "\uD504\uB85C\uC81D\uD2B8 \uC774\uB984");
210
+ assertValid(validateProjectType(projectType), "\uD504\uB85C\uC81D\uD2B8 \uD0C0\uC785");
211
+ assertValid(validateLanguage(lang), "\uC5B8\uC5B4");
114
212
  if (await fs5.pathExists(targetDir)) {
115
213
  const files = await fs5.readdir(targetDir);
116
214
  if (files.length > 0) {
@@ -203,6 +301,7 @@ async function runFeature(name, options) {
203
301
  process.exit(1);
204
302
  }
205
303
  const { docsDir, projectType, lang } = config;
304
+ assertValid(validateSafeName(name), "\uAE30\uB2A5 \uC774\uB984");
206
305
  let repo = options.repo;
207
306
  if (projectType === "fullstack" && !repo) {
208
307
  const response = await prompts(
@@ -223,7 +322,16 @@ async function runFeature(name, options) {
223
322
  );
224
323
  repo = response.repo;
225
324
  }
226
- const featureId = options.id || await getNextFeatureId(docsDir, projectType);
325
+ if (repo) {
326
+ assertValid(validateRepoType(repo), "\uB808\uD3EC\uC9C0\uD1A0\uB9AC \uD0C0\uC785");
327
+ }
328
+ let featureId;
329
+ if (options.id) {
330
+ assertValid(validateFeatureId(options.id), "Feature ID");
331
+ featureId = options.id;
332
+ } else {
333
+ featureId = await getNextFeatureId(docsDir, projectType);
334
+ }
227
335
  let featuresDir;
228
336
  if (projectType === "fullstack" && repo) {
229
337
  featuresDir = path4.join(docsDir, "features", repo);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lee-spec-kit",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Project documentation structure generator for AI-assisted development",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,13 +12,6 @@
12
12
  "dist",
13
13
  "templates"
14
14
  ],
15
- "scripts": {
16
- "build": "tsup",
17
- "dev": "tsup --watch",
18
- "lint": "eslint src",
19
- "format": "prettier --write .",
20
- "prepublishOnly": "pnpm build"
21
- },
22
15
  "keywords": [
23
16
  "docs",
24
17
  "template",
@@ -35,7 +28,7 @@
35
28
  },
36
29
  "repository": {
37
30
  "type": "git",
38
- "url": "https://github.com/leeyoonsu/lee-spec-kit"
31
+ "url": "https://github.com/leey00nsu/lee-spec-kit"
39
32
  },
40
33
  "dependencies": {
41
34
  "chalk": "^5.6.2",
@@ -56,5 +49,10 @@
56
49
  "tsup": "^8.5.1",
57
50
  "typescript": "^5.9.3"
58
51
  },
59
- "packageManager": "pnpm@10.7.0"
60
- }
52
+ "scripts": {
53
+ "build": "tsup",
54
+ "dev": "tsup --watch",
55
+ "lint": "eslint src",
56
+ "format": "prettier --write ."
57
+ }
58
+ }