@hono/cli 0.1.0 → 0.1.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.md +1 -0
- package/dist/cli.js +83 -40
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -156,6 +156,7 @@ hono request [file] [options]
|
|
|
156
156
|
- `-X, --method <method>` - HTTP method (default: GET)
|
|
157
157
|
- `-d, --data <data>` - Request body data
|
|
158
158
|
- `-H, --header <header>` - Custom headers (can be used multiple times)
|
|
159
|
+
- `-w, --watch` - Watch for changes and resend request
|
|
159
160
|
|
|
160
161
|
**Examples:**
|
|
161
162
|
|
package/dist/cli.js
CHANGED
|
@@ -70,30 +70,61 @@ import { dirname, join, resolve } from "path";
|
|
|
70
70
|
|
|
71
71
|
// src/utils/build.ts
|
|
72
72
|
import * as esbuild from "esbuild";
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
entryPoints: [filePath],
|
|
80
|
-
bundle: true,
|
|
81
|
-
write: false,
|
|
82
|
-
format: "esm",
|
|
83
|
-
target: "node20",
|
|
84
|
-
jsx: "automatic",
|
|
85
|
-
jsxImportSource: "hono/jsx",
|
|
86
|
-
platform: "node",
|
|
87
|
-
external: options.external || []
|
|
73
|
+
async function* buildAndImportApp(filePath, options = {}) {
|
|
74
|
+
let resolveApp;
|
|
75
|
+
let appPromise;
|
|
76
|
+
const preparePromise = () => {
|
|
77
|
+
appPromise = new Promise((resolve4) => {
|
|
78
|
+
resolveApp = resolve4;
|
|
88
79
|
});
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
80
|
+
};
|
|
81
|
+
preparePromise();
|
|
82
|
+
const context2 = await esbuild.context({
|
|
83
|
+
entryPoints: [filePath],
|
|
84
|
+
bundle: true,
|
|
85
|
+
write: false,
|
|
86
|
+
format: "esm",
|
|
87
|
+
target: "node20",
|
|
88
|
+
jsx: "automatic",
|
|
89
|
+
jsxImportSource: "hono/jsx",
|
|
90
|
+
platform: "node",
|
|
91
|
+
external: options.external || [],
|
|
92
|
+
plugins: [
|
|
93
|
+
{
|
|
94
|
+
name: "watch",
|
|
95
|
+
setup(build2) {
|
|
96
|
+
build2.onEnd(async (result) => {
|
|
97
|
+
try {
|
|
98
|
+
const code = result.outputFiles?.[0]?.text || "";
|
|
99
|
+
const dataUrl = `data:text/javascript;base64,${Buffer.from(code).toString("base64")}`;
|
|
100
|
+
const module = await import(dataUrl);
|
|
101
|
+
const app = module.default;
|
|
102
|
+
if (!app) {
|
|
103
|
+
throw new Error("Failed to build app");
|
|
104
|
+
}
|
|
105
|
+
if (!app || typeof app.request !== "function") {
|
|
106
|
+
throw new Error("No valid Hono app exported from the file");
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
resolveApp(app);
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error("Error building app", error);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
});
|
|
120
|
+
await context2.watch();
|
|
121
|
+
if (!options.watch) {
|
|
122
|
+
await context2.dispose();
|
|
96
123
|
}
|
|
124
|
+
do {
|
|
125
|
+
yield await appPromise;
|
|
126
|
+
preparePromise();
|
|
127
|
+
} while (options.watch);
|
|
97
128
|
}
|
|
98
129
|
|
|
99
130
|
// src/commands/optimize/index.ts
|
|
@@ -108,9 +139,10 @@ function optimizeCommand(program2) {
|
|
|
108
139
|
throw new Error(`Entry file ${entry} does not exist`);
|
|
109
140
|
}
|
|
110
141
|
const appFilePath = realpathSync(appPath);
|
|
111
|
-
const
|
|
142
|
+
const buildIterator = buildAndImportApp(appFilePath, {
|
|
112
143
|
external: ["@hono/node-server"]
|
|
113
144
|
});
|
|
145
|
+
const app = (await buildIterator.next()).value;
|
|
114
146
|
let routerName;
|
|
115
147
|
let importStatement;
|
|
116
148
|
let assignRouterStatement;
|
|
@@ -161,13 +193,13 @@ function optimizeCommand(program2) {
|
|
|
161
193
|
plugins: [
|
|
162
194
|
{
|
|
163
195
|
name: "hono-optimize",
|
|
164
|
-
setup(
|
|
196
|
+
setup(build2) {
|
|
165
197
|
const honoPseudoImportPath = "hono-optimized-pseudo-import-path";
|
|
166
|
-
|
|
198
|
+
build2.onResolve({ filter: /^hono$/ }, async (args) => {
|
|
167
199
|
if (!args.importer) {
|
|
168
200
|
return void 0;
|
|
169
201
|
}
|
|
170
|
-
const resolved = await
|
|
202
|
+
const resolved = await build2.resolve(args.path, {
|
|
171
203
|
kind: "import-statement",
|
|
172
204
|
resolveDir: args.resolveDir
|
|
173
205
|
});
|
|
@@ -175,7 +207,7 @@ function optimizeCommand(program2) {
|
|
|
175
207
|
path: join(dirname(resolved.path), honoPseudoImportPath)
|
|
176
208
|
};
|
|
177
209
|
});
|
|
178
|
-
|
|
210
|
+
build2.onLoad({ filter: new RegExp(`/${honoPseudoImportPath}$`) }, async () => {
|
|
179
211
|
return {
|
|
180
212
|
contents: `
|
|
181
213
|
import { HonoBase } from 'hono/hono-base'
|
|
@@ -203,7 +235,7 @@ import { existsSync as existsSync2, realpathSync as realpathSync2 } from "fs";
|
|
|
203
235
|
import { resolve as resolve2 } from "path";
|
|
204
236
|
var DEFAULT_ENTRY_CANDIDATES2 = ["src/index.ts", "src/index.tsx", "src/index.js", "src/index.jsx"];
|
|
205
237
|
function requestCommand(program2) {
|
|
206
|
-
program2.command("request").description("Send request to Hono app using app.request()").argument("[file]", "Path to the Hono app file").option("-P, --path <path>", "Request path", "/").option("-X, --method <method>", "HTTP method", "GET").option("-d, --data <data>", "Request body data").option(
|
|
238
|
+
program2.command("request").description("Send request to Hono app using app.request()").argument("[file]", "Path to the Hono app file").option("-P, --path <path>", "Request path", "/").option("-X, --method <method>", "HTTP method", "GET").option("-d, --data <data>", "Request body data").option("-w, --watch", "Watch for changes and re-run the request", false).option(
|
|
207
239
|
"-H, --header <header>",
|
|
208
240
|
"Custom headers",
|
|
209
241
|
(value, previous) => {
|
|
@@ -212,11 +244,15 @@ function requestCommand(program2) {
|
|
|
212
244
|
[]
|
|
213
245
|
).action(async (file, options) => {
|
|
214
246
|
const path = options.path || "/";
|
|
215
|
-
const
|
|
216
|
-
|
|
247
|
+
const watch = options.watch;
|
|
248
|
+
const buildIterator = getBuildIterator(file, watch);
|
|
249
|
+
for await (const app of buildIterator) {
|
|
250
|
+
const result = await executeRequest(app, path, options);
|
|
251
|
+
console.log(JSON.stringify(result, null, 2));
|
|
252
|
+
}
|
|
217
253
|
});
|
|
218
254
|
}
|
|
219
|
-
|
|
255
|
+
function getBuildIterator(appPath, watch) {
|
|
220
256
|
let entry;
|
|
221
257
|
let resolvedAppPath;
|
|
222
258
|
if (appPath) {
|
|
@@ -230,12 +266,12 @@ async function executeRequest(appPath, requestPath, options) {
|
|
|
230
266
|
throw new Error(`Entry file ${entry} does not exist`);
|
|
231
267
|
}
|
|
232
268
|
const appFilePath = realpathSync2(resolvedAppPath);
|
|
233
|
-
|
|
234
|
-
external: ["@hono/node-server"]
|
|
269
|
+
return buildAndImportApp(appFilePath, {
|
|
270
|
+
external: ["@hono/node-server"],
|
|
271
|
+
watch
|
|
235
272
|
});
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
273
|
+
}
|
|
274
|
+
async function executeRequest(app, requestPath, options) {
|
|
239
275
|
const url = new URL(requestPath, "http://localhost");
|
|
240
276
|
const requestInit = {
|
|
241
277
|
method: options.method || "GET"
|
|
@@ -269,11 +305,17 @@ async function executeRequest(appPath, requestPath, options) {
|
|
|
269
305
|
|
|
270
306
|
// src/commands/search/index.ts
|
|
271
307
|
function searchCommand(program2) {
|
|
272
|
-
program2.command("search").argument("<query>", "Search query for Hono documentation").option("-l, --limit <number>", "Number of results to show (default: 5)",
|
|
308
|
+
program2.command("search").argument("<query>", "Search query for Hono documentation").option("-l, --limit <number>", "Number of results to show (default: 5)", (value) => {
|
|
309
|
+
const parsed = parseInt(value, 10);
|
|
310
|
+
if (isNaN(parsed) || parsed < 1 || parsed > 20) {
|
|
311
|
+
console.warn("Limit must be a number between 1 and 20\n");
|
|
312
|
+
return 5;
|
|
313
|
+
}
|
|
314
|
+
return parsed;
|
|
315
|
+
}).option("-p, --pretty", "Display results in human-readable format").description("Search Hono documentation").action(async (query, options) => {
|
|
273
316
|
const ALGOLIA_APP_ID = "1GIFSU1REV";
|
|
274
317
|
const ALGOLIA_API_KEY = "c6a0f86b9a9f8551654600f28317a9e9";
|
|
275
318
|
const ALGOLIA_INDEX = "hono";
|
|
276
|
-
const limit = Math.max(1, Math.min(20, parseInt(options.limit, 10) || 5));
|
|
277
319
|
const searchUrl = `https://${ALGOLIA_APP_ID}-dsn.algolia.net/1/indexes/${ALGOLIA_INDEX}/query`;
|
|
278
320
|
try {
|
|
279
321
|
if (options.pretty) {
|
|
@@ -288,7 +330,7 @@ function searchCommand(program2) {
|
|
|
288
330
|
},
|
|
289
331
|
body: JSON.stringify({
|
|
290
332
|
query,
|
|
291
|
-
hitsPerPage: limit
|
|
333
|
+
hitsPerPage: options.limit || 5
|
|
292
334
|
})
|
|
293
335
|
});
|
|
294
336
|
if (!response.ok) {
|
|
@@ -478,9 +520,10 @@ function serveCommand(program2) {
|
|
|
478
520
|
app = new Hono();
|
|
479
521
|
} else {
|
|
480
522
|
const appFilePath = realpathSync3(appPath);
|
|
481
|
-
|
|
523
|
+
const buildIterator = buildAndImportApp(appFilePath, {
|
|
482
524
|
external: ["@hono/node-server"]
|
|
483
525
|
});
|
|
526
|
+
app = (await buildIterator.next()).value;
|
|
484
527
|
}
|
|
485
528
|
}
|
|
486
529
|
const allFunctions = {};
|