@ciderjs/gasnuki 0.2.10 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +84 -1
- package/README.md +86 -1
- package/dist/cli.cjs +4 -3
- package/dist/cli.mjs +3 -2
- package/dist/index.cjs +71 -6
- package/dist/index.mjs +59 -4
- package/dist/shared/{gasnuki.CS974pL-.mjs → gasnuki.Bcijv2Ub.mjs} +27 -81
- package/dist/shared/{gasnuki.93G9yyCy.cjs → gasnuki.Cbwq1CES.cjs} +28 -83
- package/dist/vite.cjs +83 -0
- package/dist/vite.d.cts +11 -0
- package/dist/vite.d.mts +11 -0
- package/dist/vite.d.ts +11 -0
- package/dist/vite.mjs +67 -0
- package/package.json +17 -7
package/README.ja.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# gasnuki
|
|
2
2
|
|
|
3
|
-
[](https://github.com/luthpg/gasnuki)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://www.npmjs.com/package/@ciderjs/gasnuki)
|
|
6
6
|
[](https://github.com/luthpg/gasnuki/issues)
|
|
@@ -45,6 +45,35 @@ npx @ciderjs/gasnuki
|
|
|
45
45
|
|
|
46
46
|
デフォルトでは `types` ディレクトリに型定義ファイルが生成されます。
|
|
47
47
|
|
|
48
|
+
### Vite プラグインとしての使い方
|
|
49
|
+
|
|
50
|
+
Vite を使用している場合、`gasnuki` をプラグインとして統合し、サーバーサイドのファイルが変更されたときに自動で型定義を生成できます。
|
|
51
|
+
|
|
52
|
+
1. `vite` と `@ciderjs/gasnuki` をインストールします:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pnpm add -D vite @ciderjs/gasnuki
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
2. `vite.config.ts` にプラグインを追加します:
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { defineConfig } from 'vite';
|
|
62
|
+
import { gasnuki } from '@ciderjs/gasnuki/vite';
|
|
63
|
+
|
|
64
|
+
export default defineConfig({
|
|
65
|
+
plugins: [
|
|
66
|
+
gasnuki({
|
|
67
|
+
/* オプション */
|
|
68
|
+
}),
|
|
69
|
+
],
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
これで `vite dev` を実行すると、`gasnuki` がApps Scriptソースファイルの変更を自動的に監視し、型を再生成します。
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
48
77
|
2. 生成されたディレクトリ(デフォルト: `types`)を `tsconfig.json` の `include` に追加してください:
|
|
49
78
|
|
|
50
79
|
```jsonc
|
|
@@ -77,6 +106,60 @@ google.script.run
|
|
|
77
106
|
- Google Apps Script クライアントAPIの型定義
|
|
78
107
|
- サーバーサイド関数の戻り値型をvoidに変換するユーティリティ型
|
|
79
108
|
|
|
109
|
+
### Promiseベースのラッパー
|
|
110
|
+
|
|
111
|
+
`@ciderjs/gasnuki/promise` を利用すると、`google.script.run` をPromiseを返す型安全なラッパーとして使用できます。これにより、`async/await` を使ったモダンな非同期処理を記述できます。
|
|
112
|
+
|
|
113
|
+
1. まず、`gasnuki` で生成した型定義 (`ServerScripts`) と、`getPromisedServerScripts` 関数をインポートします。
|
|
114
|
+
|
|
115
|
+
```ts:lib/gas.ts
|
|
116
|
+
import { getPromisedServerScripts } from '@ciderjs/gasnuki/promise';
|
|
117
|
+
// gasnukiが生成した型定義のパスを指定します
|
|
118
|
+
import type { ServerScripts } from '../types/appsscript';
|
|
119
|
+
|
|
120
|
+
export const gas = getPromisedServerScripts<ServerScripts>();
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
2. 作成した `gas` オブジェクトを使って、サーバーサイド関数を `async/await` で呼び出します。
|
|
124
|
+
|
|
125
|
+
```ts:components/MyComponent.tsx
|
|
126
|
+
import { gas } from '../lib/gas';
|
|
127
|
+
|
|
128
|
+
async function fetchData() {
|
|
129
|
+
try {
|
|
130
|
+
// 'getContent' の引数と戻り値が型安全になります
|
|
131
|
+
const result = await gas.getContent('Sheet1');
|
|
132
|
+
console.log(result);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error(error);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### モックアップによる開発
|
|
140
|
+
|
|
141
|
+
`getPromisedServerScripts` にモック関数を渡すことで、`clasp push` をせずともフロントエンド開発を進めることができます。
|
|
142
|
+
|
|
143
|
+
```ts:lib/gas.ts
|
|
144
|
+
import {
|
|
145
|
+
getPromisedServerScripts,
|
|
146
|
+
type PartialScriptType,
|
|
147
|
+
} from '@ciderjs/gasnuki/promise';
|
|
148
|
+
import type { ServerScripts } from '../types/appsscript';
|
|
149
|
+
|
|
150
|
+
// 開発用のモック関数を定義します
|
|
151
|
+
const mockup: PartialScriptType<ServerScripts> = {
|
|
152
|
+
// sayHello関数の動作をシミュレート
|
|
153
|
+
sayHello: async (name) => {
|
|
154
|
+
await new Promise(resolve => setTimeout(resolve, 500)); // ネットワーク遅延を模倣
|
|
155
|
+
return `Hello from mockup, ${name}!`;
|
|
156
|
+
},
|
|
157
|
+
// 他の関数も同様にモックできます
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const gas = getPromisedServerScripts<ServerScripts>(mockup);
|
|
161
|
+
```
|
|
162
|
+
|
|
80
163
|
## コントリビュート
|
|
81
164
|
|
|
82
165
|
バグ報告やプルリクエストは歓迎します。
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @ciderjs/gasnuki
|
|
2
2
|
|
|
3
|
-
[](https://github.com/luthpg/gasnuki)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://www.npmjs.com/package/@ciderjs/gasnuki)
|
|
6
6
|
[](https://github.com/luthpg/gasnuki/issues)
|
|
@@ -44,6 +44,35 @@ npx @ciderjs/gasnuki
|
|
|
44
44
|
|
|
45
45
|
This will generate type definition files in the `types` directory by default.
|
|
46
46
|
|
|
47
|
+
### Vite Plugin Usage
|
|
48
|
+
|
|
49
|
+
If you are using Vite, you can integrate `gasnuki` as a plugin to automatically generate types when your server-side files change.
|
|
50
|
+
|
|
51
|
+
1. Install `vite` and `@ciderjs/gasnuki`:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pnpm add -D vite @ciderjs/gasnuki
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
2. Add the plugin to your `vite.config.ts`:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { defineConfig } from 'vite';
|
|
61
|
+
import { gasnuki } from '@ciderjs/gasnuki/vite';
|
|
62
|
+
|
|
63
|
+
export default defineConfig({
|
|
64
|
+
plugins: [
|
|
65
|
+
gasnuki({
|
|
66
|
+
/* options */
|
|
67
|
+
}),
|
|
68
|
+
],
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Now, when you run `vite dev`, `gasnuki` will automatically watch for changes in your Apps Script source files and regenerate the types.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
47
76
|
2. Make sure the generated directory (default: `types`) is included in your `tsconfig.json`:
|
|
48
77
|
|
|
49
78
|
```jsonc
|
|
@@ -76,6 +105,62 @@ google.script.run
|
|
|
76
105
|
- Type definitions for Google Apps Script client-side API
|
|
77
106
|
- Utility type to convert server-side function return types to void
|
|
78
107
|
|
|
108
|
+
### Promise-based Wrapper
|
|
109
|
+
|
|
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`.
|
|
111
|
+
|
|
112
|
+
1. First, import the type definitions (`ServerScripts`) generated by `gasnuki` and the `getPromisedServerScripts` function.
|
|
113
|
+
|
|
114
|
+
```ts:lib/gas.ts
|
|
115
|
+
import { getPromisedServerScripts } from '@ciderjs/gasnuki/promise';
|
|
116
|
+
// Specify the path to the type definitions generated by gasnuki
|
|
117
|
+
import type { ServerScripts } from '../types/appsscript';
|
|
118
|
+
|
|
119
|
+
export const gas = getPromisedServerScripts<ServerScripts>();
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
2. Use the created `gas` object to call your server-side functions with `async/await`.
|
|
123
|
+
|
|
124
|
+
```ts:components/MyComponent.tsx
|
|
125
|
+
import { gas } from '../lib/gas';
|
|
126
|
+
|
|
127
|
+
async function fetchData() {
|
|
128
|
+
try {
|
|
129
|
+
// The arguments and return value of 'getContent' are now type-safe!
|
|
130
|
+
const result = await gas.getContent('Sheet1');
|
|
131
|
+
console.log(result);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error(error);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### Development with Mockups
|
|
139
|
+
|
|
140
|
+
By passing mockup functions to `getPromisedServerScripts`, you can proceed with frontend development without needing to `clasp push` every time.
|
|
141
|
+
|
|
142
|
+
```ts:lib/gas.ts
|
|
143
|
+
import {
|
|
144
|
+
getPromisedServerScripts,
|
|
145
|
+
type PartialScriptType,
|
|
146
|
+
} from '@ciderjs/gasnuki/promise';
|
|
147
|
+
import type { ServerScripts } from '../types/appsscript';
|
|
148
|
+
|
|
149
|
+
// Define mockup functions for development
|
|
150
|
+
const mockup: PartialScriptType<ServerScripts> = {
|
|
151
|
+
// Simulate the behavior of the sayHello function
|
|
152
|
+
sayHello: async (name) => {
|
|
153
|
+
await new Promise(resolve => setTimeout(resolve, 500)); // Simulate network delay
|
|
154
|
+
return `Hello from mockup, ${name}!`;
|
|
155
|
+
},
|
|
156
|
+
// Other functions can be mocked similarly
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export const gas = getPromisedServerScripts<ServerScripts>(mockup);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
79
164
|
## Contributing
|
|
80
165
|
|
|
81
166
|
Bug reports and pull requests are welcome. Please use the `issues` or `pull requests` section.
|
package/dist/cli.cjs
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
const path = require('node:path');
|
|
5
5
|
const commander = require('commander');
|
|
6
|
-
const index = require('./
|
|
6
|
+
const index = require('./index.cjs');
|
|
7
|
+
const config = require('./shared/gasnuki.Cbwq1CES.cjs');
|
|
7
8
|
require('chokidar');
|
|
8
9
|
require('consola');
|
|
9
10
|
require('node:fs');
|
|
@@ -24,11 +25,11 @@ function _interopNamespaceCompat(e) {
|
|
|
24
25
|
|
|
25
26
|
const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
|
|
26
27
|
|
|
27
|
-
const version = "0.
|
|
28
|
+
const version = "0.3.1";
|
|
28
29
|
|
|
29
30
|
const parseArgs = async (command) => {
|
|
30
31
|
const cliOpts = command.opts();
|
|
31
|
-
const fileConfig = await
|
|
32
|
+
const fileConfig = await config.loadConfig(path__namespace.resolve(cliOpts.project));
|
|
32
33
|
const defaultOpts = {};
|
|
33
34
|
for (const option of command.options) {
|
|
34
35
|
const key = option.attributeName();
|
package/dist/cli.mjs
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import { Command } from 'commander';
|
|
4
|
-
import {
|
|
4
|
+
import { generateTypes } from './index.mjs';
|
|
5
|
+
import { l as loadConfig } from './shared/gasnuki.Bcijv2Ub.mjs';
|
|
5
6
|
import 'chokidar';
|
|
6
7
|
import 'consola';
|
|
7
8
|
import 'node:fs';
|
|
8
9
|
import 'ts-morph';
|
|
9
10
|
import 'jiti';
|
|
10
11
|
|
|
11
|
-
const version = "0.
|
|
12
|
+
const version = "0.3.1";
|
|
12
13
|
|
|
13
14
|
const parseArgs = async (command) => {
|
|
14
15
|
const cliOpts = command.opts();
|
package/dist/index.cjs
CHANGED
|
@@ -1,14 +1,79 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
require('node:path');
|
|
4
|
-
require('chokidar');
|
|
5
|
-
require('consola');
|
|
6
|
-
const
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const chokidar = require('chokidar');
|
|
5
|
+
const consola = require('consola');
|
|
6
|
+
const config = require('./shared/gasnuki.Cbwq1CES.cjs');
|
|
7
7
|
require('node:fs');
|
|
8
8
|
require('ts-morph');
|
|
9
9
|
require('jiti');
|
|
10
10
|
|
|
11
|
+
function _interopNamespaceCompat(e) {
|
|
12
|
+
if (e && typeof e === 'object' && 'default' in e) return e;
|
|
13
|
+
const n = Object.create(null);
|
|
14
|
+
if (e) {
|
|
15
|
+
for (const k in e) {
|
|
16
|
+
n[k] = e[k];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
n.default = e;
|
|
20
|
+
return n;
|
|
21
|
+
}
|
|
11
22
|
|
|
23
|
+
const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
|
|
24
|
+
const chokidar__namespace = /*#__PURE__*/_interopNamespaceCompat(chokidar);
|
|
12
25
|
|
|
13
|
-
|
|
14
|
-
|
|
26
|
+
const generateTypes = async ({
|
|
27
|
+
project,
|
|
28
|
+
srcDir,
|
|
29
|
+
outDir,
|
|
30
|
+
outputFile,
|
|
31
|
+
watch
|
|
32
|
+
}) => {
|
|
33
|
+
const runGeneration = async (triggeredBy) => {
|
|
34
|
+
const reason = triggeredBy ? ` (${triggeredBy})` : "";
|
|
35
|
+
consola.consola.info(`Generating AppsScript types${reason}...`);
|
|
36
|
+
try {
|
|
37
|
+
await config.generateAppsScriptTypes({ project, srcDir, outDir, outputFile });
|
|
38
|
+
consola.consola.info("Type generation complete.");
|
|
39
|
+
} catch (e) {
|
|
40
|
+
consola.consola.error(`Type generation failed: ${e.message}`, e);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
await runGeneration();
|
|
44
|
+
if (watch) {
|
|
45
|
+
const sourcePathToWatch = path__namespace.resolve(project, srcDir).replace(/\\/g, "/");
|
|
46
|
+
consola.consola.info(
|
|
47
|
+
`Watching for changes in ${sourcePathToWatch}... (Press Ctrl+C to stop)`
|
|
48
|
+
);
|
|
49
|
+
const watcher = chokidar__namespace.watch(sourcePathToWatch, {
|
|
50
|
+
ignored: ["node_modules", "dist"],
|
|
51
|
+
persistent: true,
|
|
52
|
+
ignoreInitial: true
|
|
53
|
+
});
|
|
54
|
+
const eventHandler = async (filePath, eventName) => {
|
|
55
|
+
consola.consola.info(`Watcher is called triggered on ${eventName}`);
|
|
56
|
+
const relativePath = path__namespace.relative(project, filePath);
|
|
57
|
+
await runGeneration(relativePath);
|
|
58
|
+
};
|
|
59
|
+
watcher.on("ready", async () => {
|
|
60
|
+
console.log("...waiting...");
|
|
61
|
+
watcher.on("all", async (event, path2) => {
|
|
62
|
+
consola.consola.info(`Watcher is called triggered on ${event}: ${path2}`);
|
|
63
|
+
await eventHandler(path2, event);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
67
|
+
process.on(signal, async () => {
|
|
68
|
+
await watcher.close();
|
|
69
|
+
consola.consola.info("Watcher is closed.");
|
|
70
|
+
process.exit(0);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
process.exit(0);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
exports.defineConfig = config.defineConfig;
|
|
79
|
+
exports.generateTypes = generateTypes;
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,62 @@
|
|
|
1
|
-
import 'node:path';
|
|
2
|
-
import 'chokidar';
|
|
3
|
-
import 'consola';
|
|
4
|
-
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
import * as chokidar from 'chokidar';
|
|
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';
|
|
5
6
|
import 'node:fs';
|
|
6
7
|
import 'ts-morph';
|
|
7
8
|
import 'jiti';
|
|
9
|
+
|
|
10
|
+
const generateTypes = async ({
|
|
11
|
+
project,
|
|
12
|
+
srcDir,
|
|
13
|
+
outDir,
|
|
14
|
+
outputFile,
|
|
15
|
+
watch
|
|
16
|
+
}) => {
|
|
17
|
+
const runGeneration = async (triggeredBy) => {
|
|
18
|
+
const reason = triggeredBy ? ` (${triggeredBy})` : "";
|
|
19
|
+
consola.info(`Generating AppsScript types${reason}...`);
|
|
20
|
+
try {
|
|
21
|
+
await generateAppsScriptTypes({ project, srcDir, outDir, outputFile });
|
|
22
|
+
consola.info("Type generation complete.");
|
|
23
|
+
} catch (e) {
|
|
24
|
+
consola.error(`Type generation failed: ${e.message}`, e);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
await runGeneration();
|
|
28
|
+
if (watch) {
|
|
29
|
+
const sourcePathToWatch = path.resolve(project, srcDir).replace(/\\/g, "/");
|
|
30
|
+
consola.info(
|
|
31
|
+
`Watching for changes in ${sourcePathToWatch}... (Press Ctrl+C to stop)`
|
|
32
|
+
);
|
|
33
|
+
const watcher = chokidar.watch(sourcePathToWatch, {
|
|
34
|
+
ignored: ["node_modules", "dist"],
|
|
35
|
+
persistent: true,
|
|
36
|
+
ignoreInitial: true
|
|
37
|
+
});
|
|
38
|
+
const eventHandler = async (filePath, eventName) => {
|
|
39
|
+
consola.info(`Watcher is called triggered on ${eventName}`);
|
|
40
|
+
const relativePath = path.relative(project, filePath);
|
|
41
|
+
await runGeneration(relativePath);
|
|
42
|
+
};
|
|
43
|
+
watcher.on("ready", async () => {
|
|
44
|
+
console.log("...waiting...");
|
|
45
|
+
watcher.on("all", async (event, path2) => {
|
|
46
|
+
consola.info(`Watcher is called triggered on ${event}: ${path2}`);
|
|
47
|
+
await eventHandler(path2, event);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
51
|
+
process.on(signal, async () => {
|
|
52
|
+
await watcher.close();
|
|
53
|
+
consola.info("Watcher is closed.");
|
|
54
|
+
process.exit(0);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
process.exit(0);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export { generateTypes };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
1
2
|
import * as path from 'node:path';
|
|
2
|
-
import * as chokidar from 'chokidar';
|
|
3
3
|
import { consola } from 'consola';
|
|
4
|
-
import * as fs from 'node:fs';
|
|
5
4
|
import { Project, SyntaxKind, SymbolFlags } from 'ts-morph';
|
|
6
5
|
import { createJiti } from 'jiti';
|
|
7
6
|
|
|
@@ -78,21 +77,27 @@ const generateAppsScriptTypes = async ({
|
|
|
78
77
|
const exportedDeclarationNames = /* @__PURE__ */ new Set();
|
|
79
78
|
const exportedFunctions = [];
|
|
80
79
|
for (const sourceFile of sourceFiles) {
|
|
80
|
+
const filePath = sourceFile.getFilePath().replace(/\\/g, "/");
|
|
81
|
+
const srcPath = absoluteSrcDir.replace(/\\/g, "/");
|
|
82
|
+
const projectRelativeSrcPath = path.join(projectPath, srcDir).replace(/\\/g, "/");
|
|
83
|
+
if (!filePath.startsWith(srcPath) && !filePath.startsWith(projectRelativeSrcPath)) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
81
86
|
for (const iface of sourceFile.getInterfaces()) {
|
|
82
|
-
if (
|
|
87
|
+
if (!iface.getName()?.endsWith("_")) {
|
|
83
88
|
exportedDeclarations.push(iface);
|
|
84
89
|
exportedDeclarationNames.add(iface.getName());
|
|
85
90
|
}
|
|
86
91
|
}
|
|
87
92
|
for (const typeAlias of sourceFile.getTypeAliases()) {
|
|
88
|
-
if (
|
|
93
|
+
if (!typeAlias.getName().endsWith("_")) {
|
|
89
94
|
exportedDeclarations.push(typeAlias);
|
|
90
95
|
exportedDeclarationNames.add(typeAlias.getName());
|
|
91
96
|
}
|
|
92
97
|
}
|
|
93
98
|
for (const func of sourceFile.getFunctions()) {
|
|
94
99
|
const name = func.getName();
|
|
95
|
-
if (
|
|
100
|
+
if (name && !name.endsWith("_") && !SIMPLE_TRIGGER_FUNCTION_NAMES.includes(name)) {
|
|
96
101
|
exportedDeclarations.push(func);
|
|
97
102
|
exportedDeclarationNames.add(name);
|
|
98
103
|
methodDefinitions.push(getInterfaceMethodDefinition_(name, func));
|
|
@@ -100,7 +105,6 @@ const generateAppsScriptTypes = async ({
|
|
|
100
105
|
}
|
|
101
106
|
}
|
|
102
107
|
for (const varStmt of sourceFile.getVariableStatements()) {
|
|
103
|
-
if (!varStmt.isExported()) continue;
|
|
104
108
|
for (const varDecl of varStmt.getDeclarations()) {
|
|
105
109
|
const name = varDecl.getName();
|
|
106
110
|
const initializer = varDecl.getInitializer();
|
|
@@ -195,31 +199,14 @@ const generateAppsScriptTypes = async ({
|
|
|
195
199
|
continue;
|
|
196
200
|
}
|
|
197
201
|
const sourceFile = declaration.getSourceFile();
|
|
198
|
-
|
|
202
|
+
const sourceFilePath = sourceFile.getFilePath();
|
|
203
|
+
if (sourceFilePath.includes("node_modules")) {
|
|
199
204
|
continue;
|
|
200
205
|
}
|
|
201
206
|
processedSymbols.add(symbolName);
|
|
202
|
-
const
|
|
203
|
-
if (
|
|
204
|
-
|
|
205
|
-
const declText = declaration.getText();
|
|
206
|
-
inlineDefinitions.set(symbolName, declText);
|
|
207
|
-
const tempSourceFile = project.createSourceFile(
|
|
208
|
-
`__temp_${symbolName}.ts`,
|
|
209
|
-
declText
|
|
210
|
-
);
|
|
211
|
-
for (const descendant of tempSourceFile.getDescendantsOfKind(
|
|
212
|
-
SyntaxKind.TypeReference
|
|
213
|
-
)) {
|
|
214
|
-
const newSymbol = descendant.getType().getAliasSymbol() ?? descendant.getType().getSymbol();
|
|
215
|
-
if (newSymbol) {
|
|
216
|
-
symbolsToProcess.add(newSymbol);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
tempSourceFile.delete();
|
|
220
|
-
}
|
|
221
|
-
} else {
|
|
222
|
-
let modulePath = path.relative(absoluteOutDir, sourceFile.getFilePath()).replace(/\\/g, "/");
|
|
207
|
+
const isExternal = !sourceFilePath.replace(/\\/g, "/").startsWith(absoluteSrcDir.replace(/\\/g, "/")) && !sourceFilePath.replace(/\\/g, "/").startsWith(path.join(projectPath, srcDir).replace(/\\/g, "/"));
|
|
208
|
+
if (isExternal) {
|
|
209
|
+
let modulePath = path.relative(absoluteOutDir, sourceFilePath).replace(/\\/g, "/");
|
|
223
210
|
modulePath = modulePath.replace(/\.(d\.)?ts$/, "");
|
|
224
211
|
if (modulePath.endsWith("/index")) {
|
|
225
212
|
modulePath = modulePath.slice(0, -6);
|
|
@@ -234,6 +221,17 @@ const generateAppsScriptTypes = async ({
|
|
|
234
221
|
importsMap.set(modulePath, /* @__PURE__ */ new Set());
|
|
235
222
|
}
|
|
236
223
|
importsMap.get(modulePath)?.add(symbolName);
|
|
224
|
+
} else {
|
|
225
|
+
const declText = declaration.getText();
|
|
226
|
+
inlineDefinitions.set(symbolName, declText);
|
|
227
|
+
}
|
|
228
|
+
for (const descendant of declaration.getDescendantsOfKind(
|
|
229
|
+
SyntaxKind.TypeReference
|
|
230
|
+
)) {
|
|
231
|
+
const newSymbol = descendant.getType().getAliasSymbol() ?? descendant.getType().getSymbol();
|
|
232
|
+
if (newSymbol) {
|
|
233
|
+
symbolsToProcess.add(newSymbol);
|
|
234
|
+
}
|
|
237
235
|
}
|
|
238
236
|
}
|
|
239
237
|
if (!fs.existsSync(absoluteOutDir)) {
|
|
@@ -334,56 +332,4 @@ async function loadConfig(projectRoot) {
|
|
|
334
332
|
}
|
|
335
333
|
}
|
|
336
334
|
|
|
337
|
-
|
|
338
|
-
project,
|
|
339
|
-
srcDir,
|
|
340
|
-
outDir,
|
|
341
|
-
outputFile,
|
|
342
|
-
watch
|
|
343
|
-
}) => {
|
|
344
|
-
const runGeneration = async (triggeredBy) => {
|
|
345
|
-
const reason = triggeredBy ? ` (${triggeredBy})` : "";
|
|
346
|
-
consola.info(`Generating AppsScript types${reason}...`);
|
|
347
|
-
try {
|
|
348
|
-
await generateAppsScriptTypes({ project, srcDir, outDir, outputFile });
|
|
349
|
-
consola.info("Type generation complete.");
|
|
350
|
-
} catch (e) {
|
|
351
|
-
consola.error(`Type generation failed: ${e.message}`, e);
|
|
352
|
-
}
|
|
353
|
-
};
|
|
354
|
-
await runGeneration();
|
|
355
|
-
if (watch) {
|
|
356
|
-
const sourcePathToWatch = path.resolve(project, srcDir).replace(/\\/g, "/");
|
|
357
|
-
consola.info(
|
|
358
|
-
`Watching for changes in ${sourcePathToWatch}... (Press Ctrl+C to stop)`
|
|
359
|
-
);
|
|
360
|
-
const watcher = chokidar.watch(sourcePathToWatch, {
|
|
361
|
-
ignored: ["node_modules", "dist"],
|
|
362
|
-
persistent: true,
|
|
363
|
-
ignoreInitial: true
|
|
364
|
-
});
|
|
365
|
-
const eventHandler = async (filePath, eventName) => {
|
|
366
|
-
consola.info(`Watcher is called triggered on ${eventName}`);
|
|
367
|
-
const relativePath = path.relative(project, filePath);
|
|
368
|
-
await runGeneration(relativePath);
|
|
369
|
-
};
|
|
370
|
-
watcher.on("ready", async () => {
|
|
371
|
-
console.log("...waiting...");
|
|
372
|
-
watcher.on("all", async (event, path2) => {
|
|
373
|
-
consola.info(`Watcher is called triggered on ${event}: ${path2}`);
|
|
374
|
-
await eventHandler(path2, event);
|
|
375
|
-
});
|
|
376
|
-
});
|
|
377
|
-
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
378
|
-
process.on(signal, async () => {
|
|
379
|
-
await watcher.close();
|
|
380
|
-
consola.info("Watcher is closed.");
|
|
381
|
-
process.exit(0);
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
} else {
|
|
385
|
-
process.exit(0);
|
|
386
|
-
}
|
|
387
|
-
};
|
|
388
|
-
|
|
389
|
-
export { defineConfig as d, generateTypes as g, loadConfig as l };
|
|
335
|
+
export { defineConfig as d, generateAppsScriptTypes as g, loadConfig as l };
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const fs = require('node:fs');
|
|
3
4
|
const path = require('node:path');
|
|
4
|
-
const chokidar = require('chokidar');
|
|
5
5
|
const consola = require('consola');
|
|
6
|
-
const fs = require('node:fs');
|
|
7
6
|
const tsMorph = require('ts-morph');
|
|
8
7
|
const jiti = require('jiti');
|
|
9
8
|
|
|
@@ -19,9 +18,8 @@ function _interopNamespaceCompat(e) {
|
|
|
19
18
|
return n;
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
|
|
23
|
-
const chokidar__namespace = /*#__PURE__*/_interopNamespaceCompat(chokidar);
|
|
24
21
|
const fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
|
|
22
|
+
const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
|
|
25
23
|
|
|
26
24
|
const text = "export 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 _WebAppLocationType {\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: (callback: (location: _WebAppLocationType) => void) => void;\n };\n history: {\n push: _AppsScriptHistoryFunction;\n replace: _AppsScriptHistoryFunction;\n setChangeHandler: (\n callback: (e: { state: object; location: _WebAppLocationType }) => void,\n ) => void;\n };\n };\n}\n\ndeclare global {\n const google: GoogleClientSideApi;\n}\n";
|
|
27
25
|
|
|
@@ -96,21 +94,27 @@ const generateAppsScriptTypes = async ({
|
|
|
96
94
|
const exportedDeclarationNames = /* @__PURE__ */ new Set();
|
|
97
95
|
const exportedFunctions = [];
|
|
98
96
|
for (const sourceFile of sourceFiles) {
|
|
97
|
+
const filePath = sourceFile.getFilePath().replace(/\\/g, "/");
|
|
98
|
+
const srcPath = absoluteSrcDir.replace(/\\/g, "/");
|
|
99
|
+
const projectRelativeSrcPath = path__namespace.join(projectPath, srcDir).replace(/\\/g, "/");
|
|
100
|
+
if (!filePath.startsWith(srcPath) && !filePath.startsWith(projectRelativeSrcPath)) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
99
103
|
for (const iface of sourceFile.getInterfaces()) {
|
|
100
|
-
if (
|
|
104
|
+
if (!iface.getName()?.endsWith("_")) {
|
|
101
105
|
exportedDeclarations.push(iface);
|
|
102
106
|
exportedDeclarationNames.add(iface.getName());
|
|
103
107
|
}
|
|
104
108
|
}
|
|
105
109
|
for (const typeAlias of sourceFile.getTypeAliases()) {
|
|
106
|
-
if (
|
|
110
|
+
if (!typeAlias.getName().endsWith("_")) {
|
|
107
111
|
exportedDeclarations.push(typeAlias);
|
|
108
112
|
exportedDeclarationNames.add(typeAlias.getName());
|
|
109
113
|
}
|
|
110
114
|
}
|
|
111
115
|
for (const func of sourceFile.getFunctions()) {
|
|
112
116
|
const name = func.getName();
|
|
113
|
-
if (
|
|
117
|
+
if (name && !name.endsWith("_") && !SIMPLE_TRIGGER_FUNCTION_NAMES.includes(name)) {
|
|
114
118
|
exportedDeclarations.push(func);
|
|
115
119
|
exportedDeclarationNames.add(name);
|
|
116
120
|
methodDefinitions.push(getInterfaceMethodDefinition_(name, func));
|
|
@@ -118,7 +122,6 @@ const generateAppsScriptTypes = async ({
|
|
|
118
122
|
}
|
|
119
123
|
}
|
|
120
124
|
for (const varStmt of sourceFile.getVariableStatements()) {
|
|
121
|
-
if (!varStmt.isExported()) continue;
|
|
122
125
|
for (const varDecl of varStmt.getDeclarations()) {
|
|
123
126
|
const name = varDecl.getName();
|
|
124
127
|
const initializer = varDecl.getInitializer();
|
|
@@ -213,31 +216,14 @@ const generateAppsScriptTypes = async ({
|
|
|
213
216
|
continue;
|
|
214
217
|
}
|
|
215
218
|
const sourceFile = declaration.getSourceFile();
|
|
216
|
-
|
|
219
|
+
const sourceFilePath = sourceFile.getFilePath();
|
|
220
|
+
if (sourceFilePath.includes("node_modules")) {
|
|
217
221
|
continue;
|
|
218
222
|
}
|
|
219
223
|
processedSymbols.add(symbolName);
|
|
220
|
-
const
|
|
221
|
-
if (
|
|
222
|
-
|
|
223
|
-
const declText = declaration.getText();
|
|
224
|
-
inlineDefinitions.set(symbolName, declText);
|
|
225
|
-
const tempSourceFile = project.createSourceFile(
|
|
226
|
-
`__temp_${symbolName}.ts`,
|
|
227
|
-
declText
|
|
228
|
-
);
|
|
229
|
-
for (const descendant of tempSourceFile.getDescendantsOfKind(
|
|
230
|
-
tsMorph.SyntaxKind.TypeReference
|
|
231
|
-
)) {
|
|
232
|
-
const newSymbol = descendant.getType().getAliasSymbol() ?? descendant.getType().getSymbol();
|
|
233
|
-
if (newSymbol) {
|
|
234
|
-
symbolsToProcess.add(newSymbol);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
tempSourceFile.delete();
|
|
238
|
-
}
|
|
239
|
-
} else {
|
|
240
|
-
let modulePath = path__namespace.relative(absoluteOutDir, sourceFile.getFilePath()).replace(/\\/g, "/");
|
|
224
|
+
const isExternal = !sourceFilePath.replace(/\\/g, "/").startsWith(absoluteSrcDir.replace(/\\/g, "/")) && !sourceFilePath.replace(/\\/g, "/").startsWith(path__namespace.join(projectPath, srcDir).replace(/\\/g, "/"));
|
|
225
|
+
if (isExternal) {
|
|
226
|
+
let modulePath = path__namespace.relative(absoluteOutDir, sourceFilePath).replace(/\\/g, "/");
|
|
241
227
|
modulePath = modulePath.replace(/\.(d\.)?ts$/, "");
|
|
242
228
|
if (modulePath.endsWith("/index")) {
|
|
243
229
|
modulePath = modulePath.slice(0, -6);
|
|
@@ -252,6 +238,17 @@ const generateAppsScriptTypes = async ({
|
|
|
252
238
|
importsMap.set(modulePath, /* @__PURE__ */ new Set());
|
|
253
239
|
}
|
|
254
240
|
importsMap.get(modulePath)?.add(symbolName);
|
|
241
|
+
} else {
|
|
242
|
+
const declText = declaration.getText();
|
|
243
|
+
inlineDefinitions.set(symbolName, declText);
|
|
244
|
+
}
|
|
245
|
+
for (const descendant of declaration.getDescendantsOfKind(
|
|
246
|
+
tsMorph.SyntaxKind.TypeReference
|
|
247
|
+
)) {
|
|
248
|
+
const newSymbol = descendant.getType().getAliasSymbol() ?? descendant.getType().getSymbol();
|
|
249
|
+
if (newSymbol) {
|
|
250
|
+
symbolsToProcess.add(newSymbol);
|
|
251
|
+
}
|
|
255
252
|
}
|
|
256
253
|
}
|
|
257
254
|
if (!fs__namespace.existsSync(absoluteOutDir)) {
|
|
@@ -352,58 +349,6 @@ async function loadConfig(projectRoot) {
|
|
|
352
349
|
}
|
|
353
350
|
}
|
|
354
351
|
|
|
355
|
-
const generateTypes = async ({
|
|
356
|
-
project,
|
|
357
|
-
srcDir,
|
|
358
|
-
outDir,
|
|
359
|
-
outputFile,
|
|
360
|
-
watch
|
|
361
|
-
}) => {
|
|
362
|
-
const runGeneration = async (triggeredBy) => {
|
|
363
|
-
const reason = triggeredBy ? ` (${triggeredBy})` : "";
|
|
364
|
-
consola.consola.info(`Generating AppsScript types${reason}...`);
|
|
365
|
-
try {
|
|
366
|
-
await generateAppsScriptTypes({ project, srcDir, outDir, outputFile });
|
|
367
|
-
consola.consola.info("Type generation complete.");
|
|
368
|
-
} catch (e) {
|
|
369
|
-
consola.consola.error(`Type generation failed: ${e.message}`, e);
|
|
370
|
-
}
|
|
371
|
-
};
|
|
372
|
-
await runGeneration();
|
|
373
|
-
if (watch) {
|
|
374
|
-
const sourcePathToWatch = path__namespace.resolve(project, srcDir).replace(/\\/g, "/");
|
|
375
|
-
consola.consola.info(
|
|
376
|
-
`Watching for changes in ${sourcePathToWatch}... (Press Ctrl+C to stop)`
|
|
377
|
-
);
|
|
378
|
-
const watcher = chokidar__namespace.watch(sourcePathToWatch, {
|
|
379
|
-
ignored: ["node_modules", "dist"],
|
|
380
|
-
persistent: true,
|
|
381
|
-
ignoreInitial: true
|
|
382
|
-
});
|
|
383
|
-
const eventHandler = async (filePath, eventName) => {
|
|
384
|
-
consola.consola.info(`Watcher is called triggered on ${eventName}`);
|
|
385
|
-
const relativePath = path__namespace.relative(project, filePath);
|
|
386
|
-
await runGeneration(relativePath);
|
|
387
|
-
};
|
|
388
|
-
watcher.on("ready", async () => {
|
|
389
|
-
console.log("...waiting...");
|
|
390
|
-
watcher.on("all", async (event, path2) => {
|
|
391
|
-
consola.consola.info(`Watcher is called triggered on ${event}: ${path2}`);
|
|
392
|
-
await eventHandler(path2, event);
|
|
393
|
-
});
|
|
394
|
-
});
|
|
395
|
-
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
396
|
-
process.on(signal, async () => {
|
|
397
|
-
await watcher.close();
|
|
398
|
-
consola.consola.info("Watcher is closed.");
|
|
399
|
-
process.exit(0);
|
|
400
|
-
});
|
|
401
|
-
}
|
|
402
|
-
} else {
|
|
403
|
-
process.exit(0);
|
|
404
|
-
}
|
|
405
|
-
};
|
|
406
|
-
|
|
407
352
|
exports.defineConfig = defineConfig;
|
|
408
|
-
exports.
|
|
353
|
+
exports.generateAppsScriptTypes = generateAppsScriptTypes;
|
|
409
354
|
exports.loadConfig = loadConfig;
|
package/dist/vite.cjs
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const consola = require('consola');
|
|
5
|
+
const config = require('./shared/gasnuki.Cbwq1CES.cjs');
|
|
6
|
+
require('node:fs');
|
|
7
|
+
require('ts-morph');
|
|
8
|
+
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
|
+
|
|
24
|
+
function gasnuki(options) {
|
|
25
|
+
let projectRoot;
|
|
26
|
+
let gasnukiOptions;
|
|
27
|
+
let debounceTimer = null;
|
|
28
|
+
const debounce = (func, timeout = 300) => {
|
|
29
|
+
if (debounceTimer) {
|
|
30
|
+
clearTimeout(debounceTimer);
|
|
31
|
+
}
|
|
32
|
+
debounceTimer = setTimeout(func, timeout);
|
|
33
|
+
};
|
|
34
|
+
const runGeneration = (triggeredBy) => {
|
|
35
|
+
debounce(async () => {
|
|
36
|
+
const reason = triggeredBy ? ` (triggered by: ${triggeredBy})` : "";
|
|
37
|
+
console.log("");
|
|
38
|
+
consola.consola.info(`[gasnuki] Generating AppsScript types${reason}...`);
|
|
39
|
+
try {
|
|
40
|
+
await config.generateAppsScriptTypes({
|
|
41
|
+
...gasnukiOptions,
|
|
42
|
+
project: projectRoot
|
|
43
|
+
});
|
|
44
|
+
consola.consola.success("[gasnuki] Type generation complete.");
|
|
45
|
+
} catch (e) {
|
|
46
|
+
consola.consola.error(
|
|
47
|
+
`[gasnuki] Type generation failed: ${e.message}`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
name: "vite-plugin-gasnuki",
|
|
54
|
+
apply: "serve",
|
|
55
|
+
// Apply only in serve mode
|
|
56
|
+
async configResolved(config$1) {
|
|
57
|
+
projectRoot = config$1.root;
|
|
58
|
+
const fileConfig = await config.loadConfig(projectRoot);
|
|
59
|
+
const defaultOptions = {
|
|
60
|
+
srcDir: "server",
|
|
61
|
+
outDir: "types",
|
|
62
|
+
outputFile: "appsscript.ts"
|
|
63
|
+
};
|
|
64
|
+
gasnukiOptions = {
|
|
65
|
+
...defaultOptions,
|
|
66
|
+
...fileConfig,
|
|
67
|
+
...options || {}
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
async configureServer(server) {
|
|
71
|
+
const targetDir = path__namespace.resolve(projectRoot, gasnukiOptions.srcDir);
|
|
72
|
+
runGeneration("server startup");
|
|
73
|
+
server.watcher.on("all", (_event, filePath) => {
|
|
74
|
+
const relativePath = path__namespace.relative(targetDir, filePath);
|
|
75
|
+
if (!relativePath.startsWith("..") && relativePath !== "..") {
|
|
76
|
+
runGeneration(path__namespace.relative(projectRoot, filePath));
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
exports.gasnuki = gasnuki;
|
package/dist/vite.d.cts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
import { UserConfig } from './index.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A factory function to create the gasnuki Vite plugin.
|
|
6
|
+
* @param options - The user-defined configuration for gasnuki.
|
|
7
|
+
* @returns The Vite plugin object.
|
|
8
|
+
*/
|
|
9
|
+
declare function gasnuki(options?: UserConfig): Plugin;
|
|
10
|
+
|
|
11
|
+
export { gasnuki };
|
package/dist/vite.d.mts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
import { UserConfig } from './index.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A factory function to create the gasnuki Vite plugin.
|
|
6
|
+
* @param options - The user-defined configuration for gasnuki.
|
|
7
|
+
* @returns The Vite plugin object.
|
|
8
|
+
*/
|
|
9
|
+
declare function gasnuki(options?: UserConfig): Plugin;
|
|
10
|
+
|
|
11
|
+
export { gasnuki };
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
import { UserConfig } from './index.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A factory function to create the gasnuki Vite plugin.
|
|
6
|
+
* @param options - The user-defined configuration for gasnuki.
|
|
7
|
+
* @returns The Vite plugin object.
|
|
8
|
+
*/
|
|
9
|
+
declare function gasnuki(options?: UserConfig): Plugin;
|
|
10
|
+
|
|
11
|
+
export { gasnuki };
|
package/dist/vite.mjs
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
import { consola } from 'consola';
|
|
3
|
+
import { l as loadConfig, g as generateAppsScriptTypes } from './shared/gasnuki.Bcijv2Ub.mjs';
|
|
4
|
+
import 'node:fs';
|
|
5
|
+
import 'ts-morph';
|
|
6
|
+
import 'jiti';
|
|
7
|
+
|
|
8
|
+
function gasnuki(options) {
|
|
9
|
+
let projectRoot;
|
|
10
|
+
let gasnukiOptions;
|
|
11
|
+
let debounceTimer = null;
|
|
12
|
+
const debounce = (func, timeout = 300) => {
|
|
13
|
+
if (debounceTimer) {
|
|
14
|
+
clearTimeout(debounceTimer);
|
|
15
|
+
}
|
|
16
|
+
debounceTimer = setTimeout(func, timeout);
|
|
17
|
+
};
|
|
18
|
+
const runGeneration = (triggeredBy) => {
|
|
19
|
+
debounce(async () => {
|
|
20
|
+
const reason = triggeredBy ? ` (triggered by: ${triggeredBy})` : "";
|
|
21
|
+
console.log("");
|
|
22
|
+
consola.info(`[gasnuki] Generating AppsScript types${reason}...`);
|
|
23
|
+
try {
|
|
24
|
+
await generateAppsScriptTypes({
|
|
25
|
+
...gasnukiOptions,
|
|
26
|
+
project: projectRoot
|
|
27
|
+
});
|
|
28
|
+
consola.success("[gasnuki] Type generation complete.");
|
|
29
|
+
} catch (e) {
|
|
30
|
+
consola.error(
|
|
31
|
+
`[gasnuki] Type generation failed: ${e.message}`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
return {
|
|
37
|
+
name: "vite-plugin-gasnuki",
|
|
38
|
+
apply: "serve",
|
|
39
|
+
// Apply only in serve mode
|
|
40
|
+
async configResolved(config) {
|
|
41
|
+
projectRoot = config.root;
|
|
42
|
+
const fileConfig = await loadConfig(projectRoot);
|
|
43
|
+
const defaultOptions = {
|
|
44
|
+
srcDir: "server",
|
|
45
|
+
outDir: "types",
|
|
46
|
+
outputFile: "appsscript.ts"
|
|
47
|
+
};
|
|
48
|
+
gasnukiOptions = {
|
|
49
|
+
...defaultOptions,
|
|
50
|
+
...fileConfig,
|
|
51
|
+
...options || {}
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
async configureServer(server) {
|
|
55
|
+
const targetDir = path.resolve(projectRoot, gasnukiOptions.srcDir);
|
|
56
|
+
runGeneration("server startup");
|
|
57
|
+
server.watcher.on("all", (_event, filePath) => {
|
|
58
|
+
const relativePath = path.relative(targetDir, filePath);
|
|
59
|
+
if (!relativePath.startsWith("..") && relativePath !== "..") {
|
|
60
|
+
runGeneration(path.relative(projectRoot, filePath));
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export { gasnuki };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ciderjs/gasnuki",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
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",
|
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
"types": "./dist/promise.d.ts",
|
|
18
18
|
"import": "./dist/promise.mjs",
|
|
19
19
|
"require": "./dist/promise.cjs"
|
|
20
|
+
},
|
|
21
|
+
"./vite": {
|
|
22
|
+
"types": "./dist/vite.d.ts",
|
|
23
|
+
"import": "./dist/vite.mjs",
|
|
24
|
+
"require": "./dist/vite.cjs"
|
|
20
25
|
}
|
|
21
26
|
},
|
|
22
27
|
"scripts": {
|
|
@@ -31,6 +36,7 @@
|
|
|
31
36
|
"test:coverage:update": "pnpm test:coverage && pnpm update-coverage-badge",
|
|
32
37
|
"prepublish": "pnpm run generate && pnpm run check && pnpm run test:coverage:update && pnpm run build",
|
|
33
38
|
"pg:react": "pnpm -C playground/react",
|
|
39
|
+
"pg:react-vite": "pnpm -C playground/react-with-vite-plugin",
|
|
34
40
|
"pg:vue": "pnpm -C playground/vue3"
|
|
35
41
|
},
|
|
36
42
|
"keywords": [
|
|
@@ -47,20 +53,24 @@
|
|
|
47
53
|
"bugs": {
|
|
48
54
|
"url": "https://github.com/luthpg/gasnuki/issues"
|
|
49
55
|
},
|
|
50
|
-
"packageManager": "pnpm@10.
|
|
56
|
+
"packageManager": "pnpm@10.18.3",
|
|
51
57
|
"dependencies": {
|
|
52
58
|
"chokidar": "^4.0.3",
|
|
53
59
|
"commander": "^14.0.1",
|
|
54
60
|
"consola": "^3.4.2",
|
|
55
|
-
"jiti": "^2.
|
|
56
|
-
"ts-morph": "^27.0.
|
|
61
|
+
"jiti": "^2.6.1",
|
|
62
|
+
"ts-morph": "^27.0.2"
|
|
57
63
|
},
|
|
58
64
|
"devDependencies": {
|
|
59
|
-
"@biomejs/biome": "^2.2.
|
|
60
|
-
"@types/node": "^24.
|
|
65
|
+
"@biomejs/biome": "^2.2.6",
|
|
66
|
+
"@types/node": "^24.8.0",
|
|
61
67
|
"@vitest/coverage-v8": "3.2.4",
|
|
62
|
-
"typescript": "^5.9.
|
|
68
|
+
"typescript": "^5.9.3",
|
|
63
69
|
"unbuild": "^3.6.1",
|
|
70
|
+
"vite": "^7.1.10",
|
|
64
71
|
"vitest": "3.2.4"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"vite": "^7"
|
|
65
75
|
}
|
|
66
76
|
}
|