@ciderjs/gasnuki 0.1.5 → 0.2.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/dist/cli.cjs CHANGED
@@ -1,19 +1,54 @@
1
1
  #! /usr/bin/env node
2
2
  'use strict';
3
3
 
4
+ const path = require('node:path');
4
5
  const commander = require('commander');
5
- const index = require('./index.cjs');
6
- require('node:path');
6
+ const index = require('./shared/gasnuki.Yj84yCWz.cjs');
7
7
  require('chokidar');
8
8
  require('consola');
9
9
  require('node:fs');
10
10
  require('ts-morph');
11
+ require('jiti');
11
12
 
12
- const version = "0.1.5";
13
+ function _interopNamespaceCompat(e) {
14
+ if (e && typeof e === 'object' && 'default' in e) return e;
15
+ const n = Object.create(null);
16
+ if (e) {
17
+ for (const k in e) {
18
+ n[k] = e[k];
19
+ }
20
+ }
21
+ n.default = e;
22
+ return n;
23
+ }
24
+
25
+ const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
26
+
27
+ const version = "0.2.0";
13
28
 
14
29
  const parseArgs = async (command) => {
15
- const { project, srcDir, outDir, outputFile, watch } = command.opts();
16
- await index.generateTypes({ project, srcDir, outDir, outputFile, watch });
30
+ const cliOpts = command.opts();
31
+ const fileConfig = await index.loadConfig(path__namespace.resolve(cliOpts.project));
32
+ const defaultOpts = {};
33
+ for (const option of command.options) {
34
+ const key = option.attributeName();
35
+ defaultOpts[key] = option.defaultValue;
36
+ }
37
+ const explicitCliOpts = {};
38
+ for (const option of command.options) {
39
+ const key = option.attributeName();
40
+ if (command.getOptionValueSource(key) === "cli") {
41
+ explicitCliOpts[key] = cliOpts[key];
42
+ }
43
+ }
44
+ const finalOptions = {
45
+ ...defaultOpts,
46
+ ...fileConfig,
47
+ ...explicitCliOpts,
48
+ project: cliOpts.project,
49
+ watch: cliOpts.watch
50
+ };
51
+ await index.generateTypes(finalOptions);
17
52
  };
