@ciderjs/gasnuki 0.3.1 → 0.3.3

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 CHANGED
@@ -1,7 +1,8 @@
1
- # gasnuki
1
+ # @ciderjs/gasnuki
2
2
 
3
- [![Test Coverage](https://img.shields.io/badge/test%20coverage-90.91%25-brightgreen)](https://github.com/luthpg/gasnuki)
4
- [![License](https://img.shields.io/badge/license-ISC-blue.svg)](LICENSE)
3
+ [![README-en](https://img.shields.io/badge/English-blue?logo=ReadMe)](./README.md)
4
+ [![Test Coverage](https://img.shields.io/badge/test%20coverage-95.15%25-brightgreen)](https://github.com/luthpg/gasnuki)
5
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
5
6
  [![npm version](https://img.shields.io/npm/v/@ciderjs/gasnuki.svg)](https://www.npmjs.com/package/@ciderjs/gasnuki)
6
7
  [![GitHub issues](https://img.shields.io/github/issues/luthpg/gasnuki.svg)](https://github.com/luthpg/gasnuki/issues)
7
8
 
@@ -9,8 +10,16 @@ Google Apps Script クライアントサイドAPIの型定義・ユーティリ
9
10
 
10
11
  ## 概要
11
12
 
12
- `gasnuki`は、Google Apps Script のクライアントサイドAPIをTypeScriptで安全に扱うための型定義とユーティリティを提供します。
13
- Apps Scriptとフロントエンド間の型安全な通信をサポートします。
13
+ `gasnuki`は、サーバーサイドのGoogle Apps Script関数から型定義を自動で抽出し、クライアントサイドで利用する`google.script.run` APIに完全な型付けを提供します。これにより、Apps Scriptバックエンドとモダンなフロントエンド開発との間のギャップを埋め、自動補完と堅牢な型チェックを実現します。
14
+
15
+ ## `gasnuki`が実現する開発体験
16
+
17
+ `gasnuki`は、Google Apps Scriptを用いたWebアプリケーション開発における、もどかしい開発体験を劇的に改善します。
18
+
19
+ - **完全な型安全性**: `google.script.run`の引数や戻り値に型が付き、エディタの自動補完が効くため、推測に頼るコーディングは不要になります。
20
+ - **モダンな非同期処理**: `async/await`構文を利用して、コールバック地獄に陥ることなく、サーバーサイド関数をシンプルかつ直感的に呼び出せます。
21
+ - **高速な開発サイクル**: フロントエンドの変更を試すたびに`clasp push`する必要はありません。モック機能を使えば、オフラインで迅速なUI開発が可能です。
22
+ - **シームレスな統合**: Vite開発サーバーと連携し、サーバーサイドのコードを変更・保存するだけで、クライアントサイドの型定義が自動的に更新されます。
14
23
 
15
24
  ## インストール
16
25
 
@@ -101,16 +110,19 @@ google.script.run
101
110
  .getContent('Sheet1');
102
111
  ```
103
112
 
104
- ## 機能
113
+ ## 主な機能
114
+
115
+ `gasnuki`は、優れた開発体験を実現するために、以下の機能を提供します。
116
+
117
+ ### サーバーサイド関数の型定義を自動生成
105
118
 
106
- - Google Apps Script クライアントAPIの型定義
107
- - サーバーサイド関数の戻り値型をvoidに変換するユーティリティ型
119
+ `gasnuki`コマンドを実行すると、指定されたApps Scriptプロジェクト内の `.ts` ファイルを解析し、公開されているすべてのサーバーサイド関数のシグネチャを抽出します。そして、クライアントサイドの`google.script.run`から安全に呼び出せる型定義ファイルを生成します。
108
120
 
109
- ### Promiseベースのラッパー
121
+ ### PromiseベースのモダンなAPIラッパー
110
122
 
111
- `@ciderjs/gasnuki/promise` を利用すると、`google.script.run` をPromiseを返す型安全なラッパーとして使用できます。これにより、`async/await` を使ったモダンな非同期処理を記述できます。
123
+ `@ciderjs/gasnuki/promise`は、従来のコールバックベースのAPIを、`async/await`で利用可能なPromiseベースの型安全なラッパーに変換します。
112
124
 
113
- 1. まず、`gasnuki` で生成した型定義 (`ServerScripts`) と、`getPromisedServerScripts` 関数をインポートします。
125
+ 1. `getPromisedServerScripts`関数をインポートし、`gasnuki`が生成した型`ServerScripts`を渡します。
114
126
 
115
127
  ```ts:lib/gas.ts
116
128
  import { getPromisedServerScripts } from '@ciderjs/gasnuki/promise';
@@ -120,7 +132,7 @@ google.script.run
120
132
  export const gas = getPromisedServerScripts<ServerScripts>();
121
133
  ```
122
134
 
123
- 2. 作成した `gas` オブジェクトを使って、サーバーサイド関数を `async/await` で呼び出します。
135
+ 2. これで、サーバーサイド関数を `async/await` で呼び出せます。
124
136
 
125
137
  ```ts:components/MyComponent.tsx
126
138
  import { gas } from '../lib/gas';
@@ -136,9 +148,9 @@ google.script.run
136
148
  }
137
149
  ```
138
150
 
139
- #### モックアップによる開発
151
+ ### フロントエンド開発を加速するモック機能
140
152
 
141
- `getPromisedServerScripts` にモック関数を渡すことで、`clasp push` をせずともフロントエンド開発を進めることができます。
153
+ `getPromisedServerScripts`にモック用のオブジェクトを渡すことで、`clasp push`をせずともフロントエンド開発を進めることができます。これにより、バックエンドのロジックに依存せず、UIの挙動確認やデバッグを迅速に行えます。
142
154
 
143
155
  ```ts:lib/gas.ts
144
156
  import {
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # @ciderjs/gasnuki
2
2
 
3
- [![Test Coverage](https://img.shields.io/badge/test%20coverage-90.91%25-brightgreen)](https://github.com/luthpg/gasnuki)
4
- [![License](https://img.shields.io/badge/license-ISC-blue.svg)](LICENSE)
3
+ [![README-ja](https://img.shields.io/badge/日本語-blue?logo=ReadMe)](./README.ja.md)
4
+ [![Test Coverage](https://img.shields.io/badge/test%20coverage-95.15%25-brightgreen)](https://github.com/luthpg/gasnuki)
5
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
5
6
  [![npm version](https://img.shields.io/npm/v/@ciderjs/gasnuki.svg)](https://www.npmjs.com/package/@ciderjs/gasnuki)
6
7
  [![GitHub issues](https://img.shields.io/github/issues/luthpg/gasnuki.svg)](https://github.com/luthpg/gasnuki/issues)
7
8
 
@@ -9,7 +10,16 @@ Type definitions and utilities for Google Apps Script client-side API
9
10
 
10
11
  ## Overview
11
12
 
12
- `gasnuki` provides TypeScript type definitions and utilities for safely using the Google Apps Script client-side API. It helps ensure type-safe communication between Apps Script and your frontend.
13
+ `gasnuki` automatically extracts type definitions from your server-side Google Apps Script functions, providing a fully type-safe `google.script.run` API for your client-side code. This bridges the gap between your Apps Script backend and modern frontend development with autocompletion and robust type-checking.
14
+
15
+ ## The developer experience gasnuki Delivers
16
+
17
+ `gasnuki` dramatically improves the often-frustrating developer experience of building web applications with Google Apps Script.
18
+
19
+ - **Full Type Safety**: Say goodbye to guesswork. With typed arguments and return values for `google.script.run`, you get full autocompletion and compile-time checks in your editor.
20
+ - **Modern Async Syntax**: Write clean, intuitive code using `async/await` for your server-side calls, freeing you from callback hell.
21
+ - **Rapid Development Cycles**: No more waiting for `clasp push` every time you want to test a frontend change. The mocking feature allows you to develop your UI swiftly and offline.
22
+ - **Seamless Integration**: With the Vite plugin, your client-side types are automatically regenerated whenever you save a change in your server-side code, creating a truly seamless workflow.
13
23
 
14
24
  ## Installation
15
25
 
@@ -100,16 +110,19 @@ google.script.run
100
110
  .getContent('Sheet1');
101
111
  ```
102
112
 
103
- ## Features
113
+ ## Core Features
114
+
115
+ `gasnuki` provides the following features to deliver a superior developer experience.
104
116
 
105
- - Type definitions for Google Apps Script client-side API
106
- - Utility type to convert server-side function return types to void
117
+ ### Automatic Type Generation for Server Functions
107
118
 
108
- ### Promise-based Wrapper
119
+ Running the `gasnuki` command parses the `.ts` files in your Apps Script project, extracts the signatures of all your published server-side functions, and generates a type definition file. This file makes your functions safely callable from the client-side `google.script.run`.
109
120
 
110
- For a more modern asynchronous approach, you can use the type-safe Promise-based wrapper for `google.script.run`. This allows you to write clean code with `async/await`.
121
+ ### Modern, Promise-Based API Wrapper
111
122
 
112
- 1. First, import the type definitions (`ServerScripts`) generated by `gasnuki` and the `getPromisedServerScripts` function.
123
+ `@ciderjs/gasnuki/promise` transforms the traditional callback-based API into a type-safe, Promise-based wrapper that supports `async/await`.
124
+
125
+ 1. Import the `getPromisedServerScripts` function and pass it the `ServerScripts` type generated by `gasnuki`.
113
126
 
114
127
  ```ts:lib/gas.ts
115
128
  import { getPromisedServerScripts } from '@ciderjs/gasnuki/promise';
@@ -135,9 +148,9 @@ For a more modern asynchronous approach, you can use the type-safe Promise-based
135
148
  }
136
149
  ```
137
150
 
138
- #### Development with Mockups
151
+ ### Mocking for Accelerated Frontend Development
139
152
 
140
- By passing mockup functions to `getPromisedServerScripts`, you can proceed with frontend development without needing to `clasp push` every time.
153
+ By passing a mock object to `getPromisedServerScripts`, you can develop your frontend without needing to `clasp push`. This allows for rapid testing and debugging of your UI without any dependency on the live backend logic.
141
154
 
142
155
  ```ts:lib/gas.ts
143
156
  import {
@@ -159,8 +172,6 @@ const mockup: PartialScriptType<ServerScripts> = {
159
172
  export const gas = getPromisedServerScripts<ServerScripts>(mockup);
160
173
  ```
161
174
 
162
- ---
163
-
164
175
  ## Contributing
165
176
 
166
177
  Bug reports and pull requests are welcome. Please use the `issues` or `pull requests` section.
package/dist/cli.cjs CHANGED
@@ -4,7 +4,7 @@
4
4
  const path = require('node:path');
5
5
  const commander = require('commander');
6
6
  const index = require('./index.cjs');
7
- const config = require('./shared/gasnuki.Cbwq1CES.cjs');
7
+ const config = require('./shared/gasnuki.D8w16Lbm.cjs');
8
8
  require('chokidar');
9
9
  require('consola');
10
10
  require('node:fs');
@@ -25,7 +25,7 @@ function _interopNamespaceCompat(e) {
25
25
 
26
26
  const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
27
27
 
28
- const version = "0.3.1";
28
+ const version = "0.3.3";
29
29
 
30
30
  const parseArgs = async (command) => {
31
31
  const cliOpts = command.opts();
@@ -51,7 +51,7 @@ const parseArgs = async (command) => {
51
51
  };
52
52
  await index.generateTypes(finalOptions);
53
53
  };
54
- const cli = async () => {
54
+ const runCli = async () => {
55
55
  const program = new commander.Command();
56
56
  program.name("gasnuki").description(
57
57
  "Generate type definitions and utilities for Google Apps Script client-side API"
@@ -72,7 +72,10 @@ const cli = async () => {
72
72
  ).option("-f, --outputFile <file>", "Output file name", "appsscript.ts").option("-w, --watch", "Watch for changes and re-generate types", false);
73
73
  await program.parseAsync(process.argv);
74
74
  };
75
- cli();
75
+ const isMainModule = typeof require !== "undefined" && require.main === module;
76
+ if (isMainModule || process.argv[1] === undefined) {
77
+ runCli();
78
+ }
76
79
 
77
- exports.cli = cli;
78
80
  exports.parseArgs = parseArgs;
81
+ exports.runCli = runCli;
package/dist/cli.d.cts CHANGED
@@ -2,6 +2,6 @@
2
2
  import { Command } from 'commander';
3
3
 
4
4
  declare const parseArgs: (command: Command) => Promise<void>;
5
- declare const cli: () => Promise<void>;
5
+ declare const runCli: () => Promise<void>;
6
6
 
7
- export { cli, parseArgs };
7
+ export { parseArgs, runCli };
package/dist/cli.d.mts CHANGED
@@ -2,6 +2,6 @@
2
2
  import { Command } from 'commander';
3
3
 
4
4
  declare const parseArgs: (command: Command) => Promise<void>;
5
- declare const cli: () => Promise<void>;
5
+ declare const runCli: () => Promise<void>;
6
6
 
7
- export { cli, parseArgs };
7
+ export { parseArgs, runCli };
package/dist/cli.d.ts CHANGED
@@ -2,6 +2,6 @@
2
2
  import { Command } from 'commander';
3
3
 
4
4
  declare const parseArgs: (command: Command) => Promise<void>;
5
- declare const cli: () => Promise<void>;
5
+ declare const runCli: () => Promise<void>;
6
6
 
7
- export { cli, parseArgs };
7
+ export { parseArgs, runCli };
package/dist/cli.mjs CHANGED
@@ -2,14 +2,14 @@
2
2
  import * as path from 'node:path';
3
3
  import { Command } from 'commander';
4
4
  import { generateTypes } from './index.mjs';
5
- import { l as loadConfig } from './shared/gasnuki.Bcijv2Ub.mjs';
5
+ import { l as loadConfig } from './shared/gasnuki.D1fp3Uiw.mjs';
6
6
  import 'chokidar';
7
7
  import 'consola';
8
8
  import 'node:fs';
9
9
  import 'ts-morph';
10
10
  import 'jiti';
11
11
 
12
- const version = "0.3.1";
12
+ const version = "0.3.3";
13
13
 
14
14
  const parseArgs = async (command) => {
15
15
  const cliOpts = command.opts();
@@ -35,7 +35,7 @@ const parseArgs = async (command) => {
35
35
  };
36
36
  await generateTypes(finalOptions);
37
37
  };
38
- const cli = async () => {
38
+ const runCli = async () => {
39
39
  const program = new Command();
40
40
  program.name("gasnuki").description(
41
41
  "Generate type definitions and utilities for Google Apps Script client-side API"
@@ -56,6 +56,9 @@ const cli = async () => {
56
56
  ).option("-f, --outputFile <file>", "Output file name", "appsscript.ts").option("-w, --watch", "Watch for changes and re-generate types", false);
57
57
  await program.parseAsync(process.argv);
58
58
  };
59
- cli();
59
+ const isMainModule = typeof require !== "undefined" && require.main === module;
60
+ if (isMainModule || process.argv[1] === import.meta.filename) {
61
+ runCli();
62
+ }
60
63
 
61
- export { cli, parseArgs };
64
+ export { parseArgs, runCli };
package/dist/index.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
  const path = require('node:path');
4
4
  const chokidar = require('chokidar');
5
5
  const consola = require('consola');
6
- const config = require('./shared/gasnuki.Cbwq1CES.cjs');
6
+ const config = require('./shared/gasnuki.D8w16Lbm.cjs');
7
7
  require('node:fs');
8
8
  require('ts-morph');
9
9
  require('jiti');
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as path from 'node:path';
2
2
  import * as chokidar from 'chokidar';
3
3
  import { consola } from 'consola';
4
- import { g as generateAppsScriptTypes } from './shared/gasnuki.Bcijv2Ub.mjs';
5
- export { d as defineConfig } from './shared/gasnuki.Bcijv2Ub.mjs';
4
+ import { g as generateAppsScriptTypes } from './shared/gasnuki.D1fp3Uiw.mjs';
5
+ export { d as defineConfig } from './shared/gasnuki.D1fp3Uiw.mjs';
6
6
  import 'node:fs';
7
7
  import 'ts-morph';
8
8
  import 'jiti';
@@ -51,11 +51,34 @@ const SIMPLE_TRIGGER_FUNCTION_NAMES = [
51
51
  "doGet",
52
52
  "doPost"
53
53
  ];
54
+ const getPackageNameFromNodeModulesPath_ = (filePath) => {
55
+ const normalizedPath = filePath.replace(/\\/g, "/");
56
+ const nodeModulesIndex = normalizedPath.lastIndexOf("node_modules/");
57
+ if (nodeModulesIndex === -1) {
58
+ return null;
59
+ }
60
+ const afterNodeModules = normalizedPath.slice(
61
+ nodeModulesIndex + "node_modules/".length
62
+ );
63
+ const parts = afterNodeModules.split("/");
64
+ if (parts.length === 0) {
65
+ return null;
66
+ }
67
+ if (parts[0].startsWith("@") && parts.length >= 2) {
68
+ const scopedName = `${parts[0]}/${parts[1]}`;
69
+ if (parts[0] === "@types") {
70
+ return parts[1];
71
+ }
72
+ return scopedName;
73
+ }
74
+ return parts[0];
75
+ };
54
76
  const generateAppsScriptTypes = async ({
55
77
  project: projectPath,
56
78
  srcDir,
57
79
  outDir,
58
- outputFile
80
+ outputFile,
81
+ projectInstance
59
82
  }) => {
60
83
  const absoluteSrcDir = path.resolve(projectPath, srcDir);
61
84
  const absoluteOutDir = path.resolve(projectPath, outDir);
@@ -63,7 +86,7 @@ const generateAppsScriptTypes = async ({
63
86
  consola.info("Starting AppsScript type generation with gasnuki...");
64
87
  consola.info(` AppsScript Source Directory: ${absoluteSrcDir}`);
65
88
  consola.info(` Output File: ${absoluteOutputFile}`);
66
- const project = new Project({
89
+ const project = projectInstance ?? new Project({
67
90
  tsConfigFilePath: path.resolve(projectPath, "tsconfig.json"),
68
91
  skipAddingFilesFromTsConfig: true
69
92
  });
@@ -75,7 +98,6 @@ const generateAppsScriptTypes = async ({
75
98
  const methodDefinitions = [];
76
99
  const exportedDeclarations = [];
77
100
  const exportedDeclarationNames = /* @__PURE__ */ new Set();
78
- const exportedFunctions = [];
79
101
  for (const sourceFile of sourceFiles) {
80
102
  const filePath = sourceFile.getFilePath().replace(/\\/g, "/");
81
103
  const srcPath = absoluteSrcDir.replace(/\\/g, "/");
@@ -101,7 +123,6 @@ const generateAppsScriptTypes = async ({
101
123
  exportedDeclarations.push(func);
102
124
  exportedDeclarationNames.add(name);
103
125
  methodDefinitions.push(getInterfaceMethodDefinition_(name, func));
104
- exportedFunctions.push(func);
105
126
  }
106
127
  }
107
128
  for (const varStmt of sourceFile.getVariableStatements()) {
@@ -113,7 +134,6 @@ const generateAppsScriptTypes = async ({
113
134
  exportedDeclarations.push(varDecl);
114
135
  exportedDeclarationNames.add(name);
115
136
  methodDefinitions.push(getInterfaceMethodDefinition_(name, funcExpr));
116
- exportedFunctions.push(funcExpr);
117
137
  }
118
138
  }
119
139
  }
@@ -145,38 +165,21 @@ const generateAppsScriptTypes = async ({
145
165
  }
146
166
  }
147
167
  };
148
- const returnValueSymbols = /* @__PURE__ */ new Set();
149
- for (const func of exportedFunctions) {
150
- collectSymbolsFromType(func.getReturnType(), returnValueSymbols);
151
- }
168
+ const functionSignatureSymbols = /* @__PURE__ */ new Set();
152
169
  const symbolsToProcess = /* @__PURE__ */ new Set();
153
170
  for (const decl of exportedDeclarations) {
154
171
  if (decl.getKind() === SyntaxKind.FunctionDeclaration || decl.getKind() === SyntaxKind.VariableDeclaration && (decl.getInitializer()?.getKind() === SyntaxKind.ArrowFunction || decl.getInitializer()?.getKind() === SyntaxKind.FunctionExpression)) {
155
172
  const func = decl.getKind() === SyntaxKind.FunctionDeclaration ? decl : decl.getInitializer();
156
173
  const parameters = func.getParameters();
157
174
  for (const param of parameters) {
158
- const typeRefs = param.getDescendantsOfKind(SyntaxKind.TypeReference);
159
- for (const typeRef of typeRefs) {
160
- const symbol = typeRef.getType().getAliasSymbol() ?? typeRef.getType().getSymbol();
161
- if (symbol) symbolsToProcess.add(symbol);
162
- }
163
- }
164
- const returnTypeNode = func.getReturnTypeNode();
165
- if (returnTypeNode) {
166
- const typeRefs = returnTypeNode.getDescendantsOfKind(
167
- SyntaxKind.TypeReference
168
- );
169
- for (const typeRef of typeRefs) {
170
- const symbol = typeRef.getType().getAliasSymbol() ?? typeRef.getType().getSymbol();
171
- if (symbol) symbolsToProcess.add(symbol);
172
- }
175
+ collectSymbolsFromType(param.getType(), functionSignatureSymbols);
176
+ collectSymbolsFromType(param.getType(), symbolsToProcess);
173
177
  }
178
+ const returnType = func.getReturnType();
179
+ collectSymbolsFromType(returnType, functionSignatureSymbols);
180
+ collectSymbolsFromType(returnType, symbolsToProcess);
174
181
  } else if (decl.getKind() === SyntaxKind.InterfaceDeclaration || decl.getKind() === SyntaxKind.TypeAliasDeclaration) {
175
- const typeRefs = decl.getDescendantsOfKind(SyntaxKind.TypeReference);
176
- for (const typeRef of typeRefs) {
177
- const symbol = typeRef.getType().getAliasSymbol() ?? typeRef.getType().getSymbol();
178
- if (symbol) symbolsToProcess.add(symbol);
179
- }
182
+ collectSymbolsFromType(decl.getType(), symbolsToProcess);
180
183
  }
181
184
  }
182
185
  const importsMap = /* @__PURE__ */ new Map();
@@ -198,9 +201,25 @@ const generateAppsScriptTypes = async ({
198
201
  if (!declaration) {
199
202
  continue;
200
203
  }
204
+ if (declaration.getKind() === SyntaxKind.MethodSignature || declaration.getKind() === SyntaxKind.PropertySignature || declaration.getKind() === SyntaxKind.MethodDeclaration || declaration.getKind() === SyntaxKind.PropertyDeclaration) {
205
+ continue;
206
+ }
201
207
  const sourceFile = declaration.getSourceFile();
202
208
  const sourceFilePath = sourceFile.getFilePath();
209
+ if (/[/\\]typescript[/\\]lib[/\\]/.test(sourceFilePath)) {
210
+ continue;
211
+ }
203
212
  if (sourceFilePath.includes("node_modules")) {
213
+ if (functionSignatureSymbols.has(symbol)) {
214
+ const packageName = getPackageNameFromNodeModulesPath_(sourceFilePath);
215
+ if (packageName) {
216
+ processedSymbols.add(symbolName);
217
+ if (!importsMap.has(packageName)) {
218
+ importsMap.set(packageName, /* @__PURE__ */ new Set());
219
+ }
220
+ importsMap.get(packageName)?.add(symbolName);
221
+ }
222
+ }
204
223
  continue;
205
224
  }
206
225
  processedSymbols.add(symbolName);
@@ -68,11 +68,34 @@ const SIMPLE_TRIGGER_FUNCTION_NAMES = [
68
68
  "doGet",
69
69
  "doPost"
70
70
  ];
71
+ const getPackageNameFromNodeModulesPath_ = (filePath) => {
72
+ const normalizedPath = filePath.replace(/\\/g, "/");
73
+ const nodeModulesIndex = normalizedPath.lastIndexOf("node_modules/");
74
+ if (nodeModulesIndex === -1) {
75
+ return null;
76
+ }
77
+ const afterNodeModules = normalizedPath.slice(
78
+ nodeModulesIndex + "node_modules/".length
79
+ );
80
+ const parts = afterNodeModules.split("/");
81
+ if (parts.length === 0) {
82
+ return null;
83
+ }
84
+ if (parts[0].startsWith("@") && parts.length >= 2) {
85
+ const scopedName = `${parts[0]}/${parts[1]}`;
86
+ if (parts[0] === "@types") {
87
+ return parts[1];
88
+ }
89
+ return scopedName;
90
+ }
91
+ return parts[0];
92
+ };
71
93
  const generateAppsScriptTypes = async ({
72
94
  project: projectPath,
73
95
  srcDir,
74
96
  outDir,
75
- outputFile
97
+ outputFile,
98
+ projectInstance
76
99
  }) => {
77
100
  const absoluteSrcDir = path__namespace.resolve(projectPath, srcDir);
78
101
  const absoluteOutDir = path__namespace.resolve(projectPath, outDir);
@@ -80,7 +103,7 @@ const generateAppsScriptTypes = async ({
80
103
  consola.consola.info("Starting AppsScript type generation with gasnuki...");
81
104
  consola.consola.info(` AppsScript Source Directory: ${absoluteSrcDir}`);
82
105
  consola.consola.info(` Output File: ${absoluteOutputFile}`);
83
- const project = new tsMorph.Project({
106
+ const project = projectInstance ?? new tsMorph.Project({
84
107
  tsConfigFilePath: path__namespace.resolve(projectPath, "tsconfig.json"),
85
108
  skipAddingFilesFromTsConfig: true
86
109
  });
@@ -92,7 +115,6 @@ const generateAppsScriptTypes = async ({
92
115
  const methodDefinitions = [];
93
116
  const exportedDeclarations = [];
94
117
  const exportedDeclarationNames = /* @__PURE__ */ new Set();
95
- const exportedFunctions = [];
96
118
  for (const sourceFile of sourceFiles) {
97
119
  const filePath = sourceFile.getFilePath().replace(/\\/g, "/");
98
120
  const srcPath = absoluteSrcDir.replace(/\\/g, "/");
@@ -118,7 +140,6 @@ const generateAppsScriptTypes = async ({
118
140
  exportedDeclarations.push(func);
119
141
  exportedDeclarationNames.add(name);
120
142
  methodDefinitions.push(getInterfaceMethodDefinition_(name, func));
121
- exportedFunctions.push(func);
122
143
  }
123
144
  }
124
145
  for (const varStmt of sourceFile.getVariableStatements()) {
@@ -130,7 +151,6 @@ const generateAppsScriptTypes = async ({
130
151
  exportedDeclarations.push(varDecl);
131
152
  exportedDeclarationNames.add(name);
132
153
  methodDefinitions.push(getInterfaceMethodDefinition_(name, funcExpr));
133
- exportedFunctions.push(funcExpr);
134
154
  }
135
155
  }
136
156
  }
@@ -162,38 +182,21 @@ const generateAppsScriptTypes = async ({
162
182
  }
163
183
  }
164
184
  };
165
- const returnValueSymbols = /* @__PURE__ */ new Set();
166
- for (const func of exportedFunctions) {
167
- collectSymbolsFromType(func.getReturnType(), returnValueSymbols);
168
- }
185
+ const functionSignatureSymbols = /* @__PURE__ */ new Set();
169
186
  const symbolsToProcess = /* @__PURE__ */ new Set();
170
187
  for (const decl of exportedDeclarations) {
171
188
  if (decl.getKind() === tsMorph.SyntaxKind.FunctionDeclaration || decl.getKind() === tsMorph.SyntaxKind.VariableDeclaration && (decl.getInitializer()?.getKind() === tsMorph.SyntaxKind.ArrowFunction || decl.getInitializer()?.getKind() === tsMorph.SyntaxKind.FunctionExpression)) {
172
189
  const func = decl.getKind() === tsMorph.SyntaxKind.FunctionDeclaration ? decl : decl.getInitializer();
173
190
  const parameters = func.getParameters();
174
191
  for (const param of parameters) {
175
- const typeRefs = param.getDescendantsOfKind(tsMorph.SyntaxKind.TypeReference);
176
- for (const typeRef of typeRefs) {
177
- const symbol = typeRef.getType().getAliasSymbol() ?? typeRef.getType().getSymbol();
178
- if (symbol) symbolsToProcess.add(symbol);
179
- }
180
- }
181
- const returnTypeNode = func.getReturnTypeNode();
182
- if (returnTypeNode) {
183
- const typeRefs = returnTypeNode.getDescendantsOfKind(
184
- tsMorph.SyntaxKind.TypeReference
185
- );
186
- for (const typeRef of typeRefs) {
187
- const symbol = typeRef.getType().getAliasSymbol() ?? typeRef.getType().getSymbol();
188
- if (symbol) symbolsToProcess.add(symbol);
189
- }
192
+ collectSymbolsFromType(param.getType(), functionSignatureSymbols);
193
+ collectSymbolsFromType(param.getType(), symbolsToProcess);
190
194
  }
195
+ const returnType = func.getReturnType();
196
+ collectSymbolsFromType(returnType, functionSignatureSymbols);
197
+ collectSymbolsFromType(returnType, symbolsToProcess);
191
198
  } else if (decl.getKind() === tsMorph.SyntaxKind.InterfaceDeclaration || decl.getKind() === tsMorph.SyntaxKind.TypeAliasDeclaration) {
192
- const typeRefs = decl.getDescendantsOfKind(tsMorph.SyntaxKind.TypeReference);
193
- for (const typeRef of typeRefs) {
194
- const symbol = typeRef.getType().getAliasSymbol() ?? typeRef.getType().getSymbol();
195
- if (symbol) symbolsToProcess.add(symbol);
196
- }
199
+ collectSymbolsFromType(decl.getType(), symbolsToProcess);
197
200
  }
198
201
  }
199
202
  const importsMap = /* @__PURE__ */ new Map();
@@ -215,9 +218,25 @@ const generateAppsScriptTypes = async ({
215
218
  if (!declaration) {
216
219
  continue;
217
220
  }
221
+ if (declaration.getKind() === tsMorph.SyntaxKind.MethodSignature || declaration.getKind() === tsMorph.SyntaxKind.PropertySignature || declaration.getKind() === tsMorph.SyntaxKind.MethodDeclaration || declaration.getKind() === tsMorph.SyntaxKind.PropertyDeclaration) {
222
+ continue;
223
+ }
218
224
  const sourceFile = declaration.getSourceFile();
219
225
  const sourceFilePath = sourceFile.getFilePath();
226
+ if (/[/\\]typescript[/\\]lib[/\\]/.test(sourceFilePath)) {
227
+ continue;
228
+ }
220
229
  if (sourceFilePath.includes("node_modules")) {
230
+ if (functionSignatureSymbols.has(symbol)) {
231
+ const packageName = getPackageNameFromNodeModulesPath_(sourceFilePath);
232
+ if (packageName) {
233
+ processedSymbols.add(symbolName);
234
+ if (!importsMap.has(packageName)) {
235
+ importsMap.set(packageName, /* @__PURE__ */ new Set());
236
+ }
237
+ importsMap.get(packageName)?.add(symbolName);
238
+ }
239
+ }
221
240
  continue;
222
241
  }
223
242
  processedSymbols.add(symbolName);
package/dist/vite.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  const path = require('node:path');
4
4
  const consola = require('consola');
5
- const config = require('./shared/gasnuki.Cbwq1CES.cjs');
5
+ const config = require('./shared/gasnuki.D8w16Lbm.cjs');
6
6
  require('node:fs');
7
7
  require('ts-morph');
8
8
  require('jiti');
package/dist/vite.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as path from 'node:path';
2
2
  import { consola } from 'consola';
3
- import { l as loadConfig, g as generateAppsScriptTypes } from './shared/gasnuki.Bcijv2Ub.mjs';
3
+ import { l as loadConfig, g as generateAppsScriptTypes } from './shared/gasnuki.D1fp3Uiw.mjs';
4
4
  import 'node:fs';
5
5
  import 'ts-morph';
6
6
  import 'jiti';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ciderjs/gasnuki",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
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",
@@ -30,8 +30,8 @@
30
30
  "start": "node dist/cli.mjs -p playground/react -s src/server",
31
31
  "check": "biome check --write",
32
32
  "build": "unbuild",
33
- "test": "vitest run",
34
- "test:coverage": "vitest run --coverage",
33
+ "test": "vitest run --silent",
34
+ "test:coverage": "vitest run --coverage --silent",
35
35
  "update-coverage-badge": "jiti scripts/update-coverage-badge.ts README.md README.ja.md",
36
36
  "test:coverage:update": "pnpm test:coverage && pnpm update-coverage-badge",
37
37
  "prepublish": "pnpm run generate && pnpm run check && pnpm run test:coverage:update && pnpm run build",
@@ -55,20 +55,20 @@
55
55
  },
56
56
  "packageManager": "pnpm@10.18.3",
57
57
  "dependencies": {
58
- "chokidar": "^4.0.3",
59
- "commander": "^14.0.1",
58
+ "chokidar": "^5.0.0",
59
+ "commander": "^14.0.2",
60
60
  "consola": "^3.4.2",
61
61
  "jiti": "^2.6.1",
62
62
  "ts-morph": "^27.0.2"
63
63
  },
64
64
  "devDependencies": {
65
- "@biomejs/biome": "^2.2.6",
66
- "@types/node": "^24.8.0",
67
- "@vitest/coverage-v8": "3.2.4",
65
+ "@biomejs/biome": "^2.3.8",
66
+ "@types/node": "^25.0.1",
67
+ "@vitest/coverage-v8": "4.0.15",
68
68
  "typescript": "^5.9.3",
69
69
  "unbuild": "^3.6.1",
70
- "vite": "^7.1.10",
71
- "vitest": "3.2.4"
70
+ "vite": "^7.2.7",
71
+ "vitest": "4.0.15"
72
72
  },
73
73
  "peerDependencies": {
74
74
  "vite": "^7"
@@ -1,3 +0,0 @@
1
- {
2
- "cSpell.words": ["gasnuki"]
3
- }