asphodelos 0.0.1 → 0.2.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 CHANGED
@@ -250,10 +250,6 @@ export default defineConfig({
250
250
  })
251
251
  ```
252
252
 
253
- TanStack-family mutations also get a `<operation>MutationOptions()` factory, and SWR queries a
254
- `useImmutable<Operation>` hook. The generated hooks are compiled and run against the real
255
- libraries in [`test/`](test/README.md).
256
-
257
253
  ### Infinite Query (`x-pagination`)
258
254
 
259
255
  Set `x-pagination: true` on a GET operation to generate infinite query hooks.
@@ -511,7 +507,7 @@ name:
511
507
  | String | `x-minLength-message`, `x-maxLength-message`, `x-pattern-message`, `x-length-message` |
512
508
  | Array | `x-minItems-message`, `x-maxItems-message`, `x-uniqueItems-message`, `x-contains-message`, `x-minContains-message`, `x-maxContains-message`, `x-prefixItems-message`, `x-items-message` |
513
509
  | Object | `x-minProperties-message`, `x-maxProperties-message`, `x-additionalProperties-message`†, `x-propertyNames-message`, `x-patternProperties-message`†, `x-dependentRequired-message`, `x-dependentSchemas-message`, `x-properties-message`†, `x-unevaluatedProperties-message`†, `x-unevaluatedItems-message`† |
514
- | Combinators | `x-allOf-message`‡, `x-anyOf-message`, `x-oneOf-message`, `x-not-message`, `x-implication-message` |
510
+ | Composition | `x-allOf-message`‡, `x-anyOf-message`, `x-oneOf-message`, `x-not-message`, `x-implication-message` |
515
511
  | Conditional | `x-if-message`†, `x-then-message`†, `x-else-message`† |
516
512
 
517
513
  - † Kept on the schema, but Elysia 1.4 cannot route a 422 to it.
@@ -586,7 +582,7 @@ bun run test:clients # build, then compile and run the generated hooks under t
586
582
  bun run test:pack # build, pack, and install the tarball with npm into an empty project
587
583
  ```
588
584
 
589
- Coding agents: start with [AGENTS.md](AGENTS.md).
585
+ Coding agents: start with [AGENTS.md](https://github.com/nakita628/asphodelos/blob/main/AGENTS.md).
590
586
 
591
587
  ## License
592
588
 
package/dist/cli.mjs CHANGED
@@ -45,7 +45,7 @@ function runConfigPass(configPath, reload) {
45
45
  import("./index.mjs"),
46
46
  import("./openapi-B4aAnx4P.mjs").then((n) => n.t),
47
47
  import("./format-B0W7HIAg.mjs").then((n) => n.r),
48
- import("./shared-CrbXsFUJ.mjs").then((n) => n.a)
48
+ import("./shared-B-ADz5ww.mjs").then((n) => n.a)
49
49
  ]));
50
50
  const config = yield* readConfig(configPath, reload);
51
51
  const jobs = makeJob(yield* parseOpenAPI(config.input), config);
