@ciderjs/gasbombe 0.2.0 → 0.2.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.
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.2";
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.2";
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
@@ -18,8 +18,7 @@ async function runCommand(command, args, cwd, capture = false) {
18
18
  return new Promise((resolve, reject) => {
19
19
  const child = node_child_process.spawn(command, args, {
20
20
  cwd,
21
- stdio: capture ? "pipe" : "inherit",
22
- shell: true
21
+ stdio: capture ? "pipe" : "inherit"
23
22
  });
24
23
  let stdout = "";
25
24
  let stderr = "";
@@ -64,9 +63,17 @@ async function handleClaspSetup(claspOption, projectName, outputDir, claspProjec
64
63
  }
65
64
  }
66
65
  let scriptId;
66
+ let existingClaspJson = null;
67
67
  switch (claspOption) {
68
68
  case "create":
69
69
  try {
70
+ const claspJsonPath = path__default.join(outputDir, ".clasp.json");
71
+ try {
72
+ const existingContent = await fs__default.readFile(claspJsonPath, "utf-8");
73
+ existingClaspJson = JSON.parse(existingContent);
74
+ await fs__default.unlink(claspJsonPath);
75
+ } catch {
76
+ }
70
77
  const result = await runCommand(
71
78
  npxLikeCommand,
72
79
  [
@@ -139,12 +146,17 @@ async function handleClaspSetup(claspOption, projectName, outputDir, claspProjec
139
146
  scriptId
140
147
  };
141
148
  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 };
149
+ if (existingClaspJson) {
150
+ claspJson = { ...existingClaspJson, scriptId };
146
151
  successMessage = `.clasp.json updated successfully with scriptId: ${scriptId}`;
147
- } catch {
152
+ } else {
153
+ try {
154
+ const existingContent = await fs__default.readFile(claspJsonPath, "utf-8");
155
+ const currentClaspJson = JSON.parse(existingContent);
156
+ claspJson = { ...currentClaspJson, scriptId };
157
+ successMessage = `.clasp.json updated successfully with scriptId: ${scriptId}`;
158
+ } catch {
159
+ }
148
160
  }
149
161
  const claspJsonContent = JSON.stringify(claspJson, null, 2);
150
162
  await fs__default.writeFile(claspJsonPath, claspJsonContent, { encoding: "utf-8" });
@@ -166,12 +178,28 @@ async function generateProject({
166
178
  consola.consola.start(
167
179
  `Creating a new Project for GoogleAppsScript in ${outputDir}...`
168
180
  );
169
- try {
170
- await fs__default.access(outputDir);
171
- consola.consola.error(`Directory ${projectName} already exists.`);
172
- process.exit(1);
173
- return;
174
- } catch {
181
+ if (projectName === ".") {
182
+ try {
183
+ const files = await fs__default.readdir(outputDir);
184
+ const relevantFiles = files.filter((file) => !file.startsWith("."));
185
+ if (relevantFiles.length > 0) {
186
+ const proceed = await confirm(
187
+ "Current directory is not empty. Proceed anyway?"
188
+ );
189
+ if (!proceed) {
190
+ consola.consola.warn("Operation cancelled.");
191
+ process.exit(0);
192
+ }
193
+ }
194
+ } catch {
195
+ }
196
+ } else {
197
+ try {
198
+ await fs__default.access(outputDir);
199
+ consola.consola.error(`Directory ${projectName} already exists.`);
200
+ process.exit(1);
201
+ } catch {
202
+ }
175
203
  }
176
204
  await fs__default.mkdir(outputDir, { recursive: true });
177
205
  consola.consola.info(`Generating project files from template '${templateType}'...`);
package/dist/index.mjs CHANGED
@@ -19,8 +19,7 @@ async function runCommand(command, args, cwd, capture = false) {
19
19
  return new Promise((resolve, reject) => {
20
20
  const child = spawn(command, args, {
21
21
  cwd,
22
- stdio: capture ? "pipe" : "inherit",
23
- shell: true
22
+ stdio: capture ? "pipe" : "inherit"
24
23
  });
25
24
  let stdout = "";
26
25
  let stderr = "";
@@ -65,9 +64,17 @@ async function handleClaspSetup(claspOption, projectName, outputDir, claspProjec
65
64
  }
66
65
  }
67
66
  let scriptId;
67
+ let existingClaspJson = null;
68
68
  switch (claspOption) {
69
69
  case "create":
70
70
  try {
71
+ const claspJsonPath = path.join(outputDir, ".clasp.json");
72
+ try {
73
+ const existingContent = await fs.readFile(claspJsonPath, "utf-8");
74
+ existingClaspJson = JSON.parse(existingContent);
75
+ await fs.unlink(claspJsonPath);
76
+ } catch {
77
+ }
71
78
  const result = await runCommand(
72
79
  npxLikeCommand,
73
80
  [
@@ -140,12 +147,17 @@ async function handleClaspSetup(claspOption, projectName, outputDir, claspProjec
140
147
  scriptId
141
148
  };
142
149
  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 };
150
+ if (existingClaspJson) {
151
+ claspJson = { ...existingClaspJson, scriptId };
147
152
  successMessage = `.clasp.json updated successfully with scriptId: ${scriptId}`;
148
- } catch {
153
+ } else {
154
+ try {
155
+ const existingContent = await fs.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
+ }
149
161
  }
150
162
  const claspJsonContent = JSON.stringify(claspJson, null, 2);
151
163
  await fs.writeFile(claspJsonPath, claspJsonContent, { encoding: "utf-8" });
@@ -167,12 +179,28 @@ async function generateProject({
167
179
  consola.start(
168
180
  `Creating a new Project for GoogleAppsScript in ${outputDir}...`
169
181
  );
170
- try {
171
- await fs.access(outputDir);
172
- consola.error(`Directory ${projectName} already exists.`);
173
- process.exit(1);
174
- return;
175
- } catch {
182
+ if (projectName === ".") {
183
+ try {
184
+ const files = await fs.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.warn("Operation cancelled.");
192
+ process.exit(0);
193
+ }
194
+ }
195
+ } catch {
196
+ }
197
+ } else {
198
+ try {
199
+ await fs.access(outputDir);
200
+ consola.error(`Directory ${projectName} already exists.`);
201
+ process.exit(1);
202
+ } catch {
203
+ }
176
204
  }
177
205
  await fs.mkdir(outputDir, { recursive: true });
178
206
  consola.info(`Generating project files from template '${templateType}'...`);
package/package.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "name": "@ciderjs/gasbombe",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "A TypeScript Project Generator for GoogleAppsScript, available as CLI",
5
5
  "type": "module",
6
- "main": "src/index.ts",
6
+ "main": "dist/index.cjs",
7
7
  "bin": {
8
8
  "gasbombe": "dist/cli.cjs"
9
9
  },
10
10
  "files": [
11
11
  "dist",
12
12
  "LICENSE",
13
- "README.md"
13
+ "README.md",
14
+ "README.ja.md"
14
15
  ],
15
16
  "module": "dist/index.mjs",
16
17
  "types": "dist/index.d.ts",
@@ -20,8 +21,7 @@
20
21
  "check": "biome check --write",
21
22
  "generate": "jiti scripts/copyTemplates",
22
23
  "test": "vitest run --coverage",
23
- "build": "pnpm run tsc && pnpm run test --silent && unbuild && pnpm run generate",
24
- "postinstall": "pnpm run generate"
24
+ "build": "pnpm run tsc && pnpm run test --silent && unbuild && pnpm run generate"
25
25
  },
26
26
  "keywords": [
27
27
  "googleappsscript",