@ciderjs/gasbombe 0.2.0 → 0.2.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/dist/cli.cjs CHANGED
@@ -11,14 +11,14 @@ require('consola');
11
11
  require('ejs');
12
12
  require('glob');
13
13
 
14
- const version = "0.2.0";
14
+ const version = "0.2.1";
15
15
 
16
16
  async function main() {
17
17
  const program = new commander.Command();
18
18
  program.version(version, "-v, --version");
19
19
  program.description("Create project for GoogleAppsScript").option(
20
20
  "-n, --name [projectName]",
21
- "Project name what you want to generate",
21
+ 'Project name what you want to generate\n* Project name must be "." or a valid folder name without path characters.',
22
22
  ""
23
23
  ).option(
24
24
  "-p, --pkg [packageManager]",
@@ -46,9 +46,22 @@ async function main() {
46
46
  } = command.opts();
47
47
  let claspProjectId;
48
48
  try {
49
+ const validProjectNameRegex = /^(?!.*\.\.)[a-zA-Z0-9_-]+$/;
49
50
  projectName ||= await prompts.input({
50
- message: "Input project name what you want to generate..."
51
+ message: "Input project name what you want to generate...",
52
+ validate: (value) => {
53
+ if (value === ".") {
54
+ return true;
55
+ }
56
+ if (validProjectNameRegex.test(value) && !value.includes("/") && !value.includes("\\")) {
57
+ return true;
58
+ }
59
+ return 'Project name must be "." or a valid folder name without path characters.';
60
+ }
51
61
  });
62
+ if (!validProjectNameRegex.test(projectName)) {
63
+ throw Error("Invalid project name");
64
+ }
52
65
  templateType ||= await prompts.select({
53
66
  message: "Choice project template...",
54
67
  choices: [
@@ -56,6 +69,10 @@ async function main() {
56
69
  { name: "react-tsx", value: "react-tsx" }
57
70
  ]
58
71
  });
72
+ const templateTypes = ["vanilla-ts", "react-tsx"];
73
+ if (!templateTypes.includes(templateType)) {
74
+ throw Error("Invalid project template");
75
+ }
59
76
  clasp ||= await prompts.select({
60
77
  message: 'How do you want to set up the Apps Script project?\n* If you use "create" or "select", you need to login to clasp first',
61
78
  choices: [
@@ -81,6 +98,10 @@ async function main() {
81
98
  }
82
99
  ]
83
100
  });
101
+ const claspOptions = ["create", "list", "input", "skip"];
102
+ if (!claspOptions.includes(clasp)) {
103
+ throw Error("Invalid clasp option");
104
+ }
84
105
  if (clasp === "input") {
85
106
  claspProjectId = await prompts.input({
86
107
  message: "Input Apps Script project ID...",
@@ -98,6 +119,10 @@ async function main() {
98
119
  { name: "yarn", value: "yarn" }
99
120
  ]
100
121
  });
122
+ const packageManagers = ["npm", "pnpm", "yarn"];
123
+ if (!packageManagers.includes(packageManager)) {
124
+ throw Error("Invalid package manager");
125
+ }
101
126
  } catch (e) {
102
127
  e.message === "User force closed the prompt with SIGINT" && process.exit(0);
103
128
  throw e;
package/dist/cli.mjs CHANGED
@@ -9,14 +9,14 @@ import 'consola';
9
9
  import 'ejs';
10
10
  import 'glob';
11
11
 
12
- const version = "0.2.0";
12
+ const version = "0.2.1";
13
13
 
14
14
  async function main() {
15
15
  const program = new Command();
16
16
  program.version(version, "-v, --version");
17
17
  program.description("Create project for GoogleAppsScript").option(
18
18
  "-n, --name [projectName]",
19
- "Project name what you want to generate",
19
+ 'Project name what you want to generate\n* Project name must be "." or a valid folder name without path characters.',
20
20
  ""
21
21
  ).option(
22
22
  "-p, --pkg [packageManager]",
@@ -44,9 +44,22 @@ async function main() {
44
44
  } = command.opts();
45
45
  let claspProjectId;
46
46
  try {
47
+ const validProjectNameRegex = /^(?!.*\.\.)[a-zA-Z0-9_-]+$/;
47
48
  projectName ||= await input({
48
- message: "Input project name what you want to generate..."
49
+ message: "Input project name what you want to generate...",
50
+ validate: (value) => {
51
+ if (value === ".") {
52
+ return true;
53
+ }
54
+ if (validProjectNameRegex.test(value) && !value.includes("/") && !value.includes("\\")) {
55
+ return true;
56
+ }
57
+ return 'Project name must be "." or a valid folder name without path characters.';
58
+ }
49
59
  });
60
+ if (!validProjectNameRegex.test(projectName)) {
61
+ throw Error("Invalid project name");
62
+ }
50
63
  templateType ||= await select({
51
64
  message: "Choice project template...",
52
65
  choices: [
@@ -54,6 +67,10 @@ async function main() {
54
67
  { name: "react-tsx", value: "react-tsx" }
55
68
  ]
56
69
  });
70
+ const templateTypes = ["vanilla-ts", "react-tsx"];
71
+ if (!templateTypes.includes(templateType)) {
72
+ throw Error("Invalid project template");
73
+ }
57
74
  clasp ||= await select({
58
75
  message: 'How do you want to set up the Apps Script project?\n* If you use "create" or "select", you need to login to clasp first',
59
76
  choices: [
@@ -79,6 +96,10 @@ async function main() {
79
96
  }
80
97
  ]
81
98
  });
99
+ const claspOptions = ["create", "list", "input", "skip"];
100
+ if (!claspOptions.includes(clasp)) {
101
+ throw Error("Invalid clasp option");
102
+ }
82
103
  if (clasp === "input") {
83
104
  claspProjectId = await input({
84
105
  message: "Input Apps Script project ID...",
@@ -96,6 +117,10 @@ async function main() {
96
117
  { name: "yarn", value: "yarn" }
97
118
  ]
98
119
  });
120
+ const packageManagers = ["npm", "pnpm", "yarn"];
121
+ if (!packageManagers.includes(packageManager)) {
122
+ throw Error("Invalid package manager");
123
+ }
99
124
  } catch (e) {
100
125
  e.message === "User force closed the prompt with SIGINT" && process.exit(0);
101
126
  throw e;
package/dist/index.cjs CHANGED
@@ -64,9 +64,17 @@ async function handleClaspSetup(claspOption, projectName, outputDir, claspProjec
64
64
  }
65
65
  }
66
66
  let scriptId;
67
+ let existingClaspJson = null;
67
68
  switch (claspOption) {
68
69
  case "create":
69
70
  try {
71
+ const claspJsonPath = path__default.join(outputDir, ".clasp.json");
72
+ try {
73
+ const existingContent = await fs__default.readFile(claspJsonPath, "utf-8");
74
+ existingClaspJson = JSON.parse(existingContent);
75
+ await fs__default.unlink(claspJsonPath);
76
+ } catch {
77
+ }
70
78
  const result = await runCommand(
71
79
  npxLikeCommand,
72
80
  [
@@ -139,12 +147,17 @@ async function handleClaspSetup(claspOption, projectName, outputDir, claspProjec
139
147
  scriptId
140
148
  };
141
149
  let successMessage = `.clasp.json created successfully with scriptId: ${scriptId}`;
142
- try {
143
- const existingContent = await fs__default.readFile(claspJsonPath, "utf-8");
144
- const existingJson = JSON.parse(existingContent);
145
- claspJson = { ...existingJson, scriptId };
150
+ if (existingClaspJson) {
151
+ claspJson = { ...existingClaspJson, scriptId };
146
152
  successMessage = `.clasp.json updated successfully with scriptId: ${scriptId}`;
147
- } catch {
153
+ } else {
154
+ try {
155
+ const existingContent = await fs__default.readFile(claspJsonPath, "utf-8");
156
+ const currentClaspJson = JSON.parse(existingContent);
157
+ claspJson = { ...currentClaspJson, scriptId };
158
+ successMessage = `.clasp.json updated successfully with scriptId: ${scriptId}`;
159
+ } catch {
160
+ }
148
161
  }
149
162
  const claspJsonContent = JSON.stringify(claspJson, null, 2);
150
163
  await fs__default.writeFile(claspJsonPath, claspJsonContent, { encoding: "utf-8" });
@@ -166,12 +179,28 @@ async function generateProject({
166
179
  consola.consola.start(
167
180
  `Creating a new Project for GoogleAppsScript in ${outputDir}...`
168
181
  );
169
- try {
170
- await fs__default.access(outputDir);
171
- consola.consola.error(`Directory ${projectName} already exists.`);
172
- process.exit(1);
173
- return;
174
- } catch {
182
+ if (projectName === ".") {
183
+ try {
184
+ const files = await fs__default.readdir(outputDir);
185
+ const relevantFiles = files.filter((file) => !file.startsWith("."));
186
+ if (relevantFiles.length > 0) {
187
+ const proceed = await confirm(
188
+ "Current directory is not empty. Proceed anyway?"
189
+ );
190
+ if (!proceed) {
191
+ consola.consola.warn("Operation cancelled.");
192
+ process.exit(0);
193
+ }
194
+ }
195
+ } catch {
196
+ }
197
+ } else {
198
+ try {
199
+ await fs__default.access(outputDir);
200
+ consola.consola.error(`Directory ${projectName} already exists.`);
201
+ process.exit(1);
202
+ } catch {
203
+ }
175
204
  }
176
205
  await fs__default.mkdir(outputDir, { recursive: true });
177
206
  consola.consola.info(`Generating project files from template '${templateType}'...`);
package/dist/index.mjs CHANGED
@@ -65,9 +65,17 @@ async function handleClaspSetup(claspOption, projectName, outputDir, claspProjec
65
65
  }
66
66
  }
67
67
  let scriptId;
68
+ let existingClaspJson = null;
68
69
  switch (claspOption) {
69
70
  case "create":
70
71
  try {
72
+ const claspJsonPath = path.join(outputDir, ".clasp.json");
73
+ try {
74
+ const existingContent = await fs.readFile(claspJsonPath, "utf-8");
75
+ existingClaspJson = JSON.parse(existingContent);
76
+ await fs.unlink(claspJsonPath);
77
+ } catch {
78
+ }
71
79
  const result = await runCommand(
72
80
  npxLikeCommand,
73
81
  [
@@ -140,12 +148,17 @@ async function handleClaspSetup(claspOption, projectName, outputDir, claspProjec
140
148
  scriptId
141
149
  };
142
150
  let successMessage = `.clasp.json created successfully with scriptId: ${scriptId}`;
143
- try {
144
- const existingContent = await fs.readFile(claspJsonPath, "utf-8");
145
- const existingJson = JSON.parse(existingContent);
146
- claspJson = { ...existingJson, scriptId };
151
+ if (existingClaspJson) {
152
+ claspJson = { ...existingClaspJson, scriptId };
147
153
  successMessage = `.clasp.json updated successfully with scriptId: ${scriptId}`;
148
- } catch {
154
+ } else {
155
+ try {
156
+ const existingContent = await fs.readFile(claspJsonPath, "utf-8");
157
+ const currentClaspJson = JSON.parse(existingContent);
158
+ claspJson = { ...currentClaspJson, scriptId };
159
+ successMessage = `.clasp.json updated successfully with scriptId: ${scriptId}`;
160
+ } catch {
161
+ }
149
162
  }
150
163
  const claspJsonContent = JSON.stringify(claspJson, null, 2);
151
164
  await fs.writeFile(claspJsonPath, claspJsonContent, { encoding: "utf-8" });
@@ -167,12 +180,28 @@ async function generateProject({
167
180
  consola.start(
168
181
  `Creating a new Project for GoogleAppsScript in ${outputDir}...`
169
182
  );
170
- try {
171
- await fs.access(outputDir);
172
- consola.error(`Directory ${projectName} already exists.`);
173
- process.exit(1);
174
- return;
175
- } catch {
183
+ if (projectName === ".") {
184
+ try {
185
+ const files = await fs.readdir(outputDir);
186
+ const relevantFiles = files.filter((file) => !file.startsWith("."));
187
+ if (relevantFiles.length > 0) {
188
+ const proceed = await confirm(
189
+ "Current directory is not empty. Proceed anyway?"
190
+ );
191
+ if (!proceed) {
192
+ consola.warn("Operation cancelled.");
193
+ process.exit(0);
194
+ }
195
+ }
196
+ } catch {
197
+ }
198
+ } else {
199
+ try {
200
+ await fs.access(outputDir);
201
+ consola.error(`Directory ${projectName} already exists.`);
202
+ process.exit(1);
203
+ } catch {
204
+ }
176
205
  }
177
206
  await fs.mkdir(outputDir, { recursive: true });
178
207
  consola.info(`Generating project files from template '${templateType}'...`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ciderjs/gasbombe",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "A TypeScript Project Generator for GoogleAppsScript, available as CLI",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/index.ts CHANGED
@@ -81,10 +81,20 @@ async function handleClaspSetup(
81
81
  }
82
82
 
83
83
  let scriptId: string | undefined;
84
+ let existingClaspJson: { scriptId: string; [key: string]: string | string[] } | null = null;
84
85
 
85
86
  switch (claspOption) {
86
87
  case 'create':
87
88
  try {
89
+ const claspJsonPath = path.join(outputDir, '.clasp.json');
90
+ try {
91
+ const existingContent = await fs.readFile(claspJsonPath, 'utf-8');
92
+ existingClaspJson = JSON.parse(existingContent);
93
+ await fs.unlink(claspJsonPath);
94
+ } catch {
95
+ // No existing .clasp.json, which is fine.
96
+ }
97
+
88
98
  const result = await runCommand(
89
99
  npxLikeCommand,
90
100
  [
@@ -169,13 +179,18 @@ async function handleClaspSetup(
169
179
  };
170
180
  let successMessage = `.clasp.json created successfully with scriptId: ${scriptId}`;
171
181
 
172
- try {
173
- const existingContent = await fs.readFile(claspJsonPath, 'utf-8');
174
- const existingJson = JSON.parse(existingContent);
175
- claspJson = { ...existingJson, scriptId };
182
+ if (existingClaspJson) {
183
+ claspJson = { ...existingClaspJson, scriptId };
176
184
  successMessage = `.clasp.json updated successfully with scriptId: ${scriptId}`;
177
- } catch {
178
- // If file doesn't exist or is invalid, we'll just create a new one.
185
+ } else {
186
+ try {
187
+ const existingContent = await fs.readFile(claspJsonPath, 'utf-8');
188
+ const currentClaspJson = JSON.parse(existingContent);
189
+ claspJson = { ...currentClaspJson, scriptId };
190
+ successMessage = `.clasp.json updated successfully with scriptId: ${scriptId}`;
191
+ } catch {
192
+ // If file doesn't exist or is invalid, we'll just create a new one.
193
+ }
179
194
  }
180
195
 
181
196
  const claspJsonContent = JSON.stringify(claspJson, null, 2);
@@ -201,13 +216,32 @@ export async function generateProject({
201
216
  `Creating a new Project for GoogleAppsScript in ${outputDir}...`,
202
217
  );
203
218
 
204
- try {
205
- await fs.access(outputDir);
206
- consola.error(`Directory ${projectName} already exists.`);
207
- process.exit(1);
208
- return;
209
- } catch {
210
- // Directory does not exist, which is what we want.
219
+ if (projectName === '.') {
220
+ try {
221
+ const files = await fs.readdir(outputDir);
222
+ const relevantFiles = files.filter((file) => !file.startsWith('.'));
223
+
224
+ if (relevantFiles.length > 0) {
225
+ const proceed = await confirm(
226
+ 'Current directory is not empty. Proceed anyway?',
227
+ );
228
+
229
+ if (!proceed) {
230
+ consola.warn('Operation cancelled.');
231
+ process.exit(0);
232
+ }
233
+ }
234
+ } catch {
235
+ // Directory does not exist, then mkdir will create it.
236
+ }
237
+ } else {
238
+ try {
239
+ await fs.access(outputDir);
240
+ consola.error(`Directory ${projectName} already exists.`);
241
+ process.exit(1);
242
+ } catch {
243
+ // Directory does not exist, which is what we want.
244
+ }
211
245
  }
212
246
 
213
247
  await fs.mkdir(outputDir, { recursive: true });