@@ -102,7 +102,7 @@ function awaitChange(configPath, inputDirectory) {
102
102
  * not take the watcher down with it.
103
103
  *
104
104
  * Recursive rather than a loop because the directory to watch comes from the config, and the
105
- * config is re-read every round: an edit that repoints `input` elsewhere has to move the watcher
105
+ * config is re-read every round: an edit that points `input` somewhere else has to move the watcher
106
106
  * with it, which means new streams rather than new values.
107
107
  */
108
108
  function watchConfig(configPath, inputDirectory) {
@@ -140,7 +140,7 @@ function generate(args) {
140
140
  if (output !== void 0 && input === void 0) return yield* reject("-o <output.ts> requires an <input> document.");
141
141
  if (args.watch && (input !== void 0 || output !== void 0)) return yield* reject("--watch runs a config file, so it cannot be combined with <input> or --output.");
142
142
  if (input !== void 0 && output !== void 0) {
143
- const [{ parseOpenAPI }, { elysia }] = yield* Effect.promise(() => Promise.all([import("./openapi-B4aAnx4P.mjs").then((n) => n.t), import("./core-DS3sAabb.mjs").then((n) => n.t)]));
143
+ const [{ parseOpenAPI }, { elysia }] = yield* Effect.promise(() => Promise.all([import("./openapi-B4aAnx4P.mjs").then((n) => n.t), import("./core-C1NqA5VJ.mjs").then((n) => n.t)]));
144
144
  return yield* Console.log(yield* elysia(yield* parseOpenAPI(input), { output }));
145
145
  }
146
146
  const resolvedConfig = configPath ?? DEFAULT_CONFIG_FILE;
@@ -385,7 +385,7 @@ function sccSchemas(schemas) {
385
385
  const lowlink = /* @__PURE__ */ new Map();
386
386
  const onStack = /* @__PURE__ */ new Set();
387
387
  const stack = [];
388
- const sccs = [];
388
+ const groups = [];
389
389
  const counter = { value: 0 };
390
390
  const strongconnect = (v) => {
391
391
  index.set(v, counter.value);
@@ -407,11 +407,11 @@ function sccSchemas(schemas) {
407
407
  if (def) group.push(def);
408
408
  if (w === v) break;
409
409
  }
410
- sccs.push(group);
410
+ groups.push(group);
411
411
  }
412
412
  };
413
413
  for (const { name } of schemas) if (!index.has(name)) strongconnect(name);
414
- return sccs;
414
+ return groups;
415
415
  }
416
416
  const REF_SUFFIX = {
417
417
  schemas: "Schema",
@@ -1666,12 +1666,12 @@ function fileNameOf(group) {
1666
1666
  return uncapitalize(group.map((g) => g.name).toSorted()[0] ?? "schema");
1667
1667
  }
1668
1668
  function splitSchemaFiles(section, readonly, exportTypes) {
1669
- const sccs = sccSchemas(Object.entries(section).map(([name, schema]) => ({
1669
+ const groups = sccSchemas(Object.entries(section).map(([name, schema]) => ({
1670
1670
  name,
1671
1671
  schema
1672
1672
  })));
1673
- const nameToFile = new Map(sccs.flatMap((g) => g.map((s) => [s.name, fileNameOf(g)])));
1674
- return sccs.map((group) => {
1673
+ const nameToFile = new Map(groups.flatMap((g) => g.map((s) => [s.name, fileNameOf(g)])));
1674
+ return groups.map((group) => {
1675
1675
  const fileName = fileNameOf(group);
1676
1676
  const body = schemasCode(Object.fromEntries(group.map((g) => [g.name, g.schema])), readonly, exportTypes);
1677
1677
  if (body === "") return {
@@ -2248,8 +2248,9 @@ function optionsObjectType(config, optionsType) {
2248
2248
  }
2249
2249
  const QUERY_OMIT_KEYS = `'queryKey' | 'queryFn'`;
2250
2250
  const INFINITE_OMIT_KEYS = `'queryKey' | 'queryFn' | 'initialPageParam' | 'getNextPageParam'`;
2251
- function omitInjectedKeys(config, optionsType, keys) {
2252
- return `Omit<${config.maybeRefOptions ? `Extract<${optionsType}, { queryKey: unknown }>` : optionsObjectType(config, optionsType)}, ${keys}>`;
2251
+ const MUTATION_OMIT_KEYS = `'mutationKey' | 'mutationFn'`;
2252
+ function omitInjectedKeys(config, optionsType, keys, marker = "{ queryKey: unknown }") {
2253
+ return `Omit<${config.maybeRefOptions ? `Extract<${optionsType}, ${marker}>` : optionsObjectType(config, optionsType)}, ${keys}>`;
2253
2254
  }
2254
2255
  function makeGetQueryOptionsParam(config, dataT, keyName) {
2255
2256
  const optType = config.queryOptionsType;
@@ -2260,8 +2261,8 @@ function makeGetQueryOptionsParam(config, dataT, keyName) {
2260
2261
  return `queryOptions?: ${omit(`${optType}<${dataT}, TError, TData>`)}`;
2261
2262
  }
2262
2263
  function makeMutationOptionsParam(config, dataT, errorT, variablesType) {
2263
- const optType = `${config.mutationOptionsType}<${dataT}, ${errorT}, ${variablesType}>`;
2264
- return config.thunkOptionsCall ? `mutationOptions?: () => ${optionsObjectType(config, optType)}` : `mutationOptions?: ${optType}`;
2264
+ const optType = omitInjectedKeys(config, `${config.mutationOptionsType}<${dataT}, ${errorT}, ${variablesType}>`, MUTATION_OMIT_KEYS, "{ mutationKey?: unknown }");
2265
+ return config.thunkOptionsCall ? `mutationOptions?: () => ${optType}` : `mutationOptions?: ${optType}`;
2265
2266
  }
2266
2267
  function makeGetHookBody(config, dataT, keyCall, queryFnBlock) {
2267
2268
  const inner = `${config.thunkOptionsCall ? "...queryOptions?.()" : "...queryOptions"},queryKey:${keyCall},${queryFnBlock}`;
@@ -3427,7 +3428,7 @@ function delayMiddleware(delay) {
3427
3428
  * test) starts no server.
3428
3429
  *
3429
3430
  * A secured operation that declares a 401 checks for the credential first, and a path parameter
3430
- * with a recognisable "missing" value answers 404 — so a client can drive the unhappy paths the
3431
+ * with a recognizable "missing" value answers 404 — so a client can drive the unhappy paths the
3431
3432
  * document promises, not just the happy one.
3432
3433
  */
3433
3434
  function makeMock(spec, options = {}) {
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-wcPFST8Q.mjs";
2
- import { S as unlink, _ as responses, a as hooks, c as mediaTypes, d as links, f as securitySchemes, g as parameters, h as examples, i as mock, l as pathItems, m as requestBodies, n as types, o as elysia, p as headers, r as test, s as eden, u as callbacks, v as schemas, x as readdir, y as components } from "./core-DS3sAabb.mjs";
2
+ import { S as unlink, _ as responses, a as hooks, c as mediaTypes, d as links, f as securitySchemes, g as parameters, h as examples, i as mock, l as pathItems, m as requestBodies, n as types, o as elysia, p as headers, r as test, s as eden, u as callbacks, v as schemas, x as readdir, y as components } from "./core-C1NqA5VJ.mjs";
3
3
  import { Effect } from "effect";
4
4
  import path, { posix } from "node:path";
5
5
  //#region src/shared/index.ts
@@ -1,8 +1,8 @@
1
1
  import { parseConfig } from "../index.mjs";
2
2
  import { t as FormatOptions } from "../format-B0W7HIAg.mjs";
3
- import { b as fileSystemLayer } from "../core-DS3sAabb.mjs";
3
+ import { b as fileSystemLayer } from "../core-C1NqA5VJ.mjs";
4
4
  import { n as parseOpenAPI } from "../openapi-B4aAnx4P.mjs";
5
- import { i as makeJob, n as isUserCodeJob, r as jobTargets, t as cleanSplitOutputs } from "../shared-CrbXsFUJ.mjs";
5
+ import { i as makeJob, n as isUserCodeJob, r as jobTargets, t as cleanSplitOutputs } from "../shared-B-ADz5ww.mjs";
6
6
  import { Effect, FileSystem, Result } from "effect";
7
7
  import path from "node:path";
8
8
  import crypto from "node:crypto";
@@ -42,7 +42,7 @@ function messageOf(error) {
42
42
  /**
43
43
  * Loads and validates the config through Vite's own module loader.
44
44
  *
45
- * `ssrLoadModule` rather than the CLI's `readConfig`: Vite already transpiles TypeScript and
45
+ * `ssrLoadModule` rather than the CLI's `readConfig`: Vite already compiles TypeScript and
46
46
  * resolves the config's imports the way the rest of the project sees them, and invalidating the
47
47
  * module is how an edit is picked up. Every failure comes back as the sentence to print.
48
48
  */
@@ -178,7 +178,7 @@ function removeStaleOutput(output, keep) {
178
178
  /**
179
179
  * Removes what the previous pass generated and this one no longer does, answering with what went.
180
180
  *
181
- * A config edit that repoints or drops an output, or a document that no longer has a section,
181
+ * A config edit that moves or drops an output, or a document that no longer has a section,
182
182
  * would otherwise leave the old file behind, still importing names that are gone. Deliberately
183
183
  * narrower than a recursive delete, because a path the config used to name may be shared with the
184
184
  * user:
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "asphodelos",
3
- "version": "0.0.1",
4
- "description": "Generate type-safe Elysia code routes, TypeBox schemas, Eden wrappers, client hooks, tests and a mock server — from OpenAPI or TypeSpec",
3
+ "version": "0.2.1",
4
+ "description": "Asphodelos is a code generator from OpenAPI to Elysia",
5
5
  "keywords": [
6
6
  "elysia",
7
7
  "openapi"
@@ -36,22 +36,17 @@
36
36
  }
37
37
  },
38
38
  "scripts": {
39
- "dev": "bun run src/index.ts",
40
39
  "build": "tsdown",
41
40
  "lint": "oxlint",
42
- "lint:fix": "oxlint --fix",
43
41
  "test": "bun test",
44
- "typecheck": "tsc --noEmit",
45
- "prepublishOnly": "bun run build",
46
- "prepack": "cp ../../README.md ../../LICENSE .",
47
- "postpack": "rm -f README.md LICENSE"
42
+ "typecheck": "tsc --noEmit"
48
43
  },
49
44
  "dependencies": {
50
45
  "@apidevtools/swagger-parser": "^12.1.0",
51
46
  "@effect/platform-node": "4.0.0-rc.112",
52
47
  "@effect/platform-node-shared": "4.0.0-rc.112",
53
- "@typespec/compiler": "^1.11.0",
54
- "@typespec/openapi3": "^1.11.0",
48
+ "@typespec/compiler": "^1.16.0",
49
+ "@typespec/openapi3": "^1.16.0",
55
50
  "effect": "4.0.0-rc.112",
56
51
  "oxfmt": "^0.67.0",
57
52
  "ts-morph": "^28.0.0"
@@ -60,9 +55,9 @@
60
55
  "@faker-js/faker": "^10.6.0",
61
56
  "@sinclair/typebox": "^0.34.49",
62
57
  "@types/bun": "latest",
63
- "@typespec/http": "^1.11.0",
64
- "@typespec/rest": "^0.81.0",
65
- "@typespec/versioning": "^0.81.0",
58
+ "@typespec/http": "^1.16.0",
59
+ "@typespec/rest": "^0.86.0",
60
+ "@typespec/versioning": "^0.86.0",
66
61
  "elysia": "^1.4.28",
67
62
  "oxlint": "^1.82.0",
68
63
  "oxlint-tsgolint": "^7.0.2001",