@ciderjs/gasnuki 0.2.4 → 0.2.6

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,6 +1,6 @@
1
1
  # gasnuki
2
2
 
3
- [![Test Coverage](https://img.shields.io/badge/test%20coverage-87.76%25-green)](https://github.com/luthpg/gasnuki)
3
+ [![Test Coverage](https://img.shields.io/badge/test%20coverage-77.03%25-yellowgreen)](https://github.com/luthpg/gasnuki)
4
4
  [![License](https://img.shields.io/badge/license-ISC-blue.svg)](LICENSE)
5
5
  [![npm version](https://img.shields.io/npm/v/@ciderjs/gasnuki.svg)](https://www.npmjs.com/package/@ciderjs/gasnuki)
6
6
  [![GitHub issues](https://img.shields.io/github/issues/luthpg/gasnuki.svg)](https://github.com/luthpg/gasnuki/issues)
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @ciderjs/gasnuki
2
2
 
3
- [![Test Coverage](https://img.shields.io/badge/test%20coverage-87.76%25-green)](https://github.com/luthpg/gasnuki)
3
+ [![Test Coverage](https://img.shields.io/badge/test%20coverage-77.03%25-yellowgreen)](https://github.com/luthpg/gasnuki)
4
4
  [![License](https://img.shields.io/badge/license-ISC-blue.svg)](LICENSE)
5
5
  [![npm version](https://img.shields.io/npm/v/@ciderjs/gasnuki.svg)](https://www.npmjs.com/package/@ciderjs/gasnuki)
6
6
  [![GitHub issues](https://img.shields.io/github/issues/luthpg/gasnuki.svg)](https://github.com/luthpg/gasnuki/issues)
package/dist/cli.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  const path = require('node:path');
5
5
  const commander = require('commander');
6
- const index = require('./shared/gasnuki.CYh0jbl5.cjs');
6
+ const index = require('./shared/gasnuki.DH8w-v3n.cjs');
7
7
  require('chokidar');
8
8
  require('consola');
9
9
  require('node:fs');
@@ -24,7 +24,7 @@ function _interopNamespaceCompat(e) {
24
24
 
25
25
  const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
26
26
 
27
- const version = "0.2.4";
27
+ const version = "0.2.6";
28
28
 
29
29
  const parseArgs = async (command) => {
30
30
  const cliOpts = command.opts();
package/dist/cli.mjs CHANGED
@@ -1,14 +1,14 @@
1
1
  #! /usr/bin/env node
2
2
  import * as path from 'node:path';
3
3
  import { Command } from 'commander';
4
- import { l as loadConfig, g as generateTypes } from './shared/gasnuki.DvpVGJ1U.mjs';
4
+ import { l as loadConfig, g as generateTypes } from './shared/gasnuki.DgQBiLxg.mjs';
5
5
  import 'chokidar';
6
6
  import 'consola';
7
7
  import 'node:fs';
8
8
  import 'ts-morph';
9
9
  import 'jiti';
10
10
 
11
- const version = "0.2.4";
11
+ const version = "0.2.6";
12
12
 
13
13
  const parseArgs = async (command) => {
14
14
  const cliOpts = command.opts();
package/dist/index.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
  require('node:path');
4
4
  require('chokidar');
5
5
  require('consola');
6
- const index = require('./shared/gasnuki.CYh0jbl5.cjs');
6
+ const index = require('./shared/gasnuki.DH8w-v3n.cjs');
7
7
  require('node:fs');
8
8
  require('ts-morph');
9
9
  require('jiti');
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import 'node:path';
2
2
  import 'chokidar';
3
3
  import 'consola';
4
- export { d as defineConfig, g as generateTypes } from './shared/gasnuki.DvpVGJ1U.mjs';
4
+ export { d as defineConfig, g as generateTypes } from './shared/gasnuki.DgQBiLxg.mjs';
5
5
  import 'node:fs';
6
6
  import 'ts-morph';
7
7
  import 'jiti';
@@ -47,29 +47,17 @@ const getInterfaceMethodDefinition_ = (name, node) => {
47
47
  }
48
48
  }
49
49
  let jsDocString = "";
50
- const jsDocOwner = "getJsDocs" in node ? node : "getParantOrThrow" in node && // @ts-expect-error variable declaration
50
+ const jsDocOwner = "getJsDocs" in node ? node : "getParentOrThrow" in node && // @ts-expect-error variable declaration
51
51
  node.getParentOrThrow().getKind() === tsMorph.SyntaxKind.VariableDeclaration ? (
52
52
  // @ts-expect-error variable declaration
53
53
  node.getParentOrThrow()
54
54
  ) : null;
55
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()}
56
+ const jsDocs = "getJsDocs" in jsDocOwner ? jsDocOwner.getJsDocs() : [];
57
+ if (jsDocs.length > 0) {
58
+ const firstDoc = jsDocs[0];
59
+ jsDocString = `${firstDoc.getFullText().trim()}
70
60
  `;
71
- }
72
- }
73
61
  }
74
62
  }
75
63
  return `${jsDocString}${name}${typeParamsString}(${parameters}): ${returnType};`;
@@ -98,80 +86,154 @@ const generateAppsScriptTypes = async ({
98
86
  tsConfigFilePath: path__namespace.resolve(projectPath, "tsconfig.json"),
99
87
  skipAddingFilesFromTsConfig: true
100
88
  });
101
- project.addSourceFilesAtPaths(
102
- path__namespace.join(absoluteSrcDir, "**/*.ts").replace(/\\/g, "/")
103
- );
104
- const methodDefinitions = [];
105
- const globalTypeDefinitions = [];
106
- const importStatements = /* @__PURE__ */ new Set();
89
+ const sourceFilesPattern = path__namespace.join(absoluteSrcDir, "**/*.ts").replace(/\\/g, "/");
90
+ const testFilesPattern = `!${path__namespace.join(absoluteSrcDir, "**/*.{test,spec}.ts").replace(/\\/g, "/")}`;
91
+ project.addSourceFilesAtPaths([sourceFilesPattern, testFilesPattern]);
107
92
  const sourceFiles = project.getSourceFiles();
108
93
  consola.consola.info(`Found ${sourceFiles.length} source file(s).`);
94
+ const methodDefinitions = [];
95
+ const exportedDeclarations = [];
96
+ const exportedDeclarationNames = /* @__PURE__ */ new Set();
97
+ const exportedFunctions = [];
109
98
  for (const sourceFile of sourceFiles) {
110
- const importDeclarations = sourceFile.getImportDeclarations?.();
111
- if (importDeclarations != null && importDeclarations.length > 0) {
112
- for (const importDeclaration of importDeclarations) {
113
- const moduleSpecifier = importDeclaration.getModuleSpecifierSourceFile();
114
- if (moduleSpecifier) {
115
- const importedFilePath = moduleSpecifier.getFilePath();
116
- let relativePath = path__namespace.relative(path__namespace.dirname(absoluteOutputFile), importedFilePath).replace(/\\/g, "/");
117
- relativePath = relativePath.replace(/\.(ts|tsx|d\.ts)$/, "");
118
- if (!relativePath.startsWith(".") && !relativePath.startsWith("..")) {
119
- relativePath = `./${relativePath}`;
120
- }
121
- const originalText = importDeclaration.getText();
122
- const newImportText = originalText.replace(
123
- importDeclaration.getModuleSpecifierValue(),
124
- relativePath
125
- );
126
- importStatements.add(newImportText);
127
- } else {
128
- importStatements.add(importDeclaration.getText());
129
- }
130
- }
131
- }
132
99
  for (const iface of sourceFile.getInterfaces()) {
133
- const name = iface?.getName?.();
134
- if (name == null || name.endsWith("_")) {
135
- continue;
100
+ if (iface.isExported() && !iface.getName()?.endsWith("_")) {
101
+ exportedDeclarations.push(iface);
102
+ exportedDeclarationNames.add(iface.getName());
136
103
  }
137
- globalTypeDefinitions.push(iface.getText());
138
104
  }
139
105
  for (const typeAlias of sourceFile.getTypeAliases()) {
140
- const name = typeAlias?.getName?.();
141
- if (name == null || name.endsWith("_")) {
142
- continue;
106
+ if (typeAlias.isExported() && !typeAlias.getName().endsWith("_")) {
107
+ exportedDeclarations.push(typeAlias);
108
+ exportedDeclarationNames.add(typeAlias.getName());
143
109
  }
144
- globalTypeDefinitions.push(typeAlias.getText());
145
110
  }
146
- for (const statement of sourceFile.getStatements()) {
147
- if (statement.getKind() === tsMorph.SyntaxKind.ModuleDeclaration) {
148
- globalTypeDefinitions.push(statement.getText());
111
+ for (const func of sourceFile.getFunctions()) {
112
+ const name = func.getName();
113
+ if (func.isExported() && name && !name.endsWith("_") && !SIMPLE_TRIGGER_FUNCTION_NAMES.includes(name)) {
114
+ exportedDeclarations.push(func);
115
+ exportedDeclarationNames.add(name);
116
+ methodDefinitions.push(getInterfaceMethodDefinition_(name, func));
117
+ exportedFunctions.push(func);
149
118
  }
150
119
  }
151
- for (const funcDecl of sourceFile.getFunctions()) {
152
- if (!funcDecl.isAmbient()) {
153
- const name = funcDecl.getName();
154
- if (name != null && !name.endsWith("_") && !SIMPLE_TRIGGER_FUNCTION_NAMES.includes(name)) {
155
- methodDefinitions.push(getInterfaceMethodDefinition_(name, funcDecl));
120
+ for (const varStmt of sourceFile.getVariableStatements()) {
121
+ if (!varStmt.isExported()) continue;
122
+ for (const varDecl of varStmt.getDeclarations()) {
123
+ const name = varDecl.getName();
124
+ const initializer = varDecl.getInitializer();
125
+ if (!name.endsWith("_") && !SIMPLE_TRIGGER_FUNCTION_NAMES.includes(name) && initializer && (initializer.getKind() === tsMorph.SyntaxKind.ArrowFunction || initializer.getKind() === tsMorph.SyntaxKind.FunctionExpression)) {
126
+ const funcExpr = initializer;
127
+ exportedDeclarations.push(varDecl);
128
+ exportedDeclarationNames.add(name);
129
+ methodDefinitions.push(getInterfaceMethodDefinition_(name, funcExpr));
130
+ exportedFunctions.push(funcExpr);
156
131
  }
157
132
  }
158
133
  }
159
- for (const varStmt of sourceFile.getVariableStatements()) {
160
- if (!varStmt.isAmbient()) {
161
- for (const varDecl of varStmt.getDeclarations()) {
162
- const initializer = varDecl.getInitializer();
163
- const varName = varDecl.getName();
164
- if (initializer != null && (initializer.getKind() === tsMorph.SyntaxKind.ArrowFunction || initializer.getKind() === tsMorph.SyntaxKind.FunctionExpression) && !varName.endsWith("_") && !SIMPLE_TRIGGER_FUNCTION_NAMES.includes(varName)) {
165
- methodDefinitions.push(
166
- getInterfaceMethodDefinition_(
167
- varName,
168
- initializer
169
- )
170
- );
134
+ }
135
+ const collectSymbolsFromType = (type, foundSymbols) => {
136
+ const symbol = type.getAliasSymbol() ?? type.getSymbol();
137
+ if (symbol && !foundSymbols.has(symbol)) {
138
+ foundSymbols.add(symbol);
139
+ if (type.isObject()) {
140
+ for (const prop of type.getProperties()) {
141
+ const propDecl = prop.getDeclarations()[0];
142
+ if (propDecl) {
143
+ collectSymbolsFromType(propDecl.getType(), foundSymbols);
171
144
  }
172
145
  }
173
146
  }
174
147
  }
148
+ for (const typeArg of type.getTypeArguments()) {
149
+ collectSymbolsFromType(typeArg, foundSymbols);
150
+ }
151
+ if (type.isUnion()) {
152
+ for (const unionType of type.getUnionTypes()) {
153
+ collectSymbolsFromType(unionType, foundSymbols);
154
+ }
155
+ }
156
+ if (type.isIntersection()) {
157
+ for (const intersectionType of type.getIntersectionTypes()) {
158
+ collectSymbolsFromType(intersectionType, foundSymbols);
159
+ }
160
+ }
161
+ };
162
+ const returnValueSymbols = /* @__PURE__ */ new Set();
163
+ for (const func of exportedFunctions) {
164
+ collectSymbolsFromType(func.getReturnType(), returnValueSymbols);
165
+ }
166
+ const importsMap = /* @__PURE__ */ new Map();
167
+ const inlineDefinitions = /* @__PURE__ */ new Map();
168
+ const symbolsToProcess = /* @__PURE__ */ new Set();
169
+ const processedSymbols = /* @__PURE__ */ new Set();
170
+ for (const decl of exportedDeclarations) {
171
+ for (const descendant of decl.getDescendantsOfKind(
172
+ tsMorph.SyntaxKind.TypeReference
173
+ )) {
174
+ const symbol = descendant.getType().getAliasSymbol() ?? descendant.getType().getSymbol();
175
+ if (symbol) {
176
+ symbolsToProcess.add(symbol);
177
+ }
178
+ }
179
+ }
180
+ while (symbolsToProcess.size > 0) {
181
+ const symbol = symbolsToProcess.values().next().value;
182
+ if (!symbol) continue;
183
+ symbolsToProcess.delete(symbol);
184
+ const symbolName = symbol.getName();
185
+ if (processedSymbols.has(symbolName) || exportedDeclarationNames.has(symbolName) || symbolName === "__type") {
186
+ continue;
187
+ }
188
+ const symbolFlags = symbol.getFlags();
189
+ if (symbolFlags & tsMorph.SymbolFlags.TypeParameter) {
190
+ continue;
191
+ }
192
+ const declaration = symbol.getDeclarations()[0];
193
+ if (!declaration) {
194
+ continue;
195
+ }
196
+ const sourceFile = declaration.getSourceFile();
197
+ if (sourceFile.getFilePath().includes("node_modules")) {
198
+ continue;
199
+ }
200
+ processedSymbols.add(symbolName);
201
+ const isLocalDefinition = declaration.getParent()?.getKind() !== tsMorph.SyntaxKind.SourceFile;
202
+ if (isLocalDefinition) {
203
+ if (returnValueSymbols.has(symbol)) {
204
+ const declText = declaration.getText();
205
+ inlineDefinitions.set(symbolName, declText);
206
+ const tempSourceFile = project.createSourceFile(
207
+ `__temp_${symbolName}.ts`,
208
+ declText
209
+ );
210
+ for (const descendant of tempSourceFile.getDescendantsOfKind(
211
+ tsMorph.SyntaxKind.TypeReference
212
+ )) {
213
+ const newSymbol = descendant.getType().getAliasSymbol() ?? descendant.getType().getSymbol();
214
+ if (newSymbol) {
215
+ symbolsToProcess.add(newSymbol);
216
+ }
217
+ }
218
+ tempSourceFile.delete();
219
+ }
220
+ } else {
221
+ let modulePath = path__namespace.relative(absoluteOutDir, sourceFile.getFilePath()).replace(/\\/g, "/");
222
+ modulePath = modulePath.replace(/\.(d\.)?ts$/, "");
223
+ if (modulePath.endsWith("/index")) {
224
+ modulePath = modulePath.slice(0, -6);
225
+ }
226
+ if (modulePath === "index" || modulePath === "") {
227
+ modulePath = ".";
228
+ }
229
+ if (!modulePath.startsWith(".")) {
230
+ modulePath = `./${modulePath}`;
231
+ }
232
+ if (!importsMap.has(modulePath)) {
233
+ importsMap.set(modulePath, /* @__PURE__ */ new Set());
234
+ }
235
+ importsMap.get(modulePath)?.add(symbolName);
236
+ }
175
237
  }
176
238
  if (!fs__namespace.existsSync(absoluteOutDir)) {
177
239
  fs__namespace.mkdirSync(absoluteOutDir, { recursive: true });
@@ -180,14 +242,34 @@ const generateAppsScriptTypes = async ({
180
242
  const generatorName = "gasnuki";
181
243
  let outputContent = `// Auto-generated by ${generatorName}
182
244
  // Do NOT edit this file manually.
245
+
183
246
  `;
184
- if (importStatements.size > 0) {
185
- outputContent += `${[...importStatements].join("\n")}
247
+ const sortedModulePaths = [...importsMap.keys()].sort((a, b) => {
248
+ const aIsRelative = a.startsWith(".");
249
+ const bIsRelative = b.startsWith(".");
250
+ if (aIsRelative !== bIsRelative) return aIsRelative ? 1 : -1;
251
+ return a.localeCompare(b);
252
+ });
253
+ if (sortedModulePaths.length > 0) {
254
+ const importStatements = sortedModulePaths.map((modulePath) => {
255
+ const imports = [...importsMap.get(modulePath) ?? []].sort();
256
+ const finalModulePath = modulePath === "." ? "./index" : modulePath;
257
+ return `import type { ${imports.join(", ")} } from '${finalModulePath}';`;
258
+ });
259
+ outputContent += `${importStatements.join("\n")}
260
+
261
+ `;
262
+ }
263
+ if (inlineDefinitions.size > 0) {
264
+ outputContent += `${[...inlineDefinitions.values()].join("\n\n")}
186
265
 
187
266
  `;
188
267
  }
189
- if (globalTypeDefinitions.length > 0) {
190
- outputContent += `${globalTypeDefinitions.join("\n\n")}
268
+ const exportedTypeDefinitions = exportedDeclarations.filter(
269
+ (d) => d.getKind() === tsMorph.SyntaxKind.InterfaceDeclaration || d.getKind() === tsMorph.SyntaxKind.TypeAliasDeclaration
270
+ ).map((decl) => decl.getText());
271
+ if (exportedTypeDefinitions.length > 0) {
272
+ outputContent += `${exportedTypeDefinitions.join("\n\n")}
191
273
 
192
274
  `;
193
275
  }
@@ -200,7 +282,7 @@ ${formattedMethods}
200
282
  }
201
283
  `;
202
284
  consola.consola.info(
203
- `Interface 'ServerScript' type definitions written to ${absoluteOutputFile} (${methodDefinitions.length} function(s), ${globalTypeDefinitions.length} type(s)).`
285
+ `Interface 'ServerScript' type definitions written to ${absoluteOutputFile} (${methodDefinitions.length} function(s), ${exportedTypeDefinitions.length + inlineDefinitions.size} type(s)).`
204
286
  );
205
287
  } else {
206
288
  outputContent += "export type ServerScripts = {}\n";
@@ -2,7 +2,7 @@ import * as path from 'node:path';
2
2
  import * as chokidar from 'chokidar';
3
3
  import { consola } from 'consola';
4
4
  import * as fs from 'node:fs';
5
- import { Project, SyntaxKind } from 'ts-morph';
5
+ import { Project, SyntaxKind, SymbolFlags } from 'ts-morph';
6
6
  import { createJiti } from 'jiti';
7
7
 
8
8
  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 _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";
@@ -29,29 +29,17 @@ const getInterfaceMethodDefinition_ = (name, node) => {
29
29
  }
30
30
  }
31
31
  let jsDocString = "";
32
- const jsDocOwner = "getJsDocs" in node ? node : "getParantOrThrow" in node && // @ts-expect-error variable declaration
32
+ const jsDocOwner = "getJsDocs" in node ? node : "getParentOrThrow" in node && // @ts-expect-error variable declaration
33
33
  node.getParentOrThrow().getKind() === SyntaxKind.VariableDeclaration ? (
34
34
  // @ts-expect-error variable declaration
35
35
  node.getParentOrThrow()
36
36
  ) : null;
37
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()}
38
+ const jsDocs = "getJsDocs" in jsDocOwner ? jsDocOwner.getJsDocs() : [];
39
+ if (jsDocs.length > 0) {
40
+ const firstDoc = jsDocs[0];
41
+ jsDocString = `${firstDoc.getFullText().trim()}
52
42
  `;
53
- }
54
- }
55
43
  }
56
44
  }
57
45
  return `${jsDocString}${name}${typeParamsString}(${parameters}): ${returnType};`;
@@ -80,80 +68,154 @@ const generateAppsScriptTypes = async ({
80
68
  tsConfigFilePath: path.resolve(projectPath, "tsconfig.json"),
81
69
  skipAddingFilesFromTsConfig: true
82
70
  });
83
- project.addSourceFilesAtPaths(
84
- path.join(absoluteSrcDir, "**/*.ts").replace(/\\/g, "/")
85
- );
86
- const methodDefinitions = [];
87
- const globalTypeDefinitions = [];
88
- const importStatements = /* @__PURE__ */ new Set();
71
+ const sourceFilesPattern = path.join(absoluteSrcDir, "**/*.ts").replace(/\\/g, "/");
72
+ const testFilesPattern = `!${path.join(absoluteSrcDir, "**/*.{test,spec}.ts").replace(/\\/g, "/")}`;
73
+ project.addSourceFilesAtPaths([sourceFilesPattern, testFilesPattern]);
89
74
  const sourceFiles = project.getSourceFiles();
90
75
  consola.info(`Found ${sourceFiles.length} source file(s).`);
76
+ const methodDefinitions = [];
77
+ const exportedDeclarations = [];
78
+ const exportedDeclarationNames = /* @__PURE__ */ new Set();
79
+ const exportedFunctions = [];
91
80
  for (const sourceFile of sourceFiles) {
92
- const importDeclarations = sourceFile.getImportDeclarations?.();
93
- if (importDeclarations != null && importDeclarations.length > 0) {
94
- for (const importDeclaration of importDeclarations) {
95
- const moduleSpecifier = importDeclaration.getModuleSpecifierSourceFile();
96
- if (moduleSpecifier) {
97
- const importedFilePath = moduleSpecifier.getFilePath();
98
- let relativePath = path.relative(path.dirname(absoluteOutputFile), importedFilePath).replace(/\\/g, "/");
99
- relativePath = relativePath.replace(/\.(ts|tsx|d\.ts)$/, "");
100
- if (!relativePath.startsWith(".") && !relativePath.startsWith("..")) {
101
- relativePath = `./${relativePath}`;
102
- }
103
- const originalText = importDeclaration.getText();
104
- const newImportText = originalText.replace(
105
- importDeclaration.getModuleSpecifierValue(),
106
- relativePath
107
- );
108
- importStatements.add(newImportText);
109
- } else {
110
- importStatements.add(importDeclaration.getText());
111
- }
112
- }
113
- }
114
81
  for (const iface of sourceFile.getInterfaces()) {
115
- const name = iface?.getName?.();
116
- if (name == null || name.endsWith("_")) {
117
- continue;
82
+ if (iface.isExported() && !iface.getName()?.endsWith("_")) {
83
+ exportedDeclarations.push(iface);
84
+ exportedDeclarationNames.add(iface.getName());
118
85
  }
119
- globalTypeDefinitions.push(iface.getText());
120
86
  }
121
87
  for (const typeAlias of sourceFile.getTypeAliases()) {
122
- const name = typeAlias?.getName?.();
123
- if (name == null || name.endsWith("_")) {
124
- continue;
88
+ if (typeAlias.isExported() && !typeAlias.getName().endsWith("_")) {
89
+ exportedDeclarations.push(typeAlias);
90
+ exportedDeclarationNames.add(typeAlias.getName());
125
91
  }
126
- globalTypeDefinitions.push(typeAlias.getText());
127
92
  }
128
- for (const statement of sourceFile.getStatements()) {
129
- if (statement.getKind() === SyntaxKind.ModuleDeclaration) {
130
- globalTypeDefinitions.push(statement.getText());
93
+ for (const func of sourceFile.getFunctions()) {
94
+ const name = func.getName();
95
+ if (func.isExported() && name && !name.endsWith("_") && !SIMPLE_TRIGGER_FUNCTION_NAMES.includes(name)) {
96
+ exportedDeclarations.push(func);
97
+ exportedDeclarationNames.add(name);
98
+ methodDefinitions.push(getInterfaceMethodDefinition_(name, func));
99
+ exportedFunctions.push(func);
131
100
  }
132
101
  }
133
- for (const funcDecl of sourceFile.getFunctions()) {
134
- if (!funcDecl.isAmbient()) {
135
- const name = funcDecl.getName();
136
- if (name != null && !name.endsWith("_") && !SIMPLE_TRIGGER_FUNCTION_NAMES.includes(name)) {
137
- methodDefinitions.push(getInterfaceMethodDefinition_(name, funcDecl));
102
+ for (const varStmt of sourceFile.getVariableStatements()) {
103
+ if (!varStmt.isExported()) continue;
104
+ for (const varDecl of varStmt.getDeclarations()) {
105
+ const name = varDecl.getName();
106
+ const initializer = varDecl.getInitializer();
107
+ if (!name.endsWith("_") && !SIMPLE_TRIGGER_FUNCTION_NAMES.includes(name) && initializer && (initializer.getKind() === SyntaxKind.ArrowFunction || initializer.getKind() === SyntaxKind.FunctionExpression)) {
108
+ const funcExpr = initializer;
109
+ exportedDeclarations.push(varDecl);
110
+ exportedDeclarationNames.add(name);
111
+ methodDefinitions.push(getInterfaceMethodDefinition_(name, funcExpr));
112
+ exportedFunctions.push(funcExpr);
138
113
  }
139
114
  }
140
115
  }
141
- for (const varStmt of sourceFile.getVariableStatements()) {
142
- if (!varStmt.isAmbient()) {
143
- for (const varDecl of varStmt.getDeclarations()) {
144
- const initializer = varDecl.getInitializer();
145
- const varName = varDecl.getName();
146
- if (initializer != null && (initializer.getKind() === SyntaxKind.ArrowFunction || initializer.getKind() === SyntaxKind.FunctionExpression) && !varName.endsWith("_") && !SIMPLE_TRIGGER_FUNCTION_NAMES.includes(varName)) {
147
- methodDefinitions.push(
148
- getInterfaceMethodDefinition_(
149
- varName,
150
- initializer
151
- )
152
- );
116
+ }
117
+ const collectSymbolsFromType = (type, foundSymbols) => {
118
+ const symbol = type.getAliasSymbol() ?? type.getSymbol();
119
+ if (symbol && !foundSymbols.has(symbol)) {
120
+ foundSymbols.add(symbol);
121
+ if (type.isObject()) {
122
+ for (const prop of type.getProperties()) {
123
+ const propDecl = prop.getDeclarations()[0];
124
+ if (propDecl) {
125
+ collectSymbolsFromType(propDecl.getType(), foundSymbols);
153
126
  }
154
127
  }
155
128
  }
156
129
  }
130
+ for (const typeArg of type.getTypeArguments()) {
131
+ collectSymbolsFromType(typeArg, foundSymbols);
132
+ }
133
+ if (type.isUnion()) {
134
+ for (const unionType of type.getUnionTypes()) {
135
+ collectSymbolsFromType(unionType, foundSymbols);
136
+ }
137
+ }
138
+ if (type.isIntersection()) {
139
+ for (const intersectionType of type.getIntersectionTypes()) {
140
+ collectSymbolsFromType(intersectionType, foundSymbols);
141
+ }
142
+ }
143
+ };
144
+ const returnValueSymbols = /* @__PURE__ */ new Set();
145
+ for (const func of exportedFunctions) {
146
+ collectSymbolsFromType(func.getReturnType(), returnValueSymbols);
147
+ }
148
+ const importsMap = /* @__PURE__ */ new Map();
149
+ const inlineDefinitions = /* @__PURE__ */ new Map();
150
+ const symbolsToProcess = /* @__PURE__ */ new Set();
151
+ const processedSymbols = /* @__PURE__ */ new Set();
152
+ for (const decl of exportedDeclarations) {
153
+ for (const descendant of decl.getDescendantsOfKind(
154
+ SyntaxKind.TypeReference
155
+ )) {
156
+ const symbol = descendant.getType().getAliasSymbol() ?? descendant.getType().getSymbol();
157
+ if (symbol) {
158
+ symbolsToProcess.add(symbol);
159
+ }
160
+ }
161
+ }
162
+ while (symbolsToProcess.size > 0) {
163
+ const symbol = symbolsToProcess.values().next().value;
164
+ if (!symbol) continue;
165
+ symbolsToProcess.delete(symbol);
166
+ const symbolName = symbol.getName();
167
+ if (processedSymbols.has(symbolName) || exportedDeclarationNames.has(symbolName) || symbolName === "__type") {
168
+ continue;
169
+ }
170
+ const symbolFlags = symbol.getFlags();
171
+ if (symbolFlags & SymbolFlags.TypeParameter) {
172
+ continue;
173
+ }
174
+ const declaration = symbol.getDeclarations()[0];
175
+ if (!declaration) {
176
+ continue;
177
+ }
178
+ const sourceFile = declaration.getSourceFile();
179
+ if (sourceFile.getFilePath().includes("node_modules")) {
180
+ continue;
181
+ }
182
+ processedSymbols.add(symbolName);
183
+ const isLocalDefinition = declaration.getParent()?.getKind() !== SyntaxKind.SourceFile;
184
+ if (isLocalDefinition) {
185
+ if (returnValueSymbols.has(symbol)) {
186
+ const declText = declaration.getText();
187
+ inlineDefinitions.set(symbolName, declText);
188
+ const tempSourceFile = project.createSourceFile(
189
+ `__temp_${symbolName}.ts`,
190
+ declText
191
+ );
192
+ for (const descendant of tempSourceFile.getDescendantsOfKind(
193
+ SyntaxKind.TypeReference
194
+ )) {
195
+ const newSymbol = descendant.getType().getAliasSymbol() ?? descendant.getType().getSymbol();
196
+ if (newSymbol) {
197
+ symbolsToProcess.add(newSymbol);
198
+ }
199
+ }
200
+ tempSourceFile.delete();
201
+ }
202
+ } else {
203
+ let modulePath = path.relative(absoluteOutDir, sourceFile.getFilePath()).replace(/\\/g, "/");
204
+ modulePath = modulePath.replace(/\.(d\.)?ts$/, "");
205
+ if (modulePath.endsWith("/index")) {
206
+ modulePath = modulePath.slice(0, -6);
207
+ }
208
+ if (modulePath === "index" || modulePath === "") {
209
+ modulePath = ".";
210
+ }
211
+ if (!modulePath.startsWith(".")) {
212
+ modulePath = `./${modulePath}`;
213
+ }
214
+ if (!importsMap.has(modulePath)) {
215
+ importsMap.set(modulePath, /* @__PURE__ */ new Set());
216
+ }
217
+ importsMap.get(modulePath)?.add(symbolName);
218
+ }
157
219
  }
158
220
  if (!fs.existsSync(absoluteOutDir)) {
159
221
  fs.mkdirSync(absoluteOutDir, { recursive: true });
@@ -162,14 +224,34 @@ const generateAppsScriptTypes = async ({
162
224
  const generatorName = "gasnuki";
163
225
  let outputContent = `// Auto-generated by ${generatorName}
164
226
  // Do NOT edit this file manually.
227
+
165
228
  `;
166
- if (importStatements.size > 0) {
167
- outputContent += `${[...importStatements].join("\n")}
229
+ const sortedModulePaths = [...importsMap.keys()].sort((a, b) => {
230
+ const aIsRelative = a.startsWith(".");
231
+ const bIsRelative = b.startsWith(".");
232
+ if (aIsRelative !== bIsRelative) return aIsRelative ? 1 : -1;
233
+ return a.localeCompare(b);
234
+ });
235
+ if (sortedModulePaths.length > 0) {
236
+ const importStatements = sortedModulePaths.map((modulePath) => {
237
+ const imports = [...importsMap.get(modulePath) ?? []].sort();
238
+ const finalModulePath = modulePath === "." ? "./index" : modulePath;
239
+ return `import type { ${imports.join(", ")} } from '${finalModulePath}';`;
240
+ });
241
+ outputContent += `${importStatements.join("\n")}
242
+
243
+ `;
244
+ }
245
+ if (inlineDefinitions.size > 0) {
246
+ outputContent += `${[...inlineDefinitions.values()].join("\n\n")}
168
247
 
169
248
  `;
170
249
  }
171
- if (globalTypeDefinitions.length > 0) {
172
- outputContent += `${globalTypeDefinitions.join("\n\n")}
250
+ const exportedTypeDefinitions = exportedDeclarations.filter(
251
+ (d) => d.getKind() === SyntaxKind.InterfaceDeclaration || d.getKind() === SyntaxKind.TypeAliasDeclaration
252
+ ).map((decl) => decl.getText());
253
+ if (exportedTypeDefinitions.length > 0) {
254
+ outputContent += `${exportedTypeDefinitions.join("\n\n")}
173
255
 
174
256
  `;
175
257
  }
@@ -182,7 +264,7 @@ ${formattedMethods}
182
264
  }
183
265
  `;
184
266
  consola.info(
185
- `Interface 'ServerScript' type definitions written to ${absoluteOutputFile} (${methodDefinitions.length} function(s), ${globalTypeDefinitions.length} type(s)).`
267
+ `Interface 'ServerScript' type definitions written to ${absoluteOutputFile} (${methodDefinitions.length} function(s), ${exportedTypeDefinitions.length + inlineDefinitions.size} type(s)).`
186
268
  );
187
269
  } else {
188
270
  outputContent += "export type ServerScripts = {}\n";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ciderjs/gasnuki",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
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,7 +21,7 @@
21
21
  },
22
22
  "scripts": {
23
23
  "generate": "jiti .bin/generate.ts",
24
- "dev": "pnpm prebuild && jiti src/cli.ts -p playground/react -s src/server",
24
+ "dev": "pnpm run generate && jiti src/cli.ts -p playground/react -s src/server",
25
25
  "start": "node dist/cli.mjs -p playground/react -s src/server",
26
26
  "check": "biome check --write",
27
27
  "build": "unbuild",