18
53
  const cli = async () => {
19
54
  const program = new commander.Command();
package/dist/cli.mjs CHANGED
@@ -1,17 +1,38 @@
1
1
  #! /usr/bin/env node
2
+ import * as path from 'node:path';
2
3
  import { Command } from 'commander';
3
- import { generateTypes } from './index.mjs';
4
- import 'node:path';
4
+ import { l as loadConfig, g as generateTypes } from './shared/gasnuki.C-MvXA42.mjs';
5
5
  import 'chokidar';
6
6
  import 'consola';
7
7
  import 'node:fs';
8
8
  import 'ts-morph';
9
+ import 'jiti';
9
10
 
10
- const version = "0.1.5";
11
+ const version = "0.2.0";
11
12
 
12
13
  const parseArgs = async (command) => {
13
- const { project, srcDir, outDir, outputFile, watch } = command.opts();
14
- await generateTypes({ project, srcDir, outDir, outputFile, watch });
14
+ const cliOpts = command.opts();
15
+ const fileConfig = await loadConfig(path.resolve(cliOpts.project));
16
+ const defaultOpts = {};
17
+ for (const option of command.options) {
18
+ const key = option.attributeName();
19
+ defaultOpts[key] = option.defaultValue;
20
+ }
21
+ const explicitCliOpts = {};
22
+ for (const option of command.options) {
23
+ const key = option.attributeName();
24
+ if (command.getOptionValueSource(key) === "cli") {
25
+ explicitCliOpts[key] = cliOpts[key];
26
+ }
27
+ }
28
+ const finalOptions = {
29
+ ...defaultOpts,
30
+ ...fileConfig,
31
+ ...explicitCliOpts,
32
+ project: cliOpts.project,
33
+ watch: cliOpts.watch
34
+ };
35
+ await generateTypes(finalOptions);
15
36
  };
16
37
  const cli = async () => {
17
38
  const program = new Command();
package/dist/index.cjs CHANGED
@@ -1,225 +1,14 @@
1
1
  'use strict';
2
2
 
3
- const path = require('node:path');
4
- const chokidar = require('chokidar');
5
- const consola = require('consola');
6
- const fs = require('node:fs');
7
- const tsMorph = require('ts-morph');
3
+ require('node:path');
4
+ require('chokidar');
5
+ require('consola');
6
+ const index = require('./shared/gasnuki.Yj84yCWz.cjs');
7
+ require('node:fs');
8
+ require('ts-morph');
9
+ require('jiti');
8
10
 
9
- function _interopNamespaceCompat(e) {
10
- if (e && typeof e === 'object' && 'default' in e) return e;
11
- const n = Object.create(null);
12
- if (e) {
13
- for (const k in e) {
14
- n[k] = e[k];
15
- }
16
- }
17
- n.default = e;
18
- return n;
19
- }
20
11
 
21
- const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
22
- const chokidar__namespace = /*#__PURE__*/_interopNamespaceCompat(chokidar);
23
- const fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
24
12
 
25
- const text = "type RemoveReturnType<T> = {\n [P in keyof T]: T[P] extends (...args: infer A) => any\n ? (...args: A) => void\n : T[P];\n};\n\ntype _AppsScriptRun = RemoveReturnType<ServerScripts> & {\n [key: string]: (...args: any[]) => any;\n withSuccessHandler: <T = string | number | boolean | undefined, U = any>(\n callback: (returnValues: T, userObject?: U) => void,\n ) => _AppsScriptRun;\n withFailureHandler: <U = any>(\n callback: (error: Error, userObject?: U) => void,\n ) => _AppsScriptRun;\n withUserObject: <U = any>(userObject: U) => _AppsScriptRun;\n};\n\ntype _AppsScriptHistoryFunction = (\n stateObject: object,\n params: object,\n hash: string,\n) => void;\n\ninterface _WebAppLovacationType {\n hash: string;\n parameter: Record<string, string>;\n parameters: Record<string, string[]>;\n}\n\nexport declare interface GoogleClientSideApi {\n script: {\n run: _AppsScriptRun;\n url: {\n getLocation: (\n callback: (location: _WebAppLovacationType) => void,\n ) => void;\n };\n history: {\n push: _AppsScriptHistoryFunction;\n replace: _AppsScriptHistoryFunction;\n setChangeHandler: (\n callback: (e: {\n state: object;\n location: _WebAppLovacationType;\n }) => void,\n ) => void;\n };\n };\n}\n\ndeclare global {\n const google: GoogleClientSideApi;\n}\n";
26
-
27
- const getInterfaceMethodDefinition_ = (name, node) => {
28
- const typeParameters = node.getTypeParameters?.() ?? [];
29
- const typeParamsString = typeParameters.length > 0 ? `<${typeParameters.map((tp) => tp.getText()).join(", ")}>` : "";
30
- const parameters = node.getParameters().map((param) => {
31
- const paramName = param.getName();
32
- const type = param.getTypeNode()?.getText() ?? param.getType().getText(node) ?? "any";
33
- const questionToken = param.hasQuestionToken() ? "?" : "";
34
- return `${paramName}${questionToken}: ${type}`;
35
- }).join(", ");
36
- const returnTypeNode = node.getReturnTypeNode();
37
- let returnType;
38
- if (returnTypeNode != null) {
39
- returnType = returnTypeNode.getText();
40
- } else {
41
- const inferredReturnType = node.getReturnType();
42
- if (inferredReturnType.isVoid()) {
43
- returnType = "void";
44
- } else {
45
- returnType = inferredReturnType.getText(node);
46
- }
47
- }
48
- let jsDocString = "";
49
- const jsDocOwner = "getJsDocs" in node ? node : "getParantOrThrow" in node && // @ts-expect-error variable declaration
50
- node.getParentOrThrow().getKind() === tsMorph.SyntaxKind.VariableDeclaration ? (
51
- // @ts-expect-error variable declaration
52
- node.getParentOrThrow()
53
- ) : null;
54
- if (jsDocOwner != null) {
55
- const jsDocs = "getJsDocs" in jsDocOwner ? jsDocOwner.getJsDocs() : null;
56
- if (jsDocs != null && jsDocs.length > 0) {
57
- const rawConmmentText = jsDocs.map((doc) => doc.getFullText()).join("\n");
58
- if (rawConmmentText.includes("@deprecated")) {
59
- const deprecatedDoc = jsDocs.find(
60
- (doc) => doc.getFullText().includes("@deprecated")
61
- );
62
- jsDocString = `${deprecatedDoc != null ? deprecatedDoc.getFullText().trim() : "/**\n * @deprecated\n */"}
63
- `;
64
- } else {
65
- const firstDoc = jsDocs[0];
66
- const description = firstDoc.getDescription().trim();
67
- if (description != null || firstDoc.getTags().length > 0) {
68
- jsDocString = `${firstDoc.getFullText().trim()}
69
- `;
70
- }
71
- }
72
- }
73
- }
74
- return `${jsDocString}${name}${typeParamsString}(${parameters}): ${returnType};`;
75
- };
76
- const generateAppsScriptTypes = async ({
77
- project: projectPath,
78
- srcDir,
79
- outDir,
80
- outputFile
81
- }) => {
82
- const absoluteSrcDir = path__namespace.resolve(projectPath, srcDir);
83
- const absoluteOutDir = path__namespace.resolve(projectPath, outDir);
84
- const absoluteOutputFile = path__namespace.resolve(absoluteOutDir, outputFile);
85
- consola.consola.info("Starting AppsScript type generation with gasnuki...");
86
- consola.consola.info(` AppsScript Source Directory: ${absoluteSrcDir}`);
87
- consola.consola.info(` Output File: ${absoluteOutputFile}`);
88
- const project = new tsMorph.Project({
89
- tsConfigFilePath: path__namespace.resolve(projectPath, "tsconfig.json"),
90
- skipAddingFilesFromTsConfig: true
91
- });
92
- project.addSourceFilesAtPaths(
93
- path__namespace.join(absoluteSrcDir, "**/*.ts").replace(/\\/g, "/")
94
- );
95
- const methodDefinitions = [];
96
- const globalTypeDefinitions = [];
97
- const sourceFiles = project.getSourceFiles();
98
- consola.consola.info(`Found ${sourceFiles.length} source file(s).`);
99
- for (const sourceFile of sourceFiles) {
100
- for (const iface of sourceFile.getInterfaces()) {
101
- globalTypeDefinitions.push(iface.getText());
102
- }
103
- for (const typeAlias of sourceFile.getTypeAliases()) {
104
- globalTypeDefinitions.push(typeAlias.getText());
105
- }
106
- for (const statement of sourceFile.getStatements()) {
107
- if (statement.getKind() === tsMorph.SyntaxKind.ModuleDeclaration) {
108
- globalTypeDefinitions.push(statement.getText());
109
- }
110
- }
111
- for (const funcDecl of sourceFile.getFunctions()) {
112
- if (!funcDecl.isAmbient()) {
113
- const name = funcDecl.getName();
114
- if (name != null && !name.endsWith("_")) {
115
- methodDefinitions.push(getInterfaceMethodDefinition_(name, funcDecl));
116
- }
117
- }
118
- }
119
- for (const varStmt of sourceFile.getVariableStatements()) {
120
- if (!varStmt.isAmbient()) {
121
- for (const varDecl of varStmt.getDeclarations()) {
122
- const initializer = varDecl.getInitializer();
123
- const varName = varDecl.getName();
124
- if (initializer != null && (initializer.getKind() === tsMorph.SyntaxKind.ArrowFunction || initializer.getKind() === tsMorph.SyntaxKind.FunctionExpression) && !varName.endsWith("_")) {
125
- methodDefinitions.push(
126
- getInterfaceMethodDefinition_(
127
- varName,
128
- initializer
129
- )
130
- );
131
- }
132
- }
133
- }
134
- }
135
- }
136
- if (!fs__namespace.existsSync(absoluteOutDir)) {
137
- fs__namespace.mkdirSync(absoluteOutDir, { recursive: true });
138
- consola.consola.info(`Created output directory: ${absoluteOutDir}`);
139
- }
140
- const generatorName = "gasnuki";
141
- let outputContent = `// Auto-generated by ${generatorName}
142
- // Do NOT edit this file manually.
143
- `;
144
- if (globalTypeDefinitions.length > 0) {
145
- outputContent += `${globalTypeDefinitions.join("\n\n")}
146
-
147
- `;
148
- }
149
- if (methodDefinitions.length > 0) {
150
- const formattedMethods = methodDefinitions.map(
151
- (method) => method.split("\n").map((line) => ` ${line}`).join("\n")
152
- ).join("\n\n");
153
- outputContent += `export type ServerScripts = {
154
- ${formattedMethods}
155
- }
156
- `;
157
- consola.consola.info(
158
- `Interface 'ServerScript' type definitions written to ${absoluteOutputFile} (${methodDefinitions.length} function(s), ${globalTypeDefinitions.length} type(s)).`
159
- );
160
- } else {
161
- outputContent = "export type ServerScripts = {}\n";
162
- consola.consola.info(
163
- `Interface 'ServerScript' type definitions written to ${absoluteOutputFile} (no functions found).`
164
- );
165
- }
166
- outputContent += `
167
- // Auto-generated Types for GoogleAppsScript in client-side code
168
-
169
- ${text}`;
170
- fs__namespace.writeFileSync(absoluteOutputFile, outputContent);
171
- };
172
-
173
- const generateTypes = async ({
174
- project,
175
- srcDir,
176
- outDir,
177
- outputFile,
178
- watch
179
- }) => {
180
- const runGeneration = async (triggeredBy) => {
181
- const reason = triggeredBy ? ` (${triggeredBy})` : "";
182
- consola.consola.info(`Generating AppsScript types${reason}...`);
183
- try {
184
- await generateAppsScriptTypes({ project, srcDir, outDir, outputFile });
185
- consola.consola.info("Type generation complete.");
186
- } catch (e) {
187
- consola.consola.error(`Type generation failed: ${e.message}`, e);
188
- }
189
- };
190
- await runGeneration();
191
- if (watch) {
192
- const sourcePathToWatch = path__namespace.resolve(project, srcDir).replace(/\\/g, "/");
193
- consola.consola.info(
194
- `Watching for changes in ${sourcePathToWatch}... (Press Ctrl+C to stop)`
195
- );
196
- const watcher = chokidar__namespace.watch(sourcePathToWatch, {
197
- ignored: ["node_modules", "dist"],
198
- persistent: true,
199
- ignoreInitial: true
200
- });
201
- const eventHandler = async (filePath, eventName) => {
202
- consola.consola.info(`Watcher is called triggered on ${eventName}`);
203
- const relativePath = path__namespace.relative(project, filePath);
204
- await runGeneration(relativePath);
205
- };
206
- watcher.on("ready", async () => {
207
- console.log("...waiting...");
208
- watcher.on("all", async (event, path2) => {
209
- consola.consola.info(`Watcher is called triggered on ${event}: ${path2}`);
210
- await eventHandler(path2, event);
211
- });
212
- });
213
- for (const signal of ["SIGINT", "SIGTERM"]) {
214
- process.on(signal, async () => {
215
- await watcher.close();
216
- consola.consola.info("Watcher is closed.");
217
- process.exit(0);
218
- });
219
- }
220
- } else {
221
- process.exit(0);
222
- }
223
- };
224
-
225
- exports.generateTypes = generateTypes;
13
+ exports.defineConfig = index.defineConfig;
14
+ exports.generateTypes = index.generateTypes;
package/dist/index.d.cts CHANGED
@@ -1,3 +1,15 @@
1
+ /**
2
+ * User-defined configuration for gasnuki.
3
+ * `project` and `watch` options are excluded as they are runtime flags.
4
+ */
5
+ type UserConfig = Partial<Omit<GenerateOptions, 'watch' | 'project'>>;
6
+ /**
7
+ * A helper function to define the gasnuki configuration with type safety.
8
+ * @param config The configuration object.
9
+ * @returns The configuration object.
10
+ */
11
+ declare function defineConfig(config: UserConfig): UserConfig;
12
+
1
13
  interface GenerateOptions {
2
14
  project: string;
3
15
  srcDir: string;
@@ -7,5 +19,5 @@ interface GenerateOptions {
7
19
  }
8
20
  declare const generateTypes: ({ project, srcDir, outDir, outputFile, watch, }: GenerateOptions) => Promise<void>;
9
21
 
10
- export { generateTypes };
11
- export type { GenerateOptions };
22
+ export { defineConfig, generateTypes };
23
+ export type { GenerateOptions, UserConfig };
package/dist/index.d.mts CHANGED
@@ -1,3 +1,15 @@
1
+ /**
2
+ * User-defined configuration for gasnuki.
3
+ * `project` and `watch` options are excluded as they are runtime flags.
4
+ */
5
+ type UserConfig = Partial<Omit<GenerateOptions, 'watch' | 'project'>>;
6
+ /**
7
+ * A helper function to define the gasnuki configuration with type safety.
8
+ * @param config The configuration object.
9
+ * @returns The configuration object.
10
+ */
11
+ declare function defineConfig(config: UserConfig): UserConfig;
12
+
1
13
  interface GenerateOptions {
2
14
  project: string;
3
15
  srcDir: string;
@@ -7,5 +19,5 @@ interface GenerateOptions {
7
19
  }
8
20
  declare const generateTypes: ({ project, srcDir, outDir, outputFile, watch, }: GenerateOptions) => Promise<void>;
9
21
 
10
- export { generateTypes };
11
- export type { GenerateOptions };
22
+ export { defineConfig, generateTypes };
23
+ export type { GenerateOptions, UserConfig };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,15 @@
1
+ /**
2
+ * User-defined configuration for gasnuki.
3
+ * `project` and `watch` options are excluded as they are runtime flags.
4
+ */
5
+ type UserConfig = Partial<Omit<GenerateOptions, 'watch' | 'project'>>;
6
+ /**
7
+ * A helper function to define the gasnuki configuration with type safety.
8
+ * @param config The configuration object.
9
+ * @returns The configuration object.
10
+ */
11
+ declare function defineConfig(config: UserConfig): UserConfig;
12
+
1
13
  interface GenerateOptions {
2
14
  project: string;
3
15
  srcDir: string;
@@ -7,5 +19,5 @@ interface GenerateOptions {
7
19
  }
8
20
  declare const generateTypes: ({ project, srcDir, outDir, outputFile, watch, }: GenerateOptions) => Promise<void>;
9
21
 
10
- export { generateTypes };
11
- export type { GenerateOptions };
22
+ export { defineConfig, generateTypes };
23
+ export type { GenerateOptions, UserConfig };
package/dist/index.mjs CHANGED
@@ -1,207 +1,7 @@
1
- import * as path from 'node:path';
2
- import * as chokidar from 'chokidar';
3
- import { consola } from 'consola';
4
- import * as fs from 'node:fs';
5
- import { Project, SyntaxKind } from 'ts-morph';
6
-
7
- const text = "type RemoveReturnType<T> = {\n [P in keyof T]: T[P] extends (...args: infer A) => any\n ? (...args: A) => void\n : T[P];\n};\n\ntype _AppsScriptRun = RemoveReturnType<ServerScripts> & {\n [key: string]: (...args: any[]) => any;\n withSuccessHandler: <T = string | number | boolean | undefined, U = any>(\n callback: (returnValues: T, userObject?: U) => void,\n ) => _AppsScriptRun;\n withFailureHandler: <U = any>(\n callback: (error: Error, userObject?: U) => void,\n ) => _AppsScriptRun;\n withUserObject: <U = any>(userObject: U) => _AppsScriptRun;\n};\n\ntype _AppsScriptHistoryFunction = (\n stateObject: object,\n params: object,\n hash: string,\n) => void;\n\ninterface _WebAppLovacationType {\n hash: string;\n parameter: Record<string, string>;\n parameters: Record<string, string[]>;\n}\n\nexport declare interface GoogleClientSideApi {\n script: {\n run: _AppsScriptRun;\n url: {\n getLocation: (\n callback: (location: _WebAppLovacationType) => void,\n ) => void;\n };\n history: {\n push: _AppsScriptHistoryFunction;\n replace: _AppsScriptHistoryFunction;\n setChangeHandler: (\n callback: (e: {\n state: object;\n location: _WebAppLovacationType;\n }) => void,\n ) => void;\n };\n };\n}\n\ndeclare global {\n const google: GoogleClientSideApi;\n}\n";
8
-
9
- const getInterfaceMethodDefinition_ = (name, node) => {
10
- const typeParameters = node.getTypeParameters?.() ?? [];
11
- const typeParamsString = typeParameters.length > 0 ? `<${typeParameters.map((tp) => tp.getText()).join(", ")}>` : "";
12
- const parameters = node.getParameters().map((param) => {
13
- const paramName = param.getName();
14
- const type = param.getTypeNode()?.getText() ?? param.getType().getText(node) ?? "any";
15
- const questionToken = param.hasQuestionToken() ? "?" : "";
16
- return `${paramName}${questionToken}: ${type}`;
17
- }).join(", ");
18
- const returnTypeNode = node.getReturnTypeNode();
19
- let returnType;
20
- if (returnTypeNode != null) {
21
- returnType = returnTypeNode.getText();
22
- } else {
23
- const inferredReturnType = node.getReturnType();
24
- if (inferredReturnType.isVoid()) {
25
- returnType = "void";
26
- } else {
27
- returnType = inferredReturnType.getText(node);
28
- }
29
- }
30
- let jsDocString = "";
31
- const jsDocOwner = "getJsDocs" in node ? node : "getParantOrThrow" in node && // @ts-expect-error variable declaration
32
- node.getParentOrThrow().getKind() === SyntaxKind.VariableDeclaration ? (
33
- // @ts-expect-error variable declaration
34
- node.getParentOrThrow()
35
- ) : null;
36
- if (jsDocOwner != null) {
37
- const jsDocs = "getJsDocs" in jsDocOwner ? jsDocOwner.getJsDocs() : null;
38
- if (jsDocs != null && jsDocs.length > 0) {
39
- const rawConmmentText = jsDocs.map((doc) => doc.getFullText()).join("\n");
40
- if (rawConmmentText.includes("@deprecated")) {
41
- const deprecatedDoc = jsDocs.find(
42
- (doc) => doc.getFullText().includes("@deprecated")
43
- );
44
- jsDocString = `${deprecatedDoc != null ? deprecatedDoc.getFullText().trim() : "/**\n * @deprecated\n */"}
45
- `;
46
- } else {
47
- const firstDoc = jsDocs[0];
48
- const description = firstDoc.getDescription().trim();
49
- if (description != null || firstDoc.getTags().length > 0) {
50
- jsDocString = `${firstDoc.getFullText().trim()}
51
- `;
52
- }
53
- }
54
- }
55
- }
56
- return `${jsDocString}${name}${typeParamsString}(${parameters}): ${returnType};`;
57
- };
58
- const generateAppsScriptTypes = async ({
59
- project: projectPath,
60
- srcDir,
61
- outDir,
62
- outputFile
63
- }) => {
64
- const absoluteSrcDir = path.resolve(projectPath, srcDir);
65
- const absoluteOutDir = path.resolve(projectPath, outDir);
66
- const absoluteOutputFile = path.resolve(absoluteOutDir, outputFile);
67
- consola.info("Starting AppsScript type generation with gasnuki...");
68
- consola.info(` AppsScript Source Directory: ${absoluteSrcDir}`);
69
- consola.info(` Output File: ${absoluteOutputFile}`);
70
- const project = new Project({
71
- tsConfigFilePath: path.resolve(projectPath, "tsconfig.json"),
72
- skipAddingFilesFromTsConfig: true
73
- });
74
- project.addSourceFilesAtPaths(
75
- path.join(absoluteSrcDir, "**/*.ts").replace(/\\/g, "/")
76
- );
77
- const methodDefinitions = [];
78
- const globalTypeDefinitions = [];
79
- const sourceFiles = project.getSourceFiles();
80
- consola.info(`Found ${sourceFiles.length} source file(s).`);
81
- for (const sourceFile of sourceFiles) {
82
- for (const iface of sourceFile.getInterfaces()) {
83
- globalTypeDefinitions.push(iface.getText());
84
- }
85
- for (const typeAlias of sourceFile.getTypeAliases()) {
86
- globalTypeDefinitions.push(typeAlias.getText());
87
- }
88
- for (const statement of sourceFile.getStatements()) {
89
- if (statement.getKind() === SyntaxKind.ModuleDeclaration) {
90
- globalTypeDefinitions.push(statement.getText());
91
- }
92
- }
93
- for (const funcDecl of sourceFile.getFunctions()) {
94
- if (!funcDecl.isAmbient()) {
95
- const name = funcDecl.getName();
96
- if (name != null && !name.endsWith("_")) {
97
- methodDefinitions.push(getInterfaceMethodDefinition_(name, funcDecl));
98
- }
99
- }
100
- }
101
- for (const varStmt of sourceFile.getVariableStatements()) {
102
- if (!varStmt.isAmbient()) {
103
- for (const varDecl of varStmt.getDeclarations()) {
104
- const initializer = varDecl.getInitializer();
105
- const varName = varDecl.getName();
106
- if (initializer != null && (initializer.getKind() === SyntaxKind.ArrowFunction || initializer.getKind() === SyntaxKind.FunctionExpression) && !varName.endsWith("_")) {
107
- methodDefinitions.push(
108
- getInterfaceMethodDefinition_(
109
- varName,
110
- initializer
111
- )
112
- );
113
- }
114
- }
115
- }
116
- }
117
- }
118
- if (!fs.existsSync(absoluteOutDir)) {
119
- fs.mkdirSync(absoluteOutDir, { recursive: true });
120
- consola.info(`Created output directory: ${absoluteOutDir}`);
121
- }
122
- const generatorName = "gasnuki";
123
- let outputContent = `// Auto-generated by ${generatorName}
124
- // Do NOT edit this file manually.
125
- `;
126
- if (globalTypeDefinitions.length > 0) {
127
- outputContent += `${globalTypeDefinitions.join("\n\n")}
128
-
129
- `;
130
- }
131
- if (methodDefinitions.length > 0) {
132
- const formattedMethods = methodDefinitions.map(
133
- (method) => method.split("\n").map((line) => ` ${line}`).join("\n")
134
- ).join("\n\n");
135
- outputContent += `export type ServerScripts = {
136
- ${formattedMethods}
137
- }
138
- `;
139
- consola.info(
140
- `Interface 'ServerScript' type definitions written to ${absoluteOutputFile} (${methodDefinitions.length} function(s), ${globalTypeDefinitions.length} type(s)).`
141
- );
142
- } else {
143
- outputContent = "export type ServerScripts = {}\n";
144
- consola.info(
145
- `Interface 'ServerScript' type definitions written to ${absoluteOutputFile} (no functions found).`
146
- );
147
- }
148
- outputContent += `
149
- // Auto-generated Types for GoogleAppsScript in client-side code
150
-
151
- ${text}`;
152
- fs.writeFileSync(absoluteOutputFile, outputContent);
153
- };
154
-
155
- const generateTypes = async ({
156
- project,
157
- srcDir,
158
- outDir,
159
- outputFile,
160
- watch
161
- }) => {
162
- const runGeneration = async (triggeredBy) => {
163
- const reason = triggeredBy ? ` (${triggeredBy})` : "";
164
- consola.info(`Generating AppsScript types${reason}...`);
165
- try {
166
- await generateAppsScriptTypes({ project, srcDir, outDir, outputFile });
167
- consola.info("Type generation complete.");
168
- } catch (e) {
169
- consola.error(`Type generation failed: ${e.message}`, e);
170
- }
171
- };
172
- await runGeneration();
173
- if (watch) {
174
- const sourcePathToWatch = path.resolve(project, srcDir).replace(/\\/g, "/");
175
- consola.info(
176
- `Watching for changes in ${sourcePathToWatch}... (Press Ctrl+C to stop)`
177
- );
178
- const watcher = chokidar.watch(sourcePathToWatch, {
179
- ignored: ["node_modules", "dist"],
180
- persistent: true,
181
- ignoreInitial: true
182
- });
183
- const eventHandler = async (filePath, eventName) => {
184
- consola.info(`Watcher is called triggered on ${eventName}`);
185
- const relativePath = path.relative(project, filePath);
186
- await runGeneration(relativePath);
187
- };
188
- watcher.on("ready", async () => {
189
- console.log("...waiting...");
190
- watcher.on("all", async (event, path2) => {
191
- consola.info(`Watcher is called triggered on ${event}: ${path2}`);
192
- await eventHandler(path2, event);
193
- });
194
- });
195
- for (const signal of ["SIGINT", "SIGTERM"]) {
196
- process.on(signal, async () => {
197
- await watcher.close();
198
- consola.info("Watcher is closed.");
199
- process.exit(0);
200
- });
201
- }
202
- } else {
203
- process.exit(0);
204
- }
205
- };
206
-
207
- export { generateTypes };
1
+ import 'node:path';
2
+ import 'chokidar';
3
+ import 'consola';
4
+ export { d as defineConfig, g as generateTypes } from './shared/gasnuki.C-MvXA42.mjs';
5
+ import 'node:fs';
6
+ import 'ts-morph';
7
+ import 'jiti';
@@ -0,0 +1,244 @@
1
+ import * as path from 'node:path';
2
+ import * as chokidar from 'chokidar';
3
+ import { consola } from 'consola';
4
+ import * as fs from 'node:fs';
5
+ import { Project, SyntaxKind } from 'ts-morph';
6
+ import { createJiti } from 'jiti';
7
+
8
+ const text = "type RemoveReturnType<T> = {\n [P in keyof T]: T[P] extends (...args: infer A) => any\n ? (...args: A) => void\n : T[P];\n};\n\ntype _AppsScriptRun = RemoveReturnType<ServerScripts> & {\n [key: string]: (...args: any[]) => any;\n withSuccessHandler: <T = string | number | boolean | undefined, U = any>(\n callback: (returnValues: T, userObject?: U) => void,\n ) => _AppsScriptRun;\n withFailureHandler: <U = any>(\n callback: (error: Error, userObject?: U) => void,\n ) => _AppsScriptRun;\n withUserObject: <U = any>(userObject: U) => _AppsScriptRun;\n};\n\ntype _AppsScriptHistoryFunction = (\n stateObject: object,\n params: object,\n hash: string,\n) => void;\n\ninterface _WebAppLovacationType {\n hash: string;\n parameter: Record<string, string>;\n parameters: Record<string, string[]>;\n}\n\nexport declare interface GoogleClientSideApi {\n script: {\n run: _AppsScriptRun;\n url: {\n getLocation: (\n callback: (location: _WebAppLovacationType) => void,\n ) => void;\n };\n history: {\n push: _AppsScriptHistoryFunction;\n replace: _AppsScriptHistoryFunction;\n setChangeHandler: (\n callback: (e: {\n state: object;\n location: _WebAppLovacationType;\n }) => void,\n ) => void;\n };\n };\n}\n\ndeclare global {\n const google: GoogleClientSideApi;\n}\n";
9
+
10
+ const getInterfaceMethodDefinition_ = (name, node) => {
11
+ const typeParameters = node.getTypeParameters?.() ?? [];
12
+ const typeParamsString = typeParameters.length > 0 ? `<${typeParameters.map((tp) => tp.getText()).join(", ")}>` : "";
13
+ const parameters = node.getParameters().map((param) => {
14
+ const paramName = param.getName();
15
+ const type = param.getTypeNode()?.getText() ?? param.getType().getText(node) ?? "any";
16
+ const questionToken = param.hasQuestionToken() ? "?" : "";
17
+ return `${paramName}${questionToken}: ${type}`;
18
+ }).join(", ");
19
+ const returnTypeNode = node.getReturnTypeNode();
20
+ let returnType;
21
+ if (returnTypeNode != null) {
22
+ returnType = returnTypeNode.getText();
23
+ } else {
24
+ const inferredReturnType = node.getReturnType();
25
+ if (inferredReturnType.isVoid()) {
26
+ returnType = "void";
27
+ } else {
28
+ returnType = inferredReturnType.getText(node);
29
+ }
30
+ }
31
+ let jsDocString = "";
32
+ const jsDocOwner = "getJsDocs" in node ? node : "getParantOrThrow" in node && // @ts-expect-error variable declaration
33
+ node.getParentOrThrow().getKind() === SyntaxKind.VariableDeclaration ? (
34
+ // @ts-expect-error variable declaration
35
+ node.getParentOrThrow()
36
+ ) : null;
37
+ if (jsDocOwner != null) {
38
+ const jsDocs = "getJsDocs" in jsDocOwner ? jsDocOwner.getJsDocs() : null;
39
+ if (jsDocs != null && jsDocs.length > 0) {
40
+ const rawConmmentText = jsDocs.map((doc) => doc.getFullText()).join("\n");
41
+ if (rawConmmentText.includes("@deprecated")) {
42
+ const deprecatedDoc = jsDocs.find(
43
+ (doc) => doc.getFullText().includes("@deprecated")
44
+ );
45
+ jsDocString = `${deprecatedDoc != null ? deprecatedDoc.getFullText().trim() : "/**\n * @deprecated\n */"}
46
+ `;
47
+ } else {
48
+ const firstDoc = jsDocs[0];
49
+ const description = firstDoc.getDescription().trim();
50
+ if (description != null || firstDoc.getTags().length > 0) {
51
+ jsDocString = `${firstDoc.getFullText().trim()}
52
+ `;
53
+ }
54
+ }
55
+ }
56
+ }
57
+ return `${jsDocString}${name}${typeParamsString}(${parameters}): ${returnType};`;
58
+ };
59
+ const generateAppsScriptTypes = async ({
60
+ project: projectPath,
61
+ srcDir,
62
+ outDir,
63
+ outputFile
64
+ }) => {
65
+ const absoluteSrcDir = path.resolve(projectPath, srcDir);
66
+ const absoluteOutDir = path.resolve(projectPath, outDir);
67
+ const absoluteOutputFile = path.resolve(absoluteOutDir, outputFile);
68
+ consola.info("Starting AppsScript type generation with gasnuki...");
69
+ consola.info(` AppsScript Source Directory: ${absoluteSrcDir}`);
70
+ consola.info(` Output File: ${absoluteOutputFile}`);
71
+ const project = new Project({
72
+ tsConfigFilePath: path.resolve(projectPath, "tsconfig.json"),
73
+ skipAddingFilesFromTsConfig: true
74
+ });
75
+ project.addSourceFilesAtPaths(
76
+ path.join(absoluteSrcDir, "**/*.ts").replace(/\\/g, "/")
77
+ );
78
+ const methodDefinitions = [];
79
+ const globalTypeDefinitions = [];
80
+ const sourceFiles = project.getSourceFiles();
81
+ consola.info(`Found ${sourceFiles.length} source file(s).`);
82
+ for (const sourceFile of sourceFiles) {
83
+ for (const iface of sourceFile.getInterfaces()) {
84
+ globalTypeDefinitions.push(iface.getText());
85
+ }
86
+ for (const typeAlias of sourceFile.getTypeAliases()) {
87
+ globalTypeDefinitions.push(typeAlias.getText());
88
+ }
89
+ for (const statement of sourceFile.getStatements()) {
90
+ if (statement.getKind() === SyntaxKind.ModuleDeclaration) {
91
+ globalTypeDefinitions.push(statement.getText());
92
+ }
93
+ }
94
+ for (const funcDecl of sourceFile.getFunctions()) {
95
+ if (!funcDecl.isAmbient()) {
96
+ const name = funcDecl.getName();
97
+ if (name != null && !name.endsWith("_")) {
98
+ methodDefinitions.push(getInterfaceMethodDefinition_(name, funcDecl));
99
+ }
100
+ }
101
+ }
102
+ for (const varStmt of sourceFile.getVariableStatements()) {
103
+ if (!varStmt.isAmbient()) {
104
+ for (const varDecl of varStmt.getDeclarations()) {
105
+ const initializer = varDecl.getInitializer();
106
+ const varName = varDecl.getName();
107
+ if (initializer != null && (initializer.getKind() === SyntaxKind.ArrowFunction || initializer.getKind() === SyntaxKind.FunctionExpression) && !varName.endsWith("_")) {
108
+ methodDefinitions.push(
109
+ getInterfaceMethodDefinition_(
110
+ varName,
111
+ initializer
112
+ )
113
+ );
114
+ }
115
+ }
116
+ }
117
+ }
118
+ }
119
+ if (!fs.existsSync(absoluteOutDir)) {
120
+ fs.mkdirSync(absoluteOutDir, { recursive: true });
121
+ consola.info(`Created output directory: ${absoluteOutDir}`);
122
+ }
123
+ const generatorName = "gasnuki";
124
+ let outputContent = `// Auto-generated by ${generatorName}
125
+ // Do NOT edit this file manually.
126
+ `;
127
+ if (globalTypeDefinitions.length > 0) {
128
+ outputContent += `${globalTypeDefinitions.join("\n\n")}
129
+
130
+ `;
131
+ }
132
+ if (methodDefinitions.length > 0) {
133
+ const formattedMethods = methodDefinitions.map(
134
+ (method) => method.split("\n").map((line) => ` ${line}`).join("\n")
135
+ ).join("\n\n");
136
+ outputContent += `export type ServerScripts = {
137
+ ${formattedMethods}
138
+ }
139
+ `;
140
+ consola.info(
141
+ `Interface 'ServerScript' type definitions written to ${absoluteOutputFile} (${methodDefinitions.length} function(s), ${globalTypeDefinitions.length} type(s)).`
142
+ );
143
+ } else {
144
+ outputContent = "export type ServerScripts = {}\n";
145
+ consola.info(
146
+ `Interface 'ServerScript' type definitions written to ${absoluteOutputFile} (no functions found).`
147
+ );
148
+ }
149
+ outputContent += `
150
+ // Auto-generated Types for GoogleAppsScript in client-side code
151
+
152
+ ${text}`;
153
+ fs.writeFileSync(absoluteOutputFile, outputContent);
154
+ };
155
+
156
+ function defineConfig(config) {
157
+ return config;
158
+ }
159
+ async function loadConfig(projectRoot) {
160
+ const configFileExtensions = [".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"];
161
+ let foundConfigPath;
162
+ let foundConfigFileName;
163
+ for (const configFileExtension of configFileExtensions) {
164
+ const configFile = `gasnuki.config${configFileExtension}`;
165
+ const fullPath = path.resolve(projectRoot, configFile);
166
+ if (fs.existsSync(fullPath)) {
167
+ foundConfigPath = fullPath;
168
+ foundConfigFileName = configFile;
169
+ break;
170
+ }
171
+ }
172
+ if (!foundConfigPath || !foundConfigFileName) {
173
+ return {};
174
+ }
175
+ try {
176
+ const jiti = createJiti(projectRoot, {
177
+ fsCache: false,
178
+ moduleCache: false,
179
+ interopDefault: true
180
+ });
181
+ const configModule = await jiti.import(foundConfigPath, {
182
+ default: true
183
+ });
184
+ consola.success(`Loaded configuration from ${foundConfigFileName}`);
185
+ return configModule;
186
+ } catch (error) {
187
+ consola.error(`Error loading ${foundConfigFileName}:`, error);
188
+ return {};
189
+ }
190
+ }
191
+
192
+ const generateTypes = async ({
193
+ project,
194
+ srcDir,
195
+ outDir,
196
+ outputFile,
197
+ watch
198
+ }) => {
199
+ const runGeneration = async (triggeredBy) => {
200
+ const reason = triggeredBy ? ` (${triggeredBy})` : "";
201
+ consola.info(`Generating AppsScript types${reason}...`);
202
+ try {
203
+ await generateAppsScriptTypes({ project, srcDir, outDir, outputFile });
204
+ consola.info("Type generation complete.");
205
+ } catch (e) {
206
+ consola.error(`Type generation failed: ${e.message}`, e);
207
+ }
208
+ };
209
+ await runGeneration();
210
+ if (watch) {
211
+ const sourcePathToWatch = path.resolve(project, srcDir).replace(/\\/g, "/");
212
+ consola.info(
213
+ `Watching for changes in ${sourcePathToWatch}... (Press Ctrl+C to stop)`
214
+ );
215
+ const watcher = chokidar.watch(sourcePathToWatch, {
216
+ ignored: ["node_modules", "dist"],
217
+ persistent: true,
218
+ ignoreInitial: true
219
+ });
220
+ const eventHandler = async (filePath, eventName) => {
221
+ consola.info(`Watcher is called triggered on ${eventName}`);
222
+ const relativePath = path.relative(project, filePath);
223
+ await runGeneration(relativePath);
224
+ };
225
+ watcher.on("ready", async () => {
226
+ console.log("...waiting...");
227
+ watcher.on("all", async (event, path2) => {
228
+ consola.info(`Watcher is called triggered on ${event}: ${path2}`);
229
+ await eventHandler(path2, event);
230
+ });
231
+ });
232
+ for (const signal of ["SIGINT", "SIGTERM"]) {
233
+ process.on(signal, async () => {
234
+ await watcher.close();
235
+ consola.info("Watcher is closed.");
236
+ process.exit(0);
237
+ });
238
+ }
239
+ } else {
240
+ process.exit(0);
241
+ }
242
+ };
243
+
244
+ export { defineConfig as d, generateTypes as g, loadConfig as l };
@@ -0,0 +1,264 @@
1
+ 'use strict';
2
+
3
+ const path = require('node:path');
4
+ const chokidar = require('chokidar');
5
+ const consola = require('consola');
6
+ const fs = require('node:fs');
7
+ const tsMorph = require('ts-morph');
8
+ const jiti = require('jiti');
9
+
10
+ function _interopNamespaceCompat(e) {
11
+ if (e && typeof e === 'object' && 'default' in e) return e;
12
+ const n = Object.create(null);
13
+ if (e) {
14
+ for (const k in e) {
15
+ n[k] = e[k];
16
+ }
17
+ }
18
+ n.default = e;
19
+ return n;
20
+ }
21
+
22
+ const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
23
+ const chokidar__namespace = /*#__PURE__*/_interopNamespaceCompat(chokidar);
24
+ const fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
25
+
26
+ const text = "type RemoveReturnType<T> = {\n [P in keyof T]: T[P] extends (...args: infer A) => any\n ? (...args: A) => void\n : T[P];\n};\n\ntype _AppsScriptRun = RemoveReturnType<ServerScripts> & {\n [key: string]: (...args: any[]) => any;\n withSuccessHandler: <T = string | number | boolean | undefined, U = any>(\n callback: (returnValues: T, userObject?: U) => void,\n ) => _AppsScriptRun;\n withFailureHandler: <U = any>(\n callback: (error: Error, userObject?: U) => void,\n ) => _AppsScriptRun;\n withUserObject: <U = any>(userObject: U) => _AppsScriptRun;\n};\n\ntype _AppsScriptHistoryFunction = (\n stateObject: object,\n params: object,\n hash: string,\n) => void;\n\ninterface _WebAppLovacationType {\n hash: string;\n parameter: Record<string, string>;\n parameters: Record<string, string[]>;\n}\n\nexport declare interface GoogleClientSideApi {\n script: {\n run: _AppsScriptRun;\n url: {\n getLocation: (\n callback: (location: _WebAppLovacationType) => void,\n ) => void;\n };\n history: {\n push: _AppsScriptHistoryFunction;\n replace: _AppsScriptHistoryFunction;\n setChangeHandler: (\n callback: (e: {\n state: object;\n location: _WebAppLovacationType;\n }) => void,\n ) => void;\n };\n };\n}\n\ndeclare global {\n const google: GoogleClientSideApi;\n}\n";
27
+
28
+ const getInterfaceMethodDefinition_ = (name, node) => {
29
+ const typeParameters = node.getTypeParameters?.() ?? [];
30
+ const typeParamsString = typeParameters.length > 0 ? `<${typeParameters.map((tp) => tp.getText()).join(", ")}>` : "";
31
+ const parameters = node.getParameters().map((param) => {
32
+ const paramName = param.getName();
33
+ const type = param.getTypeNode()?.getText() ?? param.getType().getText(node) ?? "any";
34
+ const questionToken = param.hasQuestionToken() ? "?" : "";
35
+ return `${paramName}${questionToken}: ${type}`;
36
+ }).join(", ");
37
+ const returnTypeNode = node.getReturnTypeNode();
38
+ let returnType;
39
+ if (returnTypeNode != null) {
40
+ returnType = returnTypeNode.getText();
41
+ } else {
42
+ const inferredReturnType = node.getReturnType();
43
+ if (inferredReturnType.isVoid()) {
44
+ returnType = "void";
45
+ } else {
46
+ returnType = inferredReturnType.getText(node);
47
+ }
48
+ }
49
+ let jsDocString = "";
50
+ const jsDocOwner = "getJsDocs" in node ? node : "getParantOrThrow" in node && // @ts-expect-error variable declaration
51
+ node.getParentOrThrow().getKind() === tsMorph.SyntaxKind.VariableDeclaration ? (
52
+ // @ts-expect-error variable declaration
53
+ node.getParentOrThrow()
54
+ ) : null;
55
+ if (jsDocOwner != null) {
56
+ const jsDocs = "getJsDocs" in jsDocOwner ? jsDocOwner.getJsDocs() : null;
57
+ if (jsDocs != null && jsDocs.length > 0) {
58
+ const rawConmmentText = jsDocs.map((doc) => doc.getFullText()).join("\n");
59
+ if (rawConmmentText.includes("@deprecated")) {
60
+ const deprecatedDoc = jsDocs.find(
61
+ (doc) => doc.getFullText().includes("@deprecated")
62
+ );
63
+ jsDocString = `${deprecatedDoc != null ? deprecatedDoc.getFullText().trim() : "/**\n * @deprecated\n */"}
64
+ `;
65
+ } else {
66
+ const firstDoc = jsDocs[0];
67
+ const description = firstDoc.getDescription().trim();
68
+ if (description != null || firstDoc.getTags().length > 0) {
69
+ jsDocString = `${firstDoc.getFullText().trim()}
70
+ `;
71
+ }
72
+ }
73
+ }
74
+ }
75
+ return `${jsDocString}${name}${typeParamsString}(${parameters}): ${returnType};`;
76
+ };
77
+ const generateAppsScriptTypes = async ({
78
+ project: projectPath,
79
+ srcDir,
80
+ outDir,
81
+ outputFile
82
+ }) => {
83
+ const absoluteSrcDir = path__namespace.resolve(projectPath, srcDir);
84
+ const absoluteOutDir = path__namespace.resolve(projectPath, outDir);
85
+ const absoluteOutputFile = path__namespace.resolve(absoluteOutDir, outputFile);
86
+ consola.consola.info("Starting AppsScript type generation with gasnuki...");
87
+ consola.consola.info(` AppsScript Source Directory: ${absoluteSrcDir}`);
88
+ consola.consola.info(` Output File: ${absoluteOutputFile}`);
89
+ const project = new tsMorph.Project({
90
+ tsConfigFilePath: path__namespace.resolve(projectPath, "tsconfig.json"),
91
+ skipAddingFilesFromTsConfig: true
92
+ });
93
+ project.addSourceFilesAtPaths(
94
+ path__namespace.join(absoluteSrcDir, "**/*.ts").replace(/\\/g, "/")
95
+ );
96
+ const methodDefinitions = [];
97
+ const globalTypeDefinitions = [];
98
+ const sourceFiles = project.getSourceFiles();
99
+ consola.consola.info(`Found ${sourceFiles.length} source file(s).`);
100
+ for (const sourceFile of sourceFiles) {
101
+ for (const iface of sourceFile.getInterfaces()) {
102
+ globalTypeDefinitions.push(iface.getText());
103
+ }
104
+ for (const typeAlias of sourceFile.getTypeAliases()) {
105
+ globalTypeDefinitions.push(typeAlias.getText());
106
+ }
107
+ for (const statement of sourceFile.getStatements()) {
108
+ if (statement.getKind() === tsMorph.SyntaxKind.ModuleDeclaration) {
109
+ globalTypeDefinitions.push(statement.getText());
110
+ }
111
+ }
112
+ for (const funcDecl of sourceFile.getFunctions()) {
113
+ if (!funcDecl.isAmbient()) {
114
+ const name = funcDecl.getName();
115
+ if (name != null && !name.endsWith("_")) {
116
+ methodDefinitions.push(getInterfaceMethodDefinition_(name, funcDecl));
117
+ }
118
+ }
119
+ }
120
+ for (const varStmt of sourceFile.getVariableStatements()) {
121
+ if (!varStmt.isAmbient()) {
122
+ for (const varDecl of varStmt.getDeclarations()) {
123
+ const initializer = varDecl.getInitializer();
124
+ const varName = varDecl.getName();
125
+ if (initializer != null && (initializer.getKind() === tsMorph.SyntaxKind.ArrowFunction || initializer.getKind() === tsMorph.SyntaxKind.FunctionExpression) && !varName.endsWith("_")) {
126
+ methodDefinitions.push(
127
+ getInterfaceMethodDefinition_(
128
+ varName,
129
+ initializer
130
+ )
131
+ );
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ if (!fs__namespace.existsSync(absoluteOutDir)) {
138
+ fs__namespace.mkdirSync(absoluteOutDir, { recursive: true });
139
+ consola.consola.info(`Created output directory: ${absoluteOutDir}`);
140
+ }
141
+ const generatorName = "gasnuki";
142
+ let outputContent = `// Auto-generated by ${generatorName}
143
+ // Do NOT edit this file manually.
144
+ `;
145
+ if (globalTypeDefinitions.length > 0) {
146
+ outputContent += `${globalTypeDefinitions.join("\n\n")}
147
+
148
+ `;
149
+ }
150
+ if (methodDefinitions.length > 0) {
151
+ const formattedMethods = methodDefinitions.map(
152
+ (method) => method.split("\n").map((line) => ` ${line}`).join("\n")
153
+ ).join("\n\n");
154
+ outputContent += `export type ServerScripts = {
155
+ ${formattedMethods}
156
+ }
157
+ `;
158
+ consola.consola.info(
159
+ `Interface 'ServerScript' type definitions written to ${absoluteOutputFile} (${methodDefinitions.length} function(s), ${globalTypeDefinitions.length} type(s)).`
160
+ );
161
+ } else {
162
+ outputContent = "export type ServerScripts = {}\n";
163
+ consola.consola.info(
164
+ `Interface 'ServerScript' type definitions written to ${absoluteOutputFile} (no functions found).`
165
+ );
166
+ }
167
+ outputContent += `
168
+ // Auto-generated Types for GoogleAppsScript in client-side code
169
+
170
+ ${text}`;
171
+ fs__namespace.writeFileSync(absoluteOutputFile, outputContent);
172
+ };
173
+
174
+ function defineConfig(config) {
175
+ return config;
176
+ }
177
+ async function loadConfig(projectRoot) {
178
+ const configFileExtensions = [".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"];
179
+ let foundConfigPath;
180
+ let foundConfigFileName;
181
+ for (const configFileExtension of configFileExtensions) {
182
+ const configFile = `gasnuki.config${configFileExtension}`;
183
+ const fullPath = path__namespace.resolve(projectRoot, configFile);
184
+ if (fs__namespace.existsSync(fullPath)) {
185
+ foundConfigPath = fullPath;
186
+ foundConfigFileName = configFile;
187
+ break;
188
+ }
189
+ }
190
+ if (!foundConfigPath || !foundConfigFileName) {
191
+ return {};
192
+ }
193
+ try {
194
+ const jiti$1 = jiti.createJiti(projectRoot, {
195
+ fsCache: false,
196
+ moduleCache: false,
197
+ interopDefault: true
198
+ });
199
+ const configModule = await jiti$1.import(foundConfigPath, {
200
+ default: true
201
+ });
202
+ consola.consola.success(`Loaded configuration from ${foundConfigFileName}`);
203
+ return configModule;
204
+ } catch (error) {
205
+ consola.consola.error(`Error loading ${foundConfigFileName}:`, error);
206
+ return {};
207
+ }
208
+ }
209
+
210
+ const generateTypes = async ({
211
+ project,
212
+ srcDir,
213
+ outDir,
214
+ outputFile,
215
+ watch
216
+ }) => {
217
+ const runGeneration = async (triggeredBy) => {
218
+ const reason = triggeredBy ? ` (${triggeredBy})` : "";
219
+ consola.consola.info(`Generating AppsScript types${reason}...`);
220
+ try {
221
+ await generateAppsScriptTypes({ project, srcDir, outDir, outputFile });
222
+ consola.consola.info("Type generation complete.");
223
+ } catch (e) {
224
+ consola.consola.error(`Type generation failed: ${e.message}`, e);
225
+ }
226
+ };
227
+ await runGeneration();
228
+ if (watch) {
229
+ const sourcePathToWatch = path__namespace.resolve(project, srcDir).replace(/\\/g, "/");
230
+ consola.consola.info(
231
+ `Watching for changes in ${sourcePathToWatch}... (Press Ctrl+C to stop)`
232
+ );
233
+ const watcher = chokidar__namespace.watch(sourcePathToWatch, {
234
+ ignored: ["node_modules", "dist"],
235
+ persistent: true,
236
+ ignoreInitial: true
237
+ });
238
+ const eventHandler = async (filePath, eventName) => {
239
+ consola.consola.info(`Watcher is called triggered on ${eventName}`);
240
+ const relativePath = path__namespace.relative(project, filePath);
241
+ await runGeneration(relativePath);
242
+ };
243
+ watcher.on("ready", async () => {
244
+ console.log("...waiting...");
245
+ watcher.on("all", async (event, path2) => {
246
+ consola.consola.info(`Watcher is called triggered on ${event}: ${path2}`);
247
+ await eventHandler(path2, event);
248
+ });
249
+ });
250
+ for (const signal of ["SIGINT", "SIGTERM"]) {
251
+ process.on(signal, async () => {
252
+ await watcher.close();
253
+ consola.consola.info("Watcher is closed.");
254
+ process.exit(0);
255
+ });
256
+ }
257
+ } else {
258
+ process.exit(0);
259
+ }
260
+ };
261
+
262
+ exports.defineConfig = defineConfig;
263
+ exports.generateTypes = generateTypes;
264
+ exports.loadConfig = loadConfig;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ciderjs/gasnuki",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
4
4
  "description": "Type definitions and utilities for Google Apps Script client-side API",
5
5
  "main": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -21,10 +21,10 @@
21
21
  },
22
22
  "scripts": {
23
23
  "prebuild": "jiti bin/generate.ts",
24
- "dev": "pnpm prebuild && jiti src/cli.ts -p playground/react -s src/server",
24
+ "dev": "pnpm prebuild && jiti src/cli.ts -p playground/react",
25
25
  "start": "node dist/cli.mjs -p playground/react -s src/server",
26
26
  "check": "biome check --write",
27
- "build": "pnpm prebuild && unbuild",
27
+ "build": "unbuild",
28
28
  "test": "vitest run",
29
29
  "prepare": "pnpm run check && pnpm run build"
30
30
  },
@@ -44,12 +44,12 @@
44
44
  "chokidar": "^4.0.3",
45
45
  "commander": "^14.0.0",
46
46
  "consola": "^3.4.2",
47
+ "jiti": "^2.4.2",
47
48
  "ts-morph": "^26.0.0"
48
49
  },
49
50
  "devDependencies": {
50
51
  "@biomejs/biome": "^1.9.4",
51
52
  "@types/node": "^22.15.29",
52
- "jiti": "^2.4.2",
53
53
  "typescript": "^5.8.3",
54
54
  "unbuild": "^3.5.0",
55
55
  "vitest": "^3.2.1"