@ez-gform/cli 0.1.0
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/LICENSE +21 -0
- package/README.md +42 -0
- package/dist/cli.js +251 -0
- package/dist/cli.js.map +1 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 webadeva
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# @ez-gform/cli
|
|
2
|
+
|
|
3
|
+
Point it at a public Google Form; get the form's `entry.N` ids, or ready-made
|
|
4
|
+
code.
|
|
5
|
+
|
|
6
|
+
```sh
|
|
7
|
+
npx @ez-gform/cli <form-url-or-id>
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
That prints the form's schema as JSON: every question, its type, and its
|
|
11
|
+
entry id.
|
|
12
|
+
|
|
13
|
+
## Generate code
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npx @ez-gform/cli <form-url-or-id> --format react --out ContactForm.tsx
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
| Flag | What it does |
|
|
20
|
+
| --------------------- | ------------------------------------------------------------- |
|
|
21
|
+
| `--format` | `json` (default), `types`, `react` or `html`. |
|
|
22
|
+
| `--name MyForm` | Name for the generated types / component. |
|
|
23
|
+
| `--out <file>` | Write to a file instead of printing. |
|
|
24
|
+
| `--json-input <file>` | Read a saved form page (HTML or JSON) instead of fetching it. |
|
|
25
|
+
|
|
26
|
+
## Test a submission
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
npx @ez-gform/cli submit <form-url-or-id> --data '{"entry.123":"hi"}'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Checks the data against the form, then submits it. Unlike a browser, the CLI
|
|
33
|
+
can read Google's response, so this tells you whether the submission really
|
|
34
|
+
worked. `--data @file.json` reads from a file.
|
|
35
|
+
|
|
36
|
+
## Good to know
|
|
37
|
+
|
|
38
|
+
- The form must be public. If it needs sign-in, the CLI tells you which Google
|
|
39
|
+
Forms setting to turn off.
|
|
40
|
+
- Exit codes: `0` success, `1` bad usage, `2` fetch, parse or validation
|
|
41
|
+
error.
|
|
42
|
+
- Use it often? `pnpm add -D @ez-gform/cli`.
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import {
|
|
5
|
+
generateHtmlForm,
|
|
6
|
+
generateReactComponent,
|
|
7
|
+
generateSchemaJson,
|
|
8
|
+
generateTypes
|
|
9
|
+
} from "@ez-gform/codegen";
|
|
10
|
+
import {
|
|
11
|
+
formUrls,
|
|
12
|
+
normalizeFormId,
|
|
13
|
+
parseFormData,
|
|
14
|
+
parseFormHtml,
|
|
15
|
+
submitForm,
|
|
16
|
+
validateValues
|
|
17
|
+
} from "@ez-gform/core";
|
|
18
|
+
import { readFile, writeFile } from "fs/promises";
|
|
19
|
+
import { fileURLToPath } from "url";
|
|
20
|
+
import { parseArgs } from "util";
|
|
21
|
+
var USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
|
22
|
+
var SIGN_IN_ERROR = "This form requires sign-in; ez-gform only works with forms that are public (Settings \u2192 Responses \u2192 'Restrict to users in <org>' off)";
|
|
23
|
+
var USAGE = `Usage:
|
|
24
|
+
ez-gform <form-url-or-id> [--format json|types|react|html] [--name MyForm] [--out <file>] [--json-input <file>]
|
|
25
|
+
ez-gform submit <form-url-or-id> --data '<json>' | --data @<file> [--json-input <file>]
|
|
26
|
+
ez-gform --help
|
|
27
|
+
ez-gform --version
|
|
28
|
+
|
|
29
|
+
Options:
|
|
30
|
+
--format <json|types|react|html> Output format. Defaults to "json".
|
|
31
|
+
--name <Name> Base name used for generated types/component (types/react formats).
|
|
32
|
+
--out <file> Write output to a file instead of stdout.
|
|
33
|
+
--json-input <file> Use a saved FB_PUBLIC_LOAD_DATA_ JSON or viewform HTML file instead of fetching.
|
|
34
|
+
--data <json|@file> (submit) Values to submit, as inline JSON or "@path/to/file.json".
|
|
35
|
+
--help Show this help.
|
|
36
|
+
--version Show the CLI version.
|
|
37
|
+
`;
|
|
38
|
+
var UsageError = class extends Error {
|
|
39
|
+
};
|
|
40
|
+
var FetchOrParseError = class extends Error {
|
|
41
|
+
};
|
|
42
|
+
var readOwnVersion = async () => {
|
|
43
|
+
const pkgUrl = new URL("../package.json", import.meta.url);
|
|
44
|
+
const raw = await readFile(fileURLToPath(pkgUrl), "utf8");
|
|
45
|
+
const pkg = JSON.parse(raw);
|
|
46
|
+
return pkg.version ?? "0.0.0";
|
|
47
|
+
};
|
|
48
|
+
var readDataOption = async (data) => {
|
|
49
|
+
const raw = data.startsWith("@") ? await readFile(data.slice(1), "utf8") : data;
|
|
50
|
+
return JSON.parse(raw);
|
|
51
|
+
};
|
|
52
|
+
var loadSchemaFromFile = async (path) => {
|
|
53
|
+
const raw = await readFile(path, "utf8");
|
|
54
|
+
const trimmed = raw.trim();
|
|
55
|
+
if (trimmed.startsWith("[")) {
|
|
56
|
+
return parseFormData(JSON.parse(trimmed));
|
|
57
|
+
}
|
|
58
|
+
return parseFormHtml(raw);
|
|
59
|
+
};
|
|
60
|
+
var fetchSchema = async (formIdOrUrl) => {
|
|
61
|
+
const formId = normalizeFormId(formIdOrUrl);
|
|
62
|
+
const { viewform } = formUrls(formId);
|
|
63
|
+
let response;
|
|
64
|
+
try {
|
|
65
|
+
response = await fetch(viewform, {
|
|
66
|
+
headers: { "User-Agent": USER_AGENT }
|
|
67
|
+
});
|
|
68
|
+
} catch (cause) {
|
|
69
|
+
throw new FetchOrParseError(
|
|
70
|
+
`Failed to fetch "${viewform}": ${cause instanceof Error ? cause.message : String(cause)}`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
if (response.status === 401 || response.url.includes("accounts.google.com")) {
|
|
74
|
+
throw new FetchOrParseError(SIGN_IN_ERROR);
|
|
75
|
+
}
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
throw new FetchOrParseError(
|
|
78
|
+
`Failed to fetch "${viewform}": HTTP ${response.status}`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
const html = await response.text();
|
|
82
|
+
try {
|
|
83
|
+
return parseFormHtml(html);
|
|
84
|
+
} catch (cause) {
|
|
85
|
+
throw new FetchOrParseError(
|
|
86
|
+
`Failed to parse form HTML: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
var renderFormat = (format, schema, name) => {
|
|
91
|
+
switch (format) {
|
|
92
|
+
case "json":
|
|
93
|
+
return generateSchemaJson(schema, { pretty: true });
|
|
94
|
+
case "types":
|
|
95
|
+
return generateTypes(schema, { name });
|
|
96
|
+
case "react":
|
|
97
|
+
return generateReactComponent(schema, { name });
|
|
98
|
+
case "html":
|
|
99
|
+
return generateHtmlForm(schema);
|
|
100
|
+
default:
|
|
101
|
+
throw new UsageError(
|
|
102
|
+
`Unknown --format "${format}" (expected one of: json, types, react, html)`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var runGenerate = async (argv) => {
|
|
107
|
+
const { values, positionals } = parseArgs({
|
|
108
|
+
args: argv,
|
|
109
|
+
allowPositionals: true,
|
|
110
|
+
options: {
|
|
111
|
+
format: { type: "string", default: "json" },
|
|
112
|
+
name: { type: "string" },
|
|
113
|
+
out: { type: "string" },
|
|
114
|
+
"json-input": { type: "string" },
|
|
115
|
+
help: { type: "boolean", default: false },
|
|
116
|
+
version: { type: "boolean", default: false }
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
if (values.help) {
|
|
120
|
+
process.stdout.write(USAGE);
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
if (values.version) {
|
|
124
|
+
process.stdout.write(`${await readOwnVersion()}
|
|
125
|
+
`);
|
|
126
|
+
return 0;
|
|
127
|
+
}
|
|
128
|
+
const [formArg] = positionals;
|
|
129
|
+
if (!formArg) {
|
|
130
|
+
process.stderr.write(`Missing <form-url-or-id>.
|
|
131
|
+
|
|
132
|
+
${USAGE}`);
|
|
133
|
+
return 1;
|
|
134
|
+
}
|
|
135
|
+
let schema;
|
|
136
|
+
try {
|
|
137
|
+
schema = values["json-input"] ? await loadSchemaFromFile(values["json-input"]) : await fetchSchema(formArg);
|
|
138
|
+
} catch (error) {
|
|
139
|
+
if (error instanceof FetchOrParseError) {
|
|
140
|
+
process.stderr.write(`${error.message}
|
|
141
|
+
`);
|
|
142
|
+
return 2;
|
|
143
|
+
}
|
|
144
|
+
process.stderr.write(
|
|
145
|
+
`${error instanceof Error ? error.message : String(error)}
|
|
146
|
+
`
|
|
147
|
+
);
|
|
148
|
+
return 2;
|
|
149
|
+
}
|
|
150
|
+
let output;
|
|
151
|
+
try {
|
|
152
|
+
output = renderFormat(values.format, schema, values.name);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if (error instanceof UsageError) {
|
|
155
|
+
process.stderr.write(`${error.message}
|
|
156
|
+
|
|
157
|
+
${USAGE}`);
|
|
158
|
+
return 1;
|
|
159
|
+
}
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
if (values.out) {
|
|
163
|
+
await writeFile(values.out, output, "utf8");
|
|
164
|
+
} else {
|
|
165
|
+
process.stdout.write(output.endsWith("\n") ? output : `${output}
|
|
166
|
+
`);
|
|
167
|
+
}
|
|
168
|
+
return 0;
|
|
169
|
+
};
|
|
170
|
+
var runSubmit = async (argv) => {
|
|
171
|
+
const { values, positionals } = parseArgs({
|
|
172
|
+
args: argv,
|
|
173
|
+
allowPositionals: true,
|
|
174
|
+
options: {
|
|
175
|
+
data: { type: "string" },
|
|
176
|
+
"json-input": { type: "string" },
|
|
177
|
+
help: { type: "boolean", default: false }
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
if (values.help) {
|
|
181
|
+
process.stdout.write(USAGE);
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
const [formArg] = positionals;
|
|
185
|
+
if (!formArg || !values.data) {
|
|
186
|
+
process.stderr.write(
|
|
187
|
+
`Usage: ez-gform submit <form-url-or-id> --data '<json>' | --data @<file>
|
|
188
|
+
`
|
|
189
|
+
);
|
|
190
|
+
return 1;
|
|
191
|
+
}
|
|
192
|
+
let schema;
|
|
193
|
+
try {
|
|
194
|
+
schema = values["json-input"] ? await loadSchemaFromFile(values["json-input"]) : await fetchSchema(formArg);
|
|
195
|
+
} catch (error) {
|
|
196
|
+
if (error instanceof FetchOrParseError) {
|
|
197
|
+
process.stderr.write(`${error.message}
|
|
198
|
+
`);
|
|
199
|
+
return 2;
|
|
200
|
+
}
|
|
201
|
+
throw error;
|
|
202
|
+
}
|
|
203
|
+
let data;
|
|
204
|
+
try {
|
|
205
|
+
data = await readDataOption(values.data);
|
|
206
|
+
} catch (error) {
|
|
207
|
+
process.stderr.write(
|
|
208
|
+
`Failed to read --data: ${error instanceof Error ? error.message : String(error)}
|
|
209
|
+
`
|
|
210
|
+
);
|
|
211
|
+
return 1;
|
|
212
|
+
}
|
|
213
|
+
const validation = validateValues(data, schema);
|
|
214
|
+
if (!validation.ok) {
|
|
215
|
+
process.stderr.write(
|
|
216
|
+
`Validation failed:
|
|
217
|
+
${validation.errors.map((e) => {
|
|
218
|
+
return ` - ${e.entryId}: ${e.message}`;
|
|
219
|
+
}).join("\n")}
|
|
220
|
+
`
|
|
221
|
+
);
|
|
222
|
+
return 2;
|
|
223
|
+
}
|
|
224
|
+
const formId = normalizeFormId(formArg);
|
|
225
|
+
const result = await submitForm(formId, data, { schema, mode: "cors" });
|
|
226
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
227
|
+
`);
|
|
228
|
+
return result.status === "error" ? 2 : 0;
|
|
229
|
+
};
|
|
230
|
+
var main = async () => {
|
|
231
|
+
const argv = process.argv.slice(2);
|
|
232
|
+
if (argv[0] === "--help" || argv[0] === "-h") {
|
|
233
|
+
process.stdout.write(USAGE);
|
|
234
|
+
process.exit(0);
|
|
235
|
+
}
|
|
236
|
+
if (argv[0] === "--version" || argv[0] === "-v") {
|
|
237
|
+
process.stdout.write(`${await readOwnVersion()}
|
|
238
|
+
`);
|
|
239
|
+
process.exit(0);
|
|
240
|
+
}
|
|
241
|
+
const exitCode = argv[0] === "submit" ? await runSubmit(argv.slice(1)) : await runGenerate(argv);
|
|
242
|
+
process.exit(exitCode);
|
|
243
|
+
};
|
|
244
|
+
main().catch((error) => {
|
|
245
|
+
process.stderr.write(
|
|
246
|
+
`${error instanceof Error ? error.stack ?? error.message : String(error)}
|
|
247
|
+
`
|
|
248
|
+
);
|
|
249
|
+
process.exit(2);
|
|
250
|
+
});
|
|
251
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import {\n generateHtmlForm,\n generateReactComponent,\n generateSchemaJson,\n generateTypes,\n} from \"@ez-gform/codegen\";\nimport {\n formUrls,\n normalizeFormId,\n parseFormData,\n parseFormHtml,\n submitForm,\n validateValues,\n} from \"@ez-gform/core\";\nimport type { FormSchema, FormValues } from \"@ez-gform/types\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport { parseArgs } from \"node:util\";\n\nconst USER_AGENT =\n \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36\";\n\nconst SIGN_IN_ERROR =\n \"This form requires sign-in; ez-gform only works with forms that are public (Settings → Responses → 'Restrict to users in <org>' off)\";\n\nconst USAGE = `Usage:\n ez-gform <form-url-or-id> [--format json|types|react|html] [--name MyForm] [--out <file>] [--json-input <file>]\n ez-gform submit <form-url-or-id> --data '<json>' | --data @<file> [--json-input <file>]\n ez-gform --help\n ez-gform --version\n\nOptions:\n --format <json|types|react|html> Output format. Defaults to \"json\".\n --name <Name> Base name used for generated types/component (types/react formats).\n --out <file> Write output to a file instead of stdout.\n --json-input <file> Use a saved FB_PUBLIC_LOAD_DATA_ JSON or viewform HTML file instead of fetching.\n --data <json|@file> (submit) Values to submit, as inline JSON or \"@path/to/file.json\".\n --help Show this help.\n --version Show the CLI version.\n`;\n\nclass UsageError extends Error {}\nclass FetchOrParseError extends Error {}\n\nconst readOwnVersion = async (): Promise<string> => {\n const pkgUrl = new URL(\"../package.json\", import.meta.url);\n const raw = await readFile(fileURLToPath(pkgUrl), \"utf8\");\n const pkg = JSON.parse(raw) as { version?: string };\n return pkg.version ?? \"0.0.0\";\n};\n\nconst readDataOption = async (data: string): Promise<FormValues> => {\n const raw = data.startsWith(\"@\")\n ? await readFile(data.slice(1), \"utf8\")\n : data;\n return JSON.parse(raw) as FormValues;\n};\n\n/** Loads a schema from `--json-input` (FB_PUBLIC_LOAD_DATA_ JSON array, or full viewform HTML). */\nconst loadSchemaFromFile = async (path: string): Promise<FormSchema> => {\n const raw = await readFile(path, \"utf8\");\n const trimmed = raw.trim();\n if (trimmed.startsWith(\"[\")) {\n return parseFormData(JSON.parse(trimmed));\n }\n return parseFormHtml(raw);\n};\n\n/** Fetches a public form's `/viewform` HTML and parses it into a `FormSchema`. */\nconst fetchSchema = async (formIdOrUrl: string): Promise<FormSchema> => {\n const formId = normalizeFormId(formIdOrUrl);\n const { viewform } = formUrls(formId);\n\n let response: Response;\n try {\n response = await fetch(viewform, {\n headers: { \"User-Agent\": USER_AGENT },\n });\n } catch (cause) {\n throw new FetchOrParseError(\n `Failed to fetch \"${viewform}\": ${cause instanceof Error ? cause.message : String(cause)}`,\n );\n }\n\n if (response.status === 401 || response.url.includes(\"accounts.google.com\")) {\n throw new FetchOrParseError(SIGN_IN_ERROR);\n }\n\n if (!response.ok) {\n throw new FetchOrParseError(\n `Failed to fetch \"${viewform}\": HTTP ${response.status}`,\n );\n }\n\n const html = await response.text();\n try {\n return parseFormHtml(html);\n } catch (cause) {\n throw new FetchOrParseError(\n `Failed to parse form HTML: ${cause instanceof Error ? cause.message : String(cause)}`,\n );\n }\n};\n\nconst renderFormat = (\n format: string,\n schema: FormSchema,\n name: string | undefined,\n): string => {\n switch (format) {\n case \"json\":\n return generateSchemaJson(schema, { pretty: true });\n case \"types\":\n return generateTypes(schema, { name });\n case \"react\":\n return generateReactComponent(schema, { name });\n case \"html\":\n return generateHtmlForm(schema);\n default:\n throw new UsageError(\n `Unknown --format \"${format}\" (expected one of: json, types, react, html)`,\n );\n }\n};\n\nconst runGenerate = async (argv: string[]): Promise<number> => {\n const { values, positionals } = parseArgs({\n args: argv,\n allowPositionals: true,\n options: {\n format: { type: \"string\", default: \"json\" },\n name: { type: \"string\" },\n out: { type: \"string\" },\n \"json-input\": { type: \"string\" },\n help: { type: \"boolean\", default: false },\n version: { type: \"boolean\", default: false },\n },\n });\n\n if (values.help) {\n process.stdout.write(USAGE);\n return 0;\n }\n if (values.version) {\n process.stdout.write(`${await readOwnVersion()}\\n`);\n return 0;\n }\n\n const [formArg] = positionals;\n if (!formArg) {\n process.stderr.write(`Missing <form-url-or-id>.\\n\\n${USAGE}`);\n return 1;\n }\n\n let schema: FormSchema;\n try {\n schema = values[\"json-input\"]\n ? await loadSchemaFromFile(values[\"json-input\"])\n : await fetchSchema(formArg);\n } catch (error) {\n if (error instanceof FetchOrParseError) {\n process.stderr.write(`${error.message}\\n`);\n return 2;\n }\n process.stderr.write(\n `${error instanceof Error ? error.message : String(error)}\\n`,\n );\n return 2;\n }\n\n let output: string;\n try {\n output = renderFormat(values.format, schema, values.name);\n } catch (error) {\n if (error instanceof UsageError) {\n process.stderr.write(`${error.message}\\n\\n${USAGE}`);\n return 1;\n }\n throw error;\n }\n\n if (values.out) {\n await writeFile(values.out, output, \"utf8\");\n } else {\n process.stdout.write(output.endsWith(\"\\n\") ? output : `${output}\\n`);\n }\n return 0;\n};\n\nconst runSubmit = async (argv: string[]): Promise<number> => {\n const { values, positionals } = parseArgs({\n args: argv,\n allowPositionals: true,\n options: {\n data: { type: \"string\" },\n \"json-input\": { type: \"string\" },\n help: { type: \"boolean\", default: false },\n },\n });\n\n if (values.help) {\n process.stdout.write(USAGE);\n return 0;\n }\n\n const [formArg] = positionals;\n if (!formArg || !values.data) {\n process.stderr.write(\n `Usage: ez-gform submit <form-url-or-id> --data '<json>' | --data @<file>\\n`,\n );\n return 1;\n }\n\n let schema: FormSchema;\n try {\n schema = values[\"json-input\"]\n ? await loadSchemaFromFile(values[\"json-input\"])\n : await fetchSchema(formArg);\n } catch (error) {\n if (error instanceof FetchOrParseError) {\n process.stderr.write(`${error.message}\\n`);\n return 2;\n }\n throw error;\n }\n\n let data: FormValues;\n try {\n data = await readDataOption(values.data);\n } catch (error) {\n process.stderr.write(\n `Failed to read --data: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n return 1;\n }\n\n const validation = validateValues(data, schema);\n if (!validation.ok) {\n process.stderr.write(\n `Validation failed:\\n${validation.errors\n .map((e) => {\n return ` - ${e.entryId}: ${e.message}`;\n })\n .join(\"\\n\")}\\n`,\n );\n return 2;\n }\n\n const formId = normalizeFormId(formArg);\n const result = await submitForm(formId, data, { schema, mode: \"cors\" });\n process.stdout.write(`${JSON.stringify(result, null, 2)}\\n`);\n return result.status === \"error\" ? 2 : 0;\n};\n\nconst main = async (): Promise<void> => {\n const argv = process.argv.slice(2);\n\n if (argv[0] === \"--help\" || argv[0] === \"-h\") {\n process.stdout.write(USAGE);\n process.exit(0);\n }\n if (argv[0] === \"--version\" || argv[0] === \"-v\") {\n process.stdout.write(`${await readOwnVersion()}\\n`);\n process.exit(0);\n }\n\n const exitCode =\n argv[0] === \"submit\"\n ? await runSubmit(argv.slice(1))\n : await runGenerate(argv);\n process.exit(exitCode);\n};\n\nmain().catch((error: unknown) => {\n process.stderr.write(\n `${error instanceof Error ? (error.stack ?? error.message) : String(error)}\\n`,\n );\n process.exit(2);\n});\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ez-gform/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "npx tool: fetch a public Google Form and emit JSON schema, TS types, a React component, or a plain HTML form.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://github.com/theGobindSingh/ez-gform#readme",
|
|
8
|
+
"bugs": "https://github.com/theGobindSingh/ez-gform/issues",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/theGobindSingh/ez-gform.git",
|
|
12
|
+
"directory": "packages/cli"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"google-forms",
|
|
16
|
+
"ez-gform",
|
|
17
|
+
"cli",
|
|
18
|
+
"codegen"
|
|
19
|
+
],
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"bin": {
|
|
25
|
+
"ez-gform": "./dist/cli.js"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@ez-gform/codegen": "0.1.0",
|
|
32
|
+
"@ez-gform/core": "0.1.0",
|
|
33
|
+
"@ez-gform/types": "0.1.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@ez-gform/tsconfig": "0.1.0",
|
|
37
|
+
"@kami-ui/eslint-config": "0.0.6",
|
|
38
|
+
"@types/node": "^22.10.0",
|
|
39
|
+
"@vitest/coverage-v8": "5.0.1",
|
|
40
|
+
"eslint": "10.10.0",
|
|
41
|
+
"tsup": "8.5.1",
|
|
42
|
+
"typescript": "5.9.3",
|
|
43
|
+
"vitest": "5.0.1"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=20"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsup",
|
|
50
|
+
"dev": "tsup --watch",
|
|
51
|
+
"test": "vitest run",
|
|
52
|
+
"lint": "eslint .",
|
|
53
|
+
"lint:fix": "eslint . --fix",
|
|
54
|
+
"type-check": "tsc --noEmit",
|
|
55
|
+
"clean": "rm -rf dist"
|
|
56
|
+
}
|
|
57
|
+
}
|