@ciderjs/gasbombe 0.1.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/README.ja.md +12 -9
- package/README.md +14 -11
- package/dist/cli.cjs +98 -14
- package/dist/cli.mjs +98 -14
- package/dist/index.cjs +200 -29
- package/dist/index.d.cts +10 -4
- package/dist/index.d.mts +10 -4
- package/dist/index.d.ts +10 -4
- package/dist/index.mjs +200 -29
- package/dist/templates/react-tsx/index.html.ejs +1 -1
- package/dist/templates/react-tsx/package.json.ejs +1 -1
- package/dist/templates/vanilla-ts/package.json.ejs +1 -1
- package/package.json +8 -6
- package/src/index.ts +241 -30
- package/dist/templates/react-tsx/pnpm-lock.yaml.ejs +0 -6015
- package/dist/templates/react-tsx/pnpm-workspace.yaml.ejs +0 -3
- package/dist/templates/vanilla-ts/pnpm-lock.yaml.ejs +0 -5300
- package/dist/templates/vanilla-ts/pnpm-workspace.yaml.ejs +0 -3
package/README.ja.md
CHANGED
|
@@ -44,8 +44,9 @@ gasbombe
|
|
|
44
44
|
以下の項目について質問されます。
|
|
45
45
|
|
|
46
46
|
1. プロジェクト名
|
|
47
|
-
2.
|
|
48
|
-
3.
|
|
47
|
+
2. プロジェクトテンプレート(Vanilla TS, React)
|
|
48
|
+
3. Apps Scriptプロジェクトのセットアップ方法(`.clasp.json`)
|
|
49
|
+
4. パッケージマネージャー(npm, yarn, pnpm)
|
|
49
50
|
|
|
50
51
|
このツールは、指定されたプロジェクト名で新しいディレクトリを作成し、テンプレートファイルを生成して、依存関係をインストールします。
|
|
51
52
|
|
|
@@ -54,15 +55,17 @@ gasbombe
|
|
|
54
55
|
コマンドラインオプションを指定することで、対話型のプロンプトを省略できます。これは、スクリプトや自動化に便利です。
|
|
55
56
|
|
|
56
57
|
```bash
|
|
57
|
-
# 例: pnpmを使用して新しいReact
|
|
58
|
-
gasbombe --name my-react-app --
|
|
58
|
+
# 例: pnpmを使用して新しいReactプロジェクトを作成し、同時に新しいApps Scriptプロジェクトも作成する
|
|
59
|
+
gasbombe --name my-react-app --template react-tsx --clasp create --pkg pnpm
|
|
59
60
|
```
|
|
60
61
|
|
|
61
|
-
| オプション | 引数 | 説明 | 選択肢 |
|
|
62
|
-
| :--- | :--- | :--- | :--- |
|
|
63
|
-
| `--name` | `[projectName]` | 生成するプロジェクトの名前。 | - |
|
|
64
|
-
| `--
|
|
65
|
-
| `--
|
|
62
|
+
| オプション | エイリアス | 引数 | 説明 | 選択肢 |
|
|
63
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
64
|
+
| `--name` | `-n` | `[projectName]` | 生成するプロジェクトの名前。 | - |
|
|
65
|
+
| `--template` | `-t` | `[templateType]` | 使用するプロジェクトテンプレート。 | `vanilla-ts`, `react-tsx` |
|
|
66
|
+
| `--clasp` | `-c` | `[claspOption]` | `.clasp.json`のセットアップ方法。<br/>`create`と`list`は事前にclaspへのログインが必要です。 | `create`, `list`, `input`, `skip` |
|
|
67
|
+
| `--pkg` | `-p` | `[packageManager]` | 使用するパッケージマネージャー。 | `npm`, `pnpm`, `yarn` |
|
|
68
|
+
| `--skipInstall` | | | 依存関係のインストールをスキップします。 | - |
|
|
66
69
|
|
|
67
70
|
これらのオプションのいずれかが省略された場合、対話形式で値を入力するよう求められます。
|
|
68
71
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# **
|
|
1
|
+
# **Gasbombe**
|
|
2
2
|
|
|
3
|
-
[](./README.ja.md)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://www.npmjs.com/package/@ciderjs/gasbombe)
|
|
6
6
|
[](https://github.com/luthpg/gasbombe/issues)
|
|
@@ -44,8 +44,9 @@ gasbombe
|
|
|
44
44
|
You will be asked for:
|
|
45
45
|
|
|
46
46
|
1. Project name
|
|
47
|
-
2.
|
|
48
|
-
3.
|
|
47
|
+
2. Project template (Vanilla TS, React)
|
|
48
|
+
3. How to set up the Apps Script project (`.clasp.json`)
|
|
49
|
+
4. Package manager (npm, yarn, pnpm)
|
|
49
50
|
|
|
50
51
|
The tool will create a new directory with the specified project name, generate the template files, and install the dependencies.
|
|
51
52
|
|
|
@@ -54,15 +55,17 @@ The tool will create a new directory with the specified project name, generate t
|
|
|
54
55
|
You can bypass the interactive prompts by providing command-line options. This is useful for scripting and automation.
|
|
55
56
|
|
|
56
57
|
```bash
|
|
57
|
-
# Example: Create a new React project with pnpm
|
|
58
|
-
gasbombe --name my-react-app --
|
|
58
|
+
# Example: Create a new React project with pnpm, creating a new Apps Script project along with it
|
|
59
|
+
gasbombe --name my-react-app --template react-tsx --clasp create --pkg pnpm
|
|
59
60
|
```
|
|
60
61
|
|
|
61
|
-
| Option
|
|
62
|
-
|
|
|
63
|
-
| `--name`
|
|
64
|
-
| `--
|
|
65
|
-
| `--
|
|
62
|
+
| Option | Alias | Argument | Description | Choices |
|
|
63
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
64
|
+
| `--name` | `-n` | `[projectName]` | The name of the project to generate. | - |
|
|
65
|
+
| `--template` | `-t` | `[templateType]` | The project template to use. | `vanilla-ts`, `react-tsx` |
|
|
66
|
+
| `--clasp` | `-c` | `[claspOption]` | How to set up the `.clasp.json` file.<br/>`create` and `list` require prior login to clasp. | `create`, `list`, `input`, `skip` |
|
|
67
|
+
| `--pkg` | `-p` | `[packageManager]` | The package manager to use. | `npm`, `pnpm`, `yarn` |
|
|
68
|
+
| `--skipInstall` | | | Skip installing dependencies. | - |
|
|
66
69
|
|
|
67
70
|
If any of these options are omitted, you will be prompted to enter the value interactively.
|
|
68
71
|
|
package/dist/cli.cjs
CHANGED
|
@@ -11,46 +11,130 @@ require('consola');
|
|
|
11
11
|
require('ejs');
|
|
12
12
|
require('glob');
|
|
13
13
|
|
|
14
|
-
const version = "0.1
|
|
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
|
-
"--name [projectName]",
|
|
21
|
-
|
|
20
|
+
"-n, --name [projectName]",
|
|
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
|
-
"--pkg [packageManager]",
|
|
24
|
+
"-p, --pkg [packageManager]",
|
|
25
25
|
'Package manager what you want to use ("npm" | "pnpm" | "yarn")',
|
|
26
26
|
""
|
|
27
27
|
).option(
|
|
28
|
-
"--template [templateType]",
|
|
28
|
+
"-t, --template [templateType]",
|
|
29
29
|
'Project template label ("vanilla-ts" | "react-tsx")',
|
|
30
30
|
""
|
|
31
|
+
).option(
|
|
32
|
+
"-c, --clasp [claspSetupCommand]",
|
|
33
|
+
'Setup command how you want to use for Apps Script Project (create project | select project | input project id | skip)\n* If you use "create" or "select", you need to login to clasp first',
|
|
34
|
+
""
|
|
35
|
+
).option(
|
|
36
|
+
"--skipInstall",
|
|
37
|
+
"Skip install dependencies after generating the project",
|
|
38
|
+
false
|
|
31
39
|
).action(async (_param, command) => {
|
|
32
40
|
let {
|
|
33
41
|
name: projectName,
|
|
34
42
|
pkg: packageManager,
|
|
35
|
-
template: templateType
|
|
43
|
+
template: templateType,
|
|
44
|
+
clasp,
|
|
45
|
+
skipInstall
|
|
36
46
|
} = command.opts();
|
|
47
|
+
let claspProjectId;
|
|
37
48
|
try {
|
|
49
|
+
const validProjectNameRegex = /^(?!.*\.\.)[a-zA-Z0-9_-]+$/;
|
|
38
50
|
projectName ||= await prompts.input({
|
|
39
|
-
message: "Input project name what you want to generate..."
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
+
}
|
|
44
61
|
});
|
|
62
|
+
if (!validProjectNameRegex.test(projectName)) {
|
|
63
|
+
throw Error("Invalid project name");
|
|
64
|
+
}
|
|
45
65
|
templateType ||= await prompts.select({
|
|
46
|
-
message: "
|
|
47
|
-
choices: [
|
|
66
|
+
message: "Choice project template...",
|
|
67
|
+
choices: [
|
|
68
|
+
{ name: "vanilla-ts", value: "vanilla-ts" },
|
|
69
|
+
{ name: "react-tsx", value: "react-tsx" }
|
|
70
|
+
]
|
|
71
|
+
});
|
|
72
|
+
const templateTypes = ["vanilla-ts", "react-tsx"];
|
|
73
|
+
if (!templateTypes.includes(templateType)) {
|
|
74
|
+
throw Error("Invalid project template");
|
|
75
|
+
}
|
|
76
|
+
clasp ||= await prompts.select({
|
|
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',
|
|
78
|
+
choices: [
|
|
79
|
+
{
|
|
80
|
+
name: "[NEW] Create a new Apps Script project (need `npx @google/clasp login`)",
|
|
81
|
+
value: "create",
|
|
82
|
+
description: "Runs `npx @google/clasp create` to generate a new project."
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: "[SELECT] Use an existing Apps Script project (need `npx @google/clasp login`)",
|
|
86
|
+
value: "list",
|
|
87
|
+
description: "Runs `npx @google/clasp list` and lets you choose from your projects."
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: "[INPUT] Input Script ID manually",
|
|
91
|
+
value: "input",
|
|
92
|
+
description: "Manually provide an existing Script ID."
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: "[NONE] Skip for now",
|
|
96
|
+
value: "skip",
|
|
97
|
+
description: "Create a `.clasp.json` file without Apps Script project ID."
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
});
|
|
101
|
+
const claspOptions = ["create", "list", "input", "skip"];
|
|
102
|
+
if (!claspOptions.includes(clasp)) {
|
|
103
|
+
throw Error("Invalid clasp option");
|
|
104
|
+
}
|
|
105
|
+
if (clasp === "input") {
|
|
106
|
+
claspProjectId = await prompts.input({
|
|
107
|
+
message: "Input Apps Script project ID...",
|
|
108
|
+
required: false
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (packageManager === "" && clasp !== "create" && clasp !== "list" && skipInstall) {
|
|
112
|
+
packageManager = "npm";
|
|
113
|
+
}
|
|
114
|
+
packageManager ||= await prompts.select({
|
|
115
|
+
message: "Choice package manager what you want to use...",
|
|
116
|
+
choices: [
|
|
117
|
+
{ name: "npm", value: "npm" },
|
|
118
|
+
{ name: "pnpm", value: "pnpm" },
|
|
119
|
+
{ name: "yarn", value: "yarn" }
|
|
120
|
+
]
|
|
48
121
|
});
|
|
122
|
+
const packageManagers = ["npm", "pnpm", "yarn"];
|
|
123
|
+
if (!packageManagers.includes(packageManager)) {
|
|
124
|
+
throw Error("Invalid package manager");
|
|
125
|
+
}
|
|
49
126
|
} catch (e) {
|
|
50
127
|
e.message === "User force closed the prompt with SIGINT" && process.exit(0);
|
|
51
128
|
throw e;
|
|
52
129
|
}
|
|
53
|
-
await index.generateProject({
|
|
130
|
+
await index.generateProject({
|
|
131
|
+
projectName,
|
|
132
|
+
packageManager,
|
|
133
|
+
templateType,
|
|
134
|
+
clasp,
|
|
135
|
+
claspProjectId,
|
|
136
|
+
install: !skipInstall
|
|
137
|
+
});
|
|
54
138
|
});
|
|
55
139
|
program.parse(process.argv);
|
|
56
140
|
}
|
package/dist/cli.mjs
CHANGED
|
@@ -9,46 +9,130 @@ import 'consola';
|
|
|
9
9
|
import 'ejs';
|
|
10
10
|
import 'glob';
|
|
11
11
|
|
|
12
|
-
const version = "0.1
|
|
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
|
-
"--name [projectName]",
|
|
19
|
-
|
|
18
|
+
"-n, --name [projectName]",
|
|
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
|
-
"--pkg [packageManager]",
|
|
22
|
+
"-p, --pkg [packageManager]",
|
|
23
23
|
'Package manager what you want to use ("npm" | "pnpm" | "yarn")',
|
|
24
24
|
""
|
|
25
25
|
).option(
|
|
26
|
-
"--template [templateType]",
|
|
26
|
+
"-t, --template [templateType]",
|
|
27
27
|
'Project template label ("vanilla-ts" | "react-tsx")',
|
|
28
28
|
""
|
|
29
|
+
).option(
|
|
30
|
+
"-c, --clasp [claspSetupCommand]",
|
|
31
|
+
'Setup command how you want to use for Apps Script Project (create project | select project | input project id | skip)\n* If you use "create" or "select", you need to login to clasp first',
|
|
32
|
+
""
|
|
33
|
+
).option(
|
|
34
|
+
"--skipInstall",
|
|
35
|
+
"Skip install dependencies after generating the project",
|
|
36
|
+
false
|
|
29
37
|
).action(async (_param, command) => {
|
|
30
38
|
let {
|
|
31
39
|
name: projectName,
|
|
32
40
|
pkg: packageManager,
|
|
33
|
-
template: templateType
|
|
41
|
+
template: templateType,
|
|
42
|
+
clasp,
|
|
43
|
+
skipInstall
|
|
34
44
|
} = command.opts();
|
|
45
|
+
let claspProjectId;
|
|
35
46
|
try {
|
|
47
|
+
const validProjectNameRegex = /^(?!.*\.\.)[a-zA-Z0-9_-]+$/;
|
|
36
48
|
projectName ||= await input({
|
|
37
|
-
message: "Input project name what you want to generate..."
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
+
}
|
|
42
59
|
});
|
|
60
|
+
if (!validProjectNameRegex.test(projectName)) {
|
|
61
|
+
throw Error("Invalid project name");
|
|
62
|
+
}
|
|
43
63
|
templateType ||= await select({
|
|
44
|
-
message: "
|
|
45
|
-
choices: [
|
|
64
|
+
message: "Choice project template...",
|
|
65
|
+
choices: [
|
|
66
|
+
{ name: "vanilla-ts", value: "vanilla-ts" },
|
|
67
|
+
{ name: "react-tsx", value: "react-tsx" }
|
|
68
|
+
]
|
|
69
|
+
});
|
|
70
|
+
const templateTypes = ["vanilla-ts", "react-tsx"];
|
|
71
|
+
if (!templateTypes.includes(templateType)) {
|
|
72
|
+
throw Error("Invalid project template");
|
|
73
|
+
}
|
|
74
|
+
clasp ||= await select({
|
|
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',
|
|
76
|
+
choices: [
|
|
77
|
+
{
|
|
78
|
+
name: "[NEW] Create a new Apps Script project (need `npx @google/clasp login`)",
|
|
79
|
+
value: "create",
|
|
80
|
+
description: "Runs `npx @google/clasp create` to generate a new project."
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: "[SELECT] Use an existing Apps Script project (need `npx @google/clasp login`)",
|
|
84
|
+
value: "list",
|
|
85
|
+
description: "Runs `npx @google/clasp list` and lets you choose from your projects."
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: "[INPUT] Input Script ID manually",
|
|
89
|
+
value: "input",
|
|
90
|
+
description: "Manually provide an existing Script ID."
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "[NONE] Skip for now",
|
|
94
|
+
value: "skip",
|
|
95
|
+
description: "Create a `.clasp.json` file without Apps Script project ID."
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
});
|
|
99
|
+
const claspOptions = ["create", "list", "input", "skip"];
|
|
100
|
+
if (!claspOptions.includes(clasp)) {
|
|
101
|
+
throw Error("Invalid clasp option");
|
|
102
|
+
}
|
|
103
|
+
if (clasp === "input") {
|
|
104
|
+
claspProjectId = await input({
|
|
105
|
+
message: "Input Apps Script project ID...",
|
|
106
|
+
required: false
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
if (packageManager === "" && clasp !== "create" && clasp !== "list" && skipInstall) {
|
|
110
|
+
packageManager = "npm";
|
|
111
|
+
}
|
|
112
|
+
packageManager ||= await select({
|
|
113
|
+
message: "Choice package manager what you want to use...",
|
|
114
|
+
choices: [
|
|
115
|
+
{ name: "npm", value: "npm" },
|
|
116
|
+
{ name: "pnpm", value: "pnpm" },
|
|
117
|
+
{ name: "yarn", value: "yarn" }
|
|
118
|
+
]
|
|
46
119
|
});
|
|
120
|
+
const packageManagers = ["npm", "pnpm", "yarn"];
|
|
121
|
+
if (!packageManagers.includes(packageManager)) {
|
|
122
|
+
throw Error("Invalid package manager");
|
|
123
|
+
}
|
|
47
124
|
} catch (e) {
|
|
48
125
|
e.message === "User force closed the prompt with SIGINT" && process.exit(0);
|
|
49
126
|
throw e;
|
|
50
127
|
}
|
|
51
|
-
await generateProject({
|
|
128
|
+
await generateProject({
|
|
129
|
+
projectName,
|
|
130
|
+
packageManager,
|
|
131
|
+
templateType,
|
|
132
|
+
clasp,
|
|
133
|
+
claspProjectId,
|
|
134
|
+
install: !skipInstall
|
|
135
|
+
});
|
|
52
136
|
});
|
|
53
137
|
program.parse(process.argv);
|
|
54
138
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const node_child_process = require('node:child_process');
|
|
4
4
|
const fs = require('node:fs/promises');
|
|
5
5
|
const path = require('node:path');
|
|
6
|
+
const prompts = require('@inquirer/prompts');
|
|
6
7
|
const consola = require('consola');
|
|
7
8
|
const ejs = require('ejs');
|
|
8
9
|
const glob = require('glob');
|
|
@@ -13,18 +14,30 @@ const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
|
|
|
13
14
|
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
14
15
|
const ejs__default = /*#__PURE__*/_interopDefaultCompat(ejs);
|
|
15
16
|
|
|
16
|
-
async function runCommand(command, args, cwd) {
|
|
17
|
+
async function runCommand(command, args, cwd, capture = false) {
|
|
17
18
|
return new Promise((resolve, reject) => {
|
|
18
19
|
const child = node_child_process.spawn(command, args, {
|
|
19
20
|
cwd,
|
|
20
|
-
stdio: "inherit",
|
|
21
|
+
stdio: capture ? "pipe" : "inherit",
|
|
21
22
|
shell: true
|
|
22
23
|
});
|
|
24
|
+
let stdout = "";
|
|
25
|
+
let stderr = "";
|
|
26
|
+
if (capture) {
|
|
27
|
+
child.stdout?.on("data", (data) => {
|
|
28
|
+
stdout += data.toString();
|
|
29
|
+
});
|
|
30
|
+
child.stderr?.on("data", (data) => {
|
|
31
|
+
stderr += data.toString();
|
|
32
|
+
});
|
|
33
|
+
}
|
|
23
34
|
child.on("close", (code) => {
|
|
24
35
|
if (code === 0) {
|
|
25
|
-
resolve();
|
|
36
|
+
resolve(stdout.trim());
|
|
26
37
|
} else {
|
|
27
|
-
|
|
38
|
+
const errorMsg = `Command failed with exit code ${code}${stderr ? `:
|
|
39
|
+
${stderr}` : ""}`;
|
|
40
|
+
reject(new Error(errorMsg));
|
|
28
41
|
}
|
|
29
42
|
});
|
|
30
43
|
child.on("error", (err) => {
|
|
@@ -32,10 +45,132 @@ async function runCommand(command, args, cwd) {
|
|
|
32
45
|
});
|
|
33
46
|
});
|
|
34
47
|
}
|
|
48
|
+
async function handleClaspSetup(claspOption, projectName, outputDir, claspProjectId, packageManager = "npm") {
|
|
49
|
+
if (claspOption === "skip") {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const npxLikeCommand = packageManager === "npm" ? "npx" : packageManager === "pnpm" ? "pnpx" : "yarn";
|
|
53
|
+
consola.consola.start(
|
|
54
|
+
`Setting up .clasp.json with \`${npxLikeCommand} @google/clasp\`...`
|
|
55
|
+
);
|
|
56
|
+
if (claspOption === "create" || claspOption === "list") {
|
|
57
|
+
try {
|
|
58
|
+
await runCommand(npxLikeCommand, ["@google/clasp", "status"], outputDir);
|
|
59
|
+
} catch {
|
|
60
|
+
consola.consola.error(
|
|
61
|
+
`It seems you are not logged in to clasp. Please run \`${npxLikeCommand} @google/clasp login\` and try again.`
|
|
62
|
+
);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
let scriptId;
|
|
67
|
+
let existingClaspJson = null;
|
|
68
|
+
switch (claspOption) {
|
|
69
|
+
case "create":
|
|
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
|
+
}
|
|
78
|
+
const result = await runCommand(
|
|
79
|
+
npxLikeCommand,
|
|
80
|
+
[
|
|
81
|
+
"@google/clasp",
|
|
82
|
+
"create",
|
|
83
|
+
"--title",
|
|
84
|
+
`"${projectName}"`,
|
|
85
|
+
"--type",
|
|
86
|
+
"standalone"
|
|
87
|
+
],
|
|
88
|
+
outputDir,
|
|
89
|
+
true
|
|
90
|
+
);
|
|
91
|
+
const match = result.match(/Created new script: .+\/d\/(.+)\/edit/);
|
|
92
|
+
if (match?.[1]) {
|
|
93
|
+
scriptId = match[1];
|
|
94
|
+
consola.consola.info(`Created new Apps Script project with ID: ${scriptId}`);
|
|
95
|
+
} else {
|
|
96
|
+
throw new Error("Could not parse scriptId from clasp output.");
|
|
97
|
+
}
|
|
98
|
+
} catch (e) {
|
|
99
|
+
consola.consola.error("Failed to create new Apps Script project.", e);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
case "list":
|
|
104
|
+
try {
|
|
105
|
+
const listOutput = await runCommand(
|
|
106
|
+
npxLikeCommand,
|
|
107
|
+
["@google/clasp", "list"],
|
|
108
|
+
outputDir,
|
|
109
|
+
true
|
|
110
|
+
);
|
|
111
|
+
const projects = listOutput.split("\n").slice(1).map((line) => {
|
|
112
|
+
const parts = line.split(" - ");
|
|
113
|
+
if (parts.length >= 2) {
|
|
114
|
+
const name = parts[0]?.trim();
|
|
115
|
+
const url = parts[1]?.trim();
|
|
116
|
+
if (!name || !url) return null;
|
|
117
|
+
const match = url.match(/\/d\/(.+)\/edit/);
|
|
118
|
+
const scriptId2 = match?.[1];
|
|
119
|
+
if (scriptId2) {
|
|
120
|
+
return { name, value: scriptId2 };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
}).filter((p) => p !== null);
|
|
125
|
+
if (projects.length === 0) {
|
|
126
|
+
consola.consola.warn(
|
|
127
|
+
"No existing Apps Script projects found. Please create one first."
|
|
128
|
+
);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
scriptId = await prompts.select({
|
|
132
|
+
message: "Choose an existing Apps Script project:",
|
|
133
|
+
choices: projects
|
|
134
|
+
});
|
|
135
|
+
} catch (e) {
|
|
136
|
+
consola.consola.error("Failed to list Apps Script projects.", e);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
break;
|
|
140
|
+
case "input":
|
|
141
|
+
scriptId = claspProjectId;
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
if (scriptId) {
|
|
145
|
+
const claspJsonPath = path__default.join(outputDir, ".clasp.json");
|
|
146
|
+
let claspJson = {
|
|
147
|
+
scriptId
|
|
148
|
+
};
|
|
149
|
+
let successMessage = `.clasp.json created successfully with scriptId: ${scriptId}`;
|
|
150
|
+
if (existingClaspJson) {
|
|
151
|
+
claspJson = { ...existingClaspJson, scriptId };
|
|
152
|
+
successMessage = `.clasp.json updated successfully with scriptId: ${scriptId}`;
|
|
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
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const claspJsonContent = JSON.stringify(claspJson, null, 2);
|
|
163
|
+
await fs__default.writeFile(claspJsonPath, claspJsonContent, { encoding: "utf-8" });
|
|
164
|
+
consola.consola.success(successMessage);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
35
167
|
async function generateProject({
|
|
36
168
|
projectName,
|
|
37
169
|
packageManager,
|
|
38
|
-
templateType
|
|
170
|
+
templateType,
|
|
171
|
+
clasp,
|
|
172
|
+
claspProjectId,
|
|
173
|
+
install
|
|
39
174
|
}) {
|
|
40
175
|
const outputDir = path__default.resolve(process.cwd(), projectName);
|
|
41
176
|
const templateBaseDir = path__default.resolve(__dirname, "..", "dist", "templates");
|
|
@@ -44,11 +179,28 @@ async function generateProject({
|
|
|
44
179
|
consola.consola.start(
|
|
45
180
|
`Creating a new Project for GoogleAppsScript in ${outputDir}...`
|
|
46
181
|
);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
+
}
|
|
52
204
|
}
|
|
53
205
|
await fs__default.mkdir(outputDir, { recursive: true });
|
|
54
206
|
consola.consola.info(`Generating project files from template '${templateType}'...`);
|
|
@@ -58,30 +210,36 @@ async function generateProject({
|
|
|
58
210
|
const files = await glob.glob("./**/*", {
|
|
59
211
|
cwd: dir,
|
|
60
212
|
nodir: true,
|
|
61
|
-
dot: true
|
|
62
|
-
dotRelative: true,
|
|
63
|
-
follow: true,
|
|
64
|
-
windowsPathsNoEscape: true
|
|
213
|
+
dot: true
|
|
65
214
|
});
|
|
66
215
|
for (const file of files) {
|
|
67
|
-
const
|
|
68
|
-
const
|
|
216
|
+
const relativePath = path__default.relative(dir, path__default.resolve(dir, file));
|
|
217
|
+
const templatePath = path__default.join(dir, relativePath);
|
|
218
|
+
const outputPath = path__default.join(outputDir, relativePath.replace(".ejs", ""));
|
|
69
219
|
await fs__default.mkdir(path__default.dirname(outputPath), { recursive: true });
|
|
70
220
|
const templateContent = await fs__default.readFile(templatePath, {
|
|
71
221
|
encoding: "utf-8"
|
|
72
222
|
});
|
|
73
223
|
const renderedContent = ejs__default.render(templateContent, ejsData);
|
|
74
|
-
await fs__default.writeFile(outputPath, renderedContent);
|
|
224
|
+
await fs__default.writeFile(outputPath, renderedContent, { encoding: "utf-8" });
|
|
75
225
|
}
|
|
76
226
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
227
|
+
await handleClaspSetup(
|
|
228
|
+
clasp,
|
|
229
|
+
projectName,
|
|
230
|
+
outputDir,
|
|
231
|
+
claspProjectId,
|
|
232
|
+
packageManager
|
|
233
|
+
);
|
|
234
|
+
if (install) {
|
|
235
|
+
consola.consola.start(`Installing dependencies with ${packageManager}...`);
|
|
236
|
+
try {
|
|
237
|
+
await runCommand(packageManager, ["install"], outputDir);
|
|
238
|
+
consola.consola.success(`Dependencies installed successfully.`);
|
|
239
|
+
} catch (e) {
|
|
240
|
+
consola.consola.fail("Failed to install dependencies. Please do it manually.");
|
|
241
|
+
consola.consola.error(e);
|
|
242
|
+
}
|
|
85
243
|
}
|
|
86
244
|
consola.consola.start(`Initializing Git repository...`);
|
|
87
245
|
try {
|
|
@@ -93,15 +251,28 @@ async function generateProject({
|
|
|
93
251
|
outputDir
|
|
94
252
|
);
|
|
95
253
|
consola.consola.success(`Git repository initialized successfully.`);
|
|
96
|
-
} catch {
|
|
254
|
+
} catch (e) {
|
|
97
255
|
consola.consola.fail("Failed to initialize Git repository. Please do it manually.");
|
|
256
|
+
consola.consola.error(e);
|
|
98
257
|
}
|
|
99
258
|
consola.consola.success(`Project '${projectName}' created successfully!`);
|
|
100
|
-
|
|
259
|
+
const messages = [];
|
|
260
|
+
projectName !== "." && messages.push(` cd ${projectName}`);
|
|
261
|
+
!install && messages.push(` ${packageManager} install`);
|
|
262
|
+
templateType !== "vanilla-ts" && messages.push(` ${packageManager} dev`);
|
|
263
|
+
if (messages.length > 0) {
|
|
264
|
+
consola.consola.log(`
|
|
101
265
|
To get started, run:
|
|
102
266
|
`);
|
|
103
|
-
|
|
104
|
-
|
|
267
|
+
for (const message of messages) {
|
|
268
|
+
consola.consola.log(message);
|
|
269
|
+
}
|
|
270
|
+
consola.consola.log("");
|
|
271
|
+
consola.consola.log(`...and write your GAS code!`);
|
|
272
|
+
} else {
|
|
273
|
+
consola.consola.log(`
|
|
274
|
+
To get started, write your GAS code in \`src/\`!`);
|
|
275
|
+
}
|
|
105
276
|
}
|
|
106
277
|
|
|
107
278
|
exports.generateProject = generateProject;
|