@boon4681/giri 0.0.2-alpha-8 → 0.0.3-alpha-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/dist/adapters/hono.js +13 -13
- package/dist/adapters/hono.js.map +1 -1
- package/dist/cli.js +338 -155
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +179 -80
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -82,6 +82,12 @@ interface BuildGiriAppOptions {
|
|
|
82
82
|
services?: Services;
|
|
83
83
|
/** Files that changed since last build — only these are purged from require.cache before loading. */
|
|
84
84
|
dirty?: Set<string>;
|
|
85
|
+
/** Defer route-module evaluation until the adapter first reads its runtime fields. */
|
|
86
|
+
lazy?: boolean;
|
|
87
|
+
/** The caller owns a persistent TypeScript loader for lazy route evaluation. */
|
|
88
|
+
loaderRegistered?: boolean;
|
|
89
|
+
/** The caller owns a persistent project-alias resolver for lazy route evaluation. */
|
|
90
|
+
aliasResolverRegistered?: boolean;
|
|
85
91
|
}
|
|
86
92
|
interface BuiltGiriApp<App> {
|
|
87
93
|
app: App;
|
package/dist/index.js
CHANGED
|
@@ -45,13 +45,7 @@ var init_es5 = __esm({
|
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
// src/generator/schema/program.ts
|
|
48
|
-
function
|
|
49
|
-
return {
|
|
50
|
-
...options,
|
|
51
|
-
types: []
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
function createSchemaProgram(paths, routeFiles, programOptions = {}) {
|
|
48
|
+
function createSchemaProgram(paths, routeFiles) {
|
|
55
49
|
let options = { ...DEFAULT_OPTIONS };
|
|
56
50
|
const configPath = import_typescript2.default.findConfigFile(paths.cwd, import_typescript2.default.sys.fileExists, "tsconfig.json");
|
|
57
51
|
if (configPath) {
|
|
@@ -64,9 +58,6 @@ function createSchemaProgram(paths, routeFiles, programOptions = {}) {
|
|
|
64
58
|
options = { ...parsed.options, noEmit: true };
|
|
65
59
|
}
|
|
66
60
|
}
|
|
67
|
-
if (programOptions.lean) {
|
|
68
|
-
options = leanOptions(options);
|
|
69
|
-
}
|
|
70
61
|
return import_typescript2.default.createProgram(routeFiles, options);
|
|
71
62
|
}
|
|
72
63
|
var import_typescript2, DEFAULT_OPTIONS;
|
|
@@ -1108,8 +1099,11 @@ async function buildGiriApp(config, options = {}) {
|
|
|
1108
1099
|
const routes = await scanRoutes(paths.routesDir);
|
|
1109
1100
|
const app = config.adapter.createApp();
|
|
1110
1101
|
ensureGiriAliasResolver(paths.outDir);
|
|
1111
|
-
|
|
1112
|
-
|
|
1102
|
+
if (options.lazy && (!options.loaderRegistered || !options.aliasResolverRegistered)) {
|
|
1103
|
+
throw new Error("Lazy route loading requires persistent loader and alias registrations.");
|
|
1104
|
+
}
|
|
1105
|
+
const loader = options.loaderRegistered ? void 0 : await safeRegister();
|
|
1106
|
+
const unregisterAliasResolver = options.aliasResolverRegistered ? void 0 : registerAliasResolver(config.alias, paths.cwd);
|
|
1113
1107
|
try {
|
|
1114
1108
|
const dirty = options.dirty;
|
|
1115
1109
|
const forceReload = dirty === void 0;
|
|
@@ -1121,7 +1115,7 @@ async function buildGiriApp(config, options = {}) {
|
|
|
1121
1115
|
}
|
|
1122
1116
|
return sharedCache.get(file);
|
|
1123
1117
|
};
|
|
1124
|
-
|
|
1118
|
+
const runtimeFor = (route) => {
|
|
1125
1119
|
const routeModule = loadModule(route.file, isDirty(route.file));
|
|
1126
1120
|
if (typeof routeModule.handle !== "function") {
|
|
1127
1121
|
throw new Error(`${route.file} must export a named handle function.`);
|
|
@@ -1130,7 +1124,7 @@ async function buildGiriApp(config, options = {}) {
|
|
|
1130
1124
|
(file) => normalizeMiddleware(loadShared(file).middleware, file)
|
|
1131
1125
|
);
|
|
1132
1126
|
const verbMiddleware = normalizeMiddleware(routeModule.middleware, route.file);
|
|
1133
|
-
|
|
1127
|
+
return {
|
|
1134
1128
|
method: route.method,
|
|
1135
1129
|
path: route.path,
|
|
1136
1130
|
handle: routeModule.handle,
|
|
@@ -1138,19 +1132,45 @@ async function buildGiriApp(config, options = {}) {
|
|
|
1138
1132
|
input: routeInput(routeModule, route.file),
|
|
1139
1133
|
services: options.services,
|
|
1140
1134
|
cookieSecret: config.cookieSecret
|
|
1135
|
+
};
|
|
1136
|
+
};
|
|
1137
|
+
for (const route of routes) {
|
|
1138
|
+
if (!options.lazy) {
|
|
1139
|
+
config.adapter.register(app, runtimeFor(route));
|
|
1140
|
+
continue;
|
|
1141
|
+
}
|
|
1142
|
+
let runtime;
|
|
1143
|
+
const getRuntime = () => {
|
|
1144
|
+
runtime ??= runtimeFor(route);
|
|
1145
|
+
return runtime;
|
|
1146
|
+
};
|
|
1147
|
+
config.adapter.register(app, {
|
|
1148
|
+
method: route.method,
|
|
1149
|
+
path: route.path,
|
|
1150
|
+
get handle() {
|
|
1151
|
+
return getRuntime().handle;
|
|
1152
|
+
},
|
|
1153
|
+
get middleware() {
|
|
1154
|
+
return getRuntime().middleware;
|
|
1155
|
+
},
|
|
1156
|
+
get input() {
|
|
1157
|
+
return getRuntime().input;
|
|
1158
|
+
},
|
|
1159
|
+
services: options.services,
|
|
1160
|
+
cookieSecret: config.cookieSecret
|
|
1141
1161
|
});
|
|
1142
1162
|
}
|
|
1143
1163
|
} finally {
|
|
1144
|
-
unregisterAliasResolver();
|
|
1145
|
-
unregister();
|
|
1164
|
+
unregisterAliasResolver?.();
|
|
1165
|
+
loader?.unregister();
|
|
1146
1166
|
}
|
|
1147
1167
|
return { app, routes, paths };
|
|
1148
1168
|
}
|
|
1149
1169
|
|
|
1150
1170
|
// src/generator/sync.ts
|
|
1151
|
-
var
|
|
1152
|
-
var
|
|
1153
|
-
var
|
|
1171
|
+
var import_node_fs8 = require("fs");
|
|
1172
|
+
var import_promises4 = require("fs/promises");
|
|
1173
|
+
var import_node_path12 = require("path");
|
|
1154
1174
|
|
|
1155
1175
|
// src/generator/app-types.ts
|
|
1156
1176
|
var import_node_fs4 = require("fs");
|
|
@@ -2097,6 +2117,103 @@ async function writeTsConfig(paths, config) {
|
|
|
2097
2117
|
});
|
|
2098
2118
|
}
|
|
2099
2119
|
|
|
2120
|
+
// src/generator/cache.ts
|
|
2121
|
+
var import_node_crypto = require("crypto");
|
|
2122
|
+
var import_node_fs7 = require("fs");
|
|
2123
|
+
var import_promises3 = require("fs/promises");
|
|
2124
|
+
var import_node_path11 = require("path");
|
|
2125
|
+
var import_tinyglobby2 = require("tinyglobby");
|
|
2126
|
+
var CACHE_VERSION = 1;
|
|
2127
|
+
var SYNC_CACHE_NAME = ".sync-cache.json";
|
|
2128
|
+
function stableConfig(config) {
|
|
2129
|
+
const alias = Object.entries(config.alias ?? {}).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => [key, Array.isArray(value) ? [...value] : value]);
|
|
2130
|
+
return { alias, outDir: config.outDir ?? ".giri" };
|
|
2131
|
+
}
|
|
2132
|
+
async function syncFingerprint(config, paths) {
|
|
2133
|
+
const outRelative = slash((0, import_node_path11.relative)(paths.cwd, paths.outDir));
|
|
2134
|
+
const ignore = ["**/node_modules/**", "**/.git/**"];
|
|
2135
|
+
if (outRelative && !outRelative.startsWith("..")) {
|
|
2136
|
+
ignore.push(`${outRelative}/**`);
|
|
2137
|
+
}
|
|
2138
|
+
const files = await (0, import_tinyglobby2.glob)([
|
|
2139
|
+
"src/**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs,json}",
|
|
2140
|
+
"giri.config.{ts,js,mts,cts,mjs,cjs}",
|
|
2141
|
+
"tsconfig*.json",
|
|
2142
|
+
"package.json",
|
|
2143
|
+
"package-lock.json",
|
|
2144
|
+
"npm-shrinkwrap.json",
|
|
2145
|
+
"yarn.lock",
|
|
2146
|
+
"pnpm-lock.yaml",
|
|
2147
|
+
"bun.lock",
|
|
2148
|
+
"bun.lockb"
|
|
2149
|
+
], {
|
|
2150
|
+
cwd: paths.cwd,
|
|
2151
|
+
absolute: false,
|
|
2152
|
+
onlyFiles: true,
|
|
2153
|
+
dot: true,
|
|
2154
|
+
ignore
|
|
2155
|
+
});
|
|
2156
|
+
const hash = (0, import_node_crypto.createHash)("sha256");
|
|
2157
|
+
hash.update(JSON.stringify(stableConfig(config)));
|
|
2158
|
+
for (const file of files.sort()) {
|
|
2159
|
+
hash.update("\0");
|
|
2160
|
+
hash.update(slash(file));
|
|
2161
|
+
hash.update("\0");
|
|
2162
|
+
hash.update(await (0, import_promises3.readFile)((0, import_node_path11.resolve)(paths.cwd, file)));
|
|
2163
|
+
}
|
|
2164
|
+
return hash.digest("hex");
|
|
2165
|
+
}
|
|
2166
|
+
function cachePath(paths) {
|
|
2167
|
+
return (0, import_node_path11.join)(paths.outDir, SYNC_CACHE_NAME);
|
|
2168
|
+
}
|
|
2169
|
+
function serializePath(paths, file) {
|
|
2170
|
+
return slash((0, import_node_path11.relative)(paths.cwd, file));
|
|
2171
|
+
}
|
|
2172
|
+
function deserializePath(paths, file) {
|
|
2173
|
+
return slash((0, import_node_path11.resolve)(paths.cwd, file.split("/").join(import_node_path11.sep)));
|
|
2174
|
+
}
|
|
2175
|
+
function serializeMap(paths, values) {
|
|
2176
|
+
return [...values].map(([file, value]) => [serializePath(paths, file), value]);
|
|
2177
|
+
}
|
|
2178
|
+
function deserializeMap(paths, values) {
|
|
2179
|
+
return new Map(values.map(([file, value]) => [deserializePath(paths, file), value]));
|
|
2180
|
+
}
|
|
2181
|
+
async function readSyncCache(paths, fingerprint) {
|
|
2182
|
+
const file = cachePath(paths);
|
|
2183
|
+
if (!(0, import_node_fs7.existsSync)(file)) {
|
|
2184
|
+
return void 0;
|
|
2185
|
+
}
|
|
2186
|
+
try {
|
|
2187
|
+
const cache = JSON.parse(await (0, import_promises3.readFile)(file, "utf8"));
|
|
2188
|
+
if (cache.version !== CACHE_VERSION || cache.fingerprint !== fingerprint) {
|
|
2189
|
+
return void 0;
|
|
2190
|
+
}
|
|
2191
|
+
return {
|
|
2192
|
+
responsesByFile: deserializeMap(paths, cache.data.responsesByFile),
|
|
2193
|
+
inputsByFile: deserializeMap(paths, cache.data.inputsByFile),
|
|
2194
|
+
securityByFile: deserializeMap(paths, cache.data.securityByFile),
|
|
2195
|
+
hiddenFiles: new Set(cache.data.hiddenFiles.map((entry) => deserializePath(paths, entry))),
|
|
2196
|
+
openapiByFile: deserializeMap(paths, cache.data.openapiByFile)
|
|
2197
|
+
};
|
|
2198
|
+
} catch {
|
|
2199
|
+
return void 0;
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
async function writeSyncCache(paths, fingerprint, data) {
|
|
2203
|
+
const cache = {
|
|
2204
|
+
version: CACHE_VERSION,
|
|
2205
|
+
fingerprint,
|
|
2206
|
+
data: {
|
|
2207
|
+
responsesByFile: serializeMap(paths, data.responsesByFile),
|
|
2208
|
+
inputsByFile: serializeMap(paths, data.inputsByFile),
|
|
2209
|
+
securityByFile: serializeMap(paths, data.securityByFile),
|
|
2210
|
+
hiddenFiles: [...data.hiddenFiles].map((file) => serializePath(paths, file)),
|
|
2211
|
+
openapiByFile: serializeMap(paths, data.openapiByFile)
|
|
2212
|
+
}
|
|
2213
|
+
};
|
|
2214
|
+
await writeJson(cachePath(paths), cache);
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2100
2217
|
// src/generator/sync.ts
|
|
2101
2218
|
async function typeFolders(paths, routes) {
|
|
2102
2219
|
const verbsByDir = /* @__PURE__ */ new Map();
|
|
@@ -2123,57 +2240,17 @@ async function extractResponses(paths, routes) {
|
|
|
2123
2240
|
try {
|
|
2124
2241
|
const { createSchemaProgram: createSchemaProgram2, extractRouteResponses: extractRouteResponses2 } = await Promise.resolve().then(() => (init_schema(), schema_exports));
|
|
2125
2242
|
const files = [...new Set(routes.map((route) => route.file))];
|
|
2126
|
-
const appTypes = (0,
|
|
2127
|
-
const roots = (0,
|
|
2128
|
-
const program = createSchemaProgram2(paths, roots
|
|
2129
|
-
const fallbackFiles = [];
|
|
2243
|
+
const appTypes = (0, import_node_path12.join)(paths.outDir, "types", "app.d.ts");
|
|
2244
|
+
const roots = (0, import_node_fs8.existsSync)(appTypes) ? [...files, appTypes] : files;
|
|
2245
|
+
const program = createSchemaProgram2(paths, roots);
|
|
2130
2246
|
for (const file of files) {
|
|
2131
|
-
|
|
2132
|
-
byFile.set(file, responses);
|
|
2133
|
-
if (hasLooseResponseSchema(responses)) {
|
|
2134
|
-
fallbackFiles.push(file);
|
|
2135
|
-
}
|
|
2136
|
-
}
|
|
2137
|
-
if (fallbackFiles.length > 0) {
|
|
2138
|
-
const fullProgram = createSchemaProgram2(
|
|
2139
|
-
paths,
|
|
2140
|
-
(0, import_node_fs7.existsSync)(appTypes) ? [...fallbackFiles, appTypes] : fallbackFiles
|
|
2141
|
-
);
|
|
2142
|
-
for (const file of fallbackFiles) {
|
|
2143
|
-
byFile.set(file, extractRouteResponses2(fullProgram, file));
|
|
2144
|
-
}
|
|
2247
|
+
byFile.set(file, extractRouteResponses2(program, file));
|
|
2145
2248
|
}
|
|
2146
2249
|
} catch (error) {
|
|
2147
2250
|
console.warn(`giri: skipped response schema generation (${error.message}).`);
|
|
2148
2251
|
}
|
|
2149
2252
|
return byFile;
|
|
2150
2253
|
}
|
|
2151
|
-
function isLooseSchema(value) {
|
|
2152
|
-
if (!value || typeof value !== "object") {
|
|
2153
|
-
return false;
|
|
2154
|
-
}
|
|
2155
|
-
const schema = value;
|
|
2156
|
-
const keys = Object.keys(schema);
|
|
2157
|
-
if (keys.length === 0) {
|
|
2158
|
-
return true;
|
|
2159
|
-
}
|
|
2160
|
-
if (typeof schema.$ref === "string") {
|
|
2161
|
-
return false;
|
|
2162
|
-
}
|
|
2163
|
-
if (Array.isArray(schema.anyOf) && schema.anyOf.some(isLooseSchema)) {
|
|
2164
|
-
return true;
|
|
2165
|
-
}
|
|
2166
|
-
if (schema.items && isLooseSchema(schema.items)) {
|
|
2167
|
-
return true;
|
|
2168
|
-
}
|
|
2169
|
-
if (schema.properties && typeof schema.properties === "object") {
|
|
2170
|
-
return Object.values(schema.properties).some(isLooseSchema);
|
|
2171
|
-
}
|
|
2172
|
-
return false;
|
|
2173
|
-
}
|
|
2174
|
-
function hasLooseResponseSchema(responses) {
|
|
2175
|
-
return responses.responses.some((response) => isLooseSchema(response.schema));
|
|
2176
|
-
}
|
|
2177
2254
|
async function extractMeta(config, paths, routes) {
|
|
2178
2255
|
const inputsByFile = /* @__PURE__ */ new Map();
|
|
2179
2256
|
const securityByFile = /* @__PURE__ */ new Map();
|
|
@@ -2206,28 +2283,44 @@ async function extractMeta(config, paths, routes) {
|
|
|
2206
2283
|
async function syncProject(config, options = {}) {
|
|
2207
2284
|
const paths = resolveGiriPaths(config, options.cwd);
|
|
2208
2285
|
assertSafeOutDir(paths);
|
|
2209
|
-
const hadOutDir = (0,
|
|
2286
|
+
const hadOutDir = (0, import_node_fs8.existsSync)(paths.outDir);
|
|
2210
2287
|
const routes = await scanRoutes(paths.routesDir);
|
|
2211
2288
|
const folders = await typeFolders(paths, routes);
|
|
2212
|
-
await (
|
|
2289
|
+
const fingerprint = await syncFingerprint(config, paths);
|
|
2290
|
+
const cached = await readSyncCache(paths, fingerprint);
|
|
2291
|
+
const generatedFiles = [
|
|
2292
|
+
(0, import_node_path12.join)(paths.outDir, "tsconfig.json"),
|
|
2293
|
+
(0, import_node_path12.join)(paths.outDir, "manifest.json"),
|
|
2294
|
+
(0, import_node_path12.join)(paths.outDir, "openapi.json"),
|
|
2295
|
+
(0, import_node_path12.join)(paths.outDir, "routes.d.ts"),
|
|
2296
|
+
(0, import_node_path12.join)(paths.outDir, "types", "app.d.ts"),
|
|
2297
|
+
...folders.map((folder) => typeFilePath(paths, folder.dir))
|
|
2298
|
+
];
|
|
2299
|
+
if (cached && generatedFiles.every(import_node_fs8.existsSync)) {
|
|
2300
|
+
return { paths, routes, folders, data: cached };
|
|
2301
|
+
}
|
|
2302
|
+
await (0, import_promises4.mkdir)(paths.outDir, { recursive: true });
|
|
2213
2303
|
await writeParamTypes(paths, folders);
|
|
2214
2304
|
await writeRouteTypes(paths, routes);
|
|
2215
2305
|
await writeAppTypes(paths);
|
|
2216
2306
|
await writeTsConfig(paths, config);
|
|
2217
|
-
const
|
|
2218
|
-
|
|
2219
|
-
|
|
2307
|
+
const data = cached ?? {
|
|
2308
|
+
responsesByFile: await extractResponses(paths, routes),
|
|
2309
|
+
...await extractMeta(config, paths, routes)
|
|
2310
|
+
};
|
|
2220
2311
|
await writeManifest(paths, routes, data);
|
|
2221
2312
|
await writeOpenApi(paths, routes, data);
|
|
2313
|
+
await writeSyncCache(paths, fingerprint, data);
|
|
2222
2314
|
if (hadOutDir) {
|
|
2223
2315
|
await pruneDir(
|
|
2224
2316
|
paths.outDir,
|
|
2225
2317
|
/* @__PURE__ */ new Set([
|
|
2226
|
-
(0,
|
|
2227
|
-
(0,
|
|
2228
|
-
(0,
|
|
2229
|
-
(0,
|
|
2230
|
-
(0,
|
|
2318
|
+
(0, import_node_path12.join)(paths.outDir, "tsconfig.json"),
|
|
2319
|
+
(0, import_node_path12.join)(paths.outDir, "manifest.json"),
|
|
2320
|
+
(0, import_node_path12.join)(paths.outDir, "openapi.json"),
|
|
2321
|
+
(0, import_node_path12.join)(paths.outDir, "routes.d.ts"),
|
|
2322
|
+
(0, import_node_path12.join)(paths.outDir, SYNC_CACHE_NAME),
|
|
2323
|
+
(0, import_node_path12.join)(paths.outDir, "types", "app.d.ts"),
|
|
2231
2324
|
...folders.map((folder) => typeFilePath(paths, folder.dir))
|
|
2232
2325
|
])
|
|
2233
2326
|
);
|
|
@@ -2236,27 +2329,33 @@ async function syncProject(config, options = {}) {
|
|
|
2236
2329
|
}
|
|
2237
2330
|
|
|
2238
2331
|
// src/generator/watch.ts
|
|
2239
|
-
var
|
|
2332
|
+
var import_node_fs10 = require("fs");
|
|
2333
|
+
var import_node_path15 = require("path");
|
|
2334
|
+
|
|
2335
|
+
// src/loader/import-graph.ts
|
|
2336
|
+
var import_node_fs9 = require("fs");
|
|
2240
2337
|
var import_node_path13 = require("path");
|
|
2338
|
+
var import_typescript5 = __toESM(require("typescript"));
|
|
2339
|
+
var import_tinyglobby3 = require("tinyglobby");
|
|
2241
2340
|
|
|
2242
2341
|
// src/loader/module-loader.ts
|
|
2243
|
-
var
|
|
2342
|
+
var import_node_path14 = require("path");
|
|
2244
2343
|
|
|
2245
2344
|
// src/lifecycle.ts
|
|
2246
|
-
var
|
|
2247
|
-
var
|
|
2345
|
+
var import_node_fs11 = require("fs");
|
|
2346
|
+
var import_node_path16 = require("path");
|
|
2248
2347
|
var MAIN_EXTENSIONS2 = ["ts", "tsx", "mts", "cts", "js", "jsx", "mjs", "cjs"];
|
|
2249
2348
|
function resolveMainFile(cwd) {
|
|
2250
2349
|
for (const ext of MAIN_EXTENSIONS2) {
|
|
2251
|
-
const file = (0,
|
|
2252
|
-
if ((0,
|
|
2350
|
+
const file = (0, import_node_path16.join)(cwd, "src", `main.${ext}`);
|
|
2351
|
+
if ((0, import_node_fs11.existsSync)(file)) {
|
|
2253
2352
|
return file;
|
|
2254
2353
|
}
|
|
2255
2354
|
}
|
|
2256
2355
|
return void 0;
|
|
2257
2356
|
}
|
|
2258
2357
|
async function loadLifecycle(cwd = process.cwd()) {
|
|
2259
|
-
const file = resolveMainFile((0,
|
|
2358
|
+
const file = resolveMainFile((0, import_node_path16.resolve)(cwd));
|
|
2260
2359
|
if (!file) {
|
|
2261
2360
|
return {};
|
|
2262
2361
|
}
|