@async/db 0.2.0

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.
Files changed (398) hide show
  1. package/CHANGELOG.md +167 -0
  2. package/README.md +431 -0
  3. package/SPEC.md +1429 -0
  4. package/db.config.example.mjs +128 -0
  5. package/dist/cli/args.d.ts +8 -0
  6. package/dist/cli/args.js +16 -0
  7. package/dist/cli/commands/create.d.ts +3 -0
  8. package/dist/cli/commands/create.js +13 -0
  9. package/dist/cli/commands/doctor.d.ts +3 -0
  10. package/dist/cli/commands/doctor.js +31 -0
  11. package/dist/cli/commands/generate.d.ts +6 -0
  12. package/dist/cli/commands/generate.js +24 -0
  13. package/dist/cli/commands/operations.d.ts +12 -0
  14. package/dist/cli/commands/operations.js +61 -0
  15. package/dist/cli/commands/schema.d.ts +11 -0
  16. package/dist/cli/commands/schema.js +1086 -0
  17. package/dist/cli/commands/serve.d.ts +9 -0
  18. package/dist/cli/commands/serve.js +18 -0
  19. package/dist/cli/commands/sync.d.ts +3 -0
  20. package/dist/cli/commands/sync.js +11 -0
  21. package/dist/cli/commands/types.d.ts +7 -0
  22. package/dist/cli/commands/types.js +37 -0
  23. package/dist/cli/commands/viewer.d.ts +6 -0
  24. package/dist/cli/commands/viewer.js +29 -0
  25. package/dist/cli/index.d.ts +2 -0
  26. package/dist/cli/index.js +108 -0
  27. package/dist/cli/output.d.ts +25 -0
  28. package/dist/cli/output.js +149 -0
  29. package/dist/cli/schema-prompt.d.ts +20 -0
  30. package/dist/cli/schema-prompt.js +66 -0
  31. package/dist/cli.d.ts +2 -0
  32. package/dist/cli.js +3 -0
  33. package/dist/client-cache.d.ts +105 -0
  34. package/dist/client-cache.js +916 -0
  35. package/dist/client.d.ts +64 -0
  36. package/dist/client.js +405 -0
  37. package/dist/config-public.d.ts +1 -0
  38. package/dist/config-public.js +1 -0
  39. package/dist/config.d.ts +54 -0
  40. package/dist/config.js +2 -0
  41. package/dist/csv.d.ts +1 -0
  42. package/dist/csv.js +1 -0
  43. package/dist/db.d.ts +3 -0
  44. package/dist/db.js +3 -0
  45. package/dist/doctor.d.ts +1 -0
  46. package/dist/doctor.js +1 -0
  47. package/dist/errors.d.ts +1 -0
  48. package/dist/errors.js +1 -0
  49. package/dist/features/config/defaults.d.ts +98 -0
  50. package/dist/features/config/defaults.js +95 -0
  51. package/dist/features/config/load.d.ts +11 -0
  52. package/dist/features/config/load.js +265 -0
  53. package/dist/features/config/public.d.ts +17 -0
  54. package/dist/features/config/public.js +75 -0
  55. package/dist/features/doctor/duplicate-ids.d.ts +18 -0
  56. package/dist/features/doctor/duplicate-ids.js +79 -0
  57. package/dist/features/doctor/field-consistency.d.ts +17 -0
  58. package/dist/features/doctor/field-consistency.js +48 -0
  59. package/dist/features/doctor/index.d.ts +39 -0
  60. package/dist/features/doctor/index.js +177 -0
  61. package/dist/features/doctor/relations.d.ts +22 -0
  62. package/dist/features/doctor/relations.js +90 -0
  63. package/dist/features/doctor/schema-guidance.d.ts +35 -0
  64. package/dist/features/doctor/schema-guidance.js +184 -0
  65. package/dist/features/generate/registry.d.ts +14 -0
  66. package/dist/features/generate/registry.js +37 -0
  67. package/dist/features/http/registry.d.ts +46 -0
  68. package/dist/features/http/registry.js +86 -0
  69. package/dist/features/operations/index.d.ts +49 -0
  70. package/dist/features/operations/index.js +199 -0
  71. package/dist/features/operations/maps.d.ts +1 -0
  72. package/dist/features/operations/maps.js +10 -0
  73. package/dist/features/operations/readiness.d.ts +30 -0
  74. package/dist/features/operations/readiness.js +228 -0
  75. package/dist/features/operations/runtime.d.ts +57 -0
  76. package/dist/features/operations/runtime.js +288 -0
  77. package/dist/features/runtime/collection.d.ts +51 -0
  78. package/dist/features/runtime/collection.js +198 -0
  79. package/dist/features/runtime/db.d.ts +152 -0
  80. package/dist/features/runtime/db.js +824 -0
  81. package/dist/features/runtime/document.d.ts +43 -0
  82. package/dist/features/runtime/document.js +111 -0
  83. package/dist/features/runtime/fanout.d.ts +24 -0
  84. package/dist/features/runtime/fanout.js +77 -0
  85. package/dist/features/runtime/json-pointer.d.ts +5 -0
  86. package/dist/features/runtime/json-pointer.js +49 -0
  87. package/dist/features/runtime/scope-state.d.ts +44 -0
  88. package/dist/features/runtime/scope-state.js +185 -0
  89. package/dist/features/runtime/state.d.ts +1 -0
  90. package/dist/features/runtime/state.js +1 -0
  91. package/dist/features/schema/api.d.ts +107 -0
  92. package/dist/features/schema/api.js +460 -0
  93. package/dist/features/schema/builders.d.ts +86 -0
  94. package/dist/features/schema/builders.js +110 -0
  95. package/dist/features/schema/fields.d.ts +38 -0
  96. package/dist/features/schema/fields.js +296 -0
  97. package/dist/features/schema/generated.d.ts +29 -0
  98. package/dist/features/schema/generated.js +32 -0
  99. package/dist/features/schema/locator.d.ts +16 -0
  100. package/dist/features/schema/locator.js +135 -0
  101. package/dist/features/schema/manifest.d.ts +91 -0
  102. package/dist/features/schema/manifest.js +384 -0
  103. package/dist/features/schema/metadata.d.ts +30 -0
  104. package/dist/features/schema/metadata.js +75 -0
  105. package/dist/features/schema/project.d.ts +46 -0
  106. package/dist/features/schema/project.js +442 -0
  107. package/dist/features/schema/relations.d.ts +38 -0
  108. package/dist/features/schema/relations.js +109 -0
  109. package/dist/features/schema/resolvers.d.ts +36 -0
  110. package/dist/features/schema/resolvers.js +111 -0
  111. package/dist/features/schema/resource.d.ts +75 -0
  112. package/dist/features/schema/resource.js +253 -0
  113. package/dist/features/schema/source-definitions.d.ts +21 -0
  114. package/dist/features/schema/source-definitions.js +29 -0
  115. package/dist/features/schema/sources.d.ts +83 -0
  116. package/dist/features/schema/sources.js +689 -0
  117. package/dist/features/schema/standard-schema.d.ts +57 -0
  118. package/dist/features/schema/standard-schema.js +232 -0
  119. package/dist/features/schema/validation.d.ts +69 -0
  120. package/dist/features/schema/validation.js +434 -0
  121. package/dist/features/storage/events.d.ts +12 -0
  122. package/dist/features/storage/events.js +30 -0
  123. package/dist/features/storage/json.d.ts +112 -0
  124. package/dist/features/storage/json.js +239 -0
  125. package/dist/features/storage/memory.d.ts +30 -0
  126. package/dist/features/storage/memory.js +44 -0
  127. package/dist/features/storage/resource-json.d.ts +31 -0
  128. package/dist/features/storage/resource-json.js +76 -0
  129. package/dist/features/storage/runtime.d.ts +37 -0
  130. package/dist/features/storage/runtime.js +184 -0
  131. package/dist/features/storage/source-metadata.d.ts +20 -0
  132. package/dist/features/storage/source-metadata.js +25 -0
  133. package/dist/features/storage/source.d.ts +37 -0
  134. package/dist/features/storage/source.js +60 -0
  135. package/dist/features/storage/static.d.ts +29 -0
  136. package/dist/features/storage/static.js +42 -0
  137. package/dist/features/sync/defaults.d.ts +21 -0
  138. package/dist/features/sync/defaults.js +21 -0
  139. package/dist/features/sync/index.d.ts +35 -0
  140. package/dist/features/sync/index.js +85 -0
  141. package/dist/features/sync/mirror-state.d.ts +14 -0
  142. package/dist/features/sync/mirror-state.js +4 -0
  143. package/dist/features/sync/runtime-dirs.d.ts +5 -0
  144. package/dist/features/sync/runtime-dirs.js +9 -0
  145. package/dist/features/sync/source-writes.d.ts +15 -0
  146. package/dist/features/sync/source-writes.js +27 -0
  147. package/dist/features/sync/synthetic-seed.d.ts +26 -0
  148. package/dist/features/sync/synthetic-seed.js +83 -0
  149. package/dist/features/viewer/manifest.d.ts +148 -0
  150. package/dist/features/viewer/manifest.js +165 -0
  151. package/dist/fs-utils.d.ts +1 -0
  152. package/dist/fs-utils.js +1 -0
  153. package/dist/generate/hono/app.d.ts +6 -0
  154. package/dist/generate/hono/app.js +51 -0
  155. package/dist/generate/hono/graphql.d.ts +7 -0
  156. package/dist/generate/hono/graphql.js +53 -0
  157. package/dist/generate/hono/index.d.ts +55 -0
  158. package/dist/generate/hono/index.js +140 -0
  159. package/dist/generate/hono/package.d.ts +6 -0
  160. package/dist/generate/hono/package.js +44 -0
  161. package/dist/generate/hono/readme.d.ts +13 -0
  162. package/dist/generate/hono/readme.js +28 -0
  163. package/dist/generate/hono/repository.d.ts +1 -0
  164. package/dist/generate/hono/repository.js +27 -0
  165. package/dist/generate/hono/rest.d.ts +1 -0
  166. package/dist/generate/hono/rest.js +38 -0
  167. package/dist/generate/hono/schema.d.ts +13 -0
  168. package/dist/generate/hono/schema.js +18 -0
  169. package/dist/generate/hono/sqlite.d.ts +20 -0
  170. package/dist/generate/hono/sqlite.js +266 -0
  171. package/dist/generate/hono/validators.d.ts +1 -0
  172. package/dist/generate/hono/validators.js +141 -0
  173. package/dist/generate/hono.d.ts +1 -0
  174. package/dist/generate/hono.js +1 -0
  175. package/dist/graphql/execute.d.ts +14 -0
  176. package/dist/graphql/execute.js +719 -0
  177. package/dist/graphql/http.d.ts +15 -0
  178. package/dist/graphql/http.js +29 -0
  179. package/dist/graphql/index.d.ts +3 -0
  180. package/dist/graphql/index.js +3 -0
  181. package/dist/graphql/parser.d.ts +54 -0
  182. package/dist/graphql/parser.js +433 -0
  183. package/dist/hono.d.ts +77 -0
  184. package/dist/hono.js +1 -0
  185. package/dist/index.d.ts +1065 -0
  186. package/dist/index.js +14 -0
  187. package/dist/integrations/hono.d.ts +136 -0
  188. package/dist/integrations/hono.js +508 -0
  189. package/dist/integrations/kv.d.ts +69 -0
  190. package/dist/integrations/kv.js +69 -0
  191. package/dist/integrations/postgres.d.ts +52 -0
  192. package/dist/integrations/postgres.js +113 -0
  193. package/dist/integrations/sqlite.d.ts +112 -0
  194. package/dist/integrations/sqlite.js +489 -0
  195. package/dist/integrations/vite.d.ts +45 -0
  196. package/dist/integrations/vite.js +111 -0
  197. package/dist/json.d.ts +48 -0
  198. package/dist/json.js +1 -0
  199. package/dist/jsonc.d.ts +1 -0
  200. package/dist/jsonc.js +1 -0
  201. package/dist/kv.d.ts +24 -0
  202. package/dist/kv.js +1 -0
  203. package/dist/mock.d.ts +1 -0
  204. package/dist/mock.js +1 -0
  205. package/dist/names.d.ts +1 -0
  206. package/dist/names.js +1 -0
  207. package/dist/operations.d.ts +3 -0
  208. package/dist/operations.js +3 -0
  209. package/dist/postgres.d.ts +24 -0
  210. package/dist/postgres.js +1 -0
  211. package/dist/redis.d.ts +14 -0
  212. package/dist/redis.js +1 -0
  213. package/dist/rest/formats.d.ts +80 -0
  214. package/dist/rest/formats.js +318 -0
  215. package/dist/rest/handler.d.ts +111 -0
  216. package/dist/rest/handler.js +833 -0
  217. package/dist/rest/shape.d.ts +33 -0
  218. package/dist/rest/shape.js +218 -0
  219. package/dist/schema-builders.d.ts +1 -0
  220. package/dist/schema-builders.js +1 -0
  221. package/dist/schema-manifest.d.ts +1 -0
  222. package/dist/schema-manifest.js +1 -0
  223. package/dist/schema.d.ts +193 -0
  224. package/dist/schema.js +6 -0
  225. package/dist/server.d.ts +116 -0
  226. package/dist/server.js +601 -0
  227. package/dist/shared/csv.d.ts +8 -0
  228. package/dist/shared/csv.js +149 -0
  229. package/dist/shared/errors.d.ts +40 -0
  230. package/dist/shared/errors.js +55 -0
  231. package/dist/shared/fs-utils.d.ts +4 -0
  232. package/dist/shared/fs-utils.js +30 -0
  233. package/dist/shared/jsonc.d.ts +2 -0
  234. package/dist/shared/jsonc.js +99 -0
  235. package/dist/shared/mock.d.ts +40 -0
  236. package/dist/shared/mock.js +83 -0
  237. package/dist/shared/names.d.ts +28 -0
  238. package/dist/shared/names.js +127 -0
  239. package/dist/shared/operations.d.ts +32 -0
  240. package/dist/shared/operations.js +302 -0
  241. package/dist/sqlite.d.ts +24 -0
  242. package/dist/sqlite.js +1 -0
  243. package/dist/state.d.ts +1 -0
  244. package/dist/state.js +1 -0
  245. package/dist/sync.d.ts +1 -0
  246. package/dist/sync.js +1 -0
  247. package/dist/tracing.d.ts +95 -0
  248. package/dist/tracing.js +260 -0
  249. package/dist/types.d.ts +51 -0
  250. package/dist/types.js +285 -0
  251. package/dist/viewer-manifest.d.ts +1 -0
  252. package/dist/viewer-manifest.js +1 -0
  253. package/dist/vite.d.ts +59 -0
  254. package/dist/vite.js +1 -0
  255. package/dist/web/json-viewer.d.ts +5 -0
  256. package/dist/web/json-viewer.js +176 -0
  257. package/dist/web/viewer.d.ts +12 -0
  258. package/dist/web/viewer.js +1015 -0
  259. package/docs/README.md +42 -0
  260. package/docs/architecture.md +112 -0
  261. package/docs/ci-and-release.md +177 -0
  262. package/docs/cms-storage-patterns.md +108 -0
  263. package/docs/concepts.md +141 -0
  264. package/docs/configuration.md +552 -0
  265. package/docs/fixtures-and-schemas.md +527 -0
  266. package/docs/fork-branch-workflows.md +108 -0
  267. package/docs/generated-files.md +174 -0
  268. package/docs/getting-started.md +165 -0
  269. package/docs/integrations.md +206 -0
  270. package/docs/json-production.md +120 -0
  271. package/docs/package-api.md +418 -0
  272. package/docs/prototype-to-production.md +378 -0
  273. package/docs/server-and-viewer.md +466 -0
  274. package/docs/store-graduation.md +120 -0
  275. package/docs/typescript-schema-sources.md +79 -0
  276. package/examples/advanced/README.md +55 -0
  277. package/examples/advanced/db/projects.schema.jsonc +44 -0
  278. package/examples/advanced/db/settings.jsonc +9 -0
  279. package/examples/advanced/db/users.json +23 -0
  280. package/examples/advanced/db/users.schema.mjs +31 -0
  281. package/examples/advanced/db.config.mjs +18 -0
  282. package/examples/advanced/example.json +5 -0
  283. package/examples/advanced/src/generated/db.types.d.ts +64 -0
  284. package/examples/basic/README.md +95 -0
  285. package/examples/basic/db/operations/get-user.jsonc +8 -0
  286. package/examples/basic/db/settings.json +7 -0
  287. package/examples/basic/db/users.schema.jsonc +36 -0
  288. package/examples/basic/db.config.mjs +68 -0
  289. package/examples/basic/example.json +5 -0
  290. package/examples/basic/src/generated/db.types.d.ts +39 -0
  291. package/examples/cms-json-publish/README.md +21 -0
  292. package/examples/cms-json-publish/db/navigation.json +7 -0
  293. package/examples/cms-json-publish/db/pages.json +18 -0
  294. package/examples/cms-json-publish/example.json +5 -0
  295. package/examples/cms-json-publish/src/cms.mjs +104 -0
  296. package/examples/computed-fields/README.md +93 -0
  297. package/examples/computed-fields/db/orders.schema.mjs +62 -0
  298. package/examples/computed-fields/db/posts.schema.mjs +59 -0
  299. package/examples/computed-fields/db/products.schema.mjs +39 -0
  300. package/examples/computed-fields/db/users.schema.mjs +43 -0
  301. package/examples/computed-fields/db.config.mjs +15 -0
  302. package/examples/computed-fields/example.json +5 -0
  303. package/examples/computed-fields/src/generated/db.types.d.ts +81 -0
  304. package/examples/content-collections/README.md +91 -0
  305. package/examples/content-collections/db/authors.json +12 -0
  306. package/examples/content-collections/db/authors.schema.mjs +20 -0
  307. package/examples/content-collections/db/blog/draft-roadmap.mdx +12 -0
  308. package/examples/content-collections/db/blog/index.schema.mjs +61 -0
  309. package/examples/content-collections/db/blog/launch-notes.mdx +15 -0
  310. package/examples/content-collections/db/docs/index.schema.mjs +32 -0
  311. package/examples/content-collections/db/docs/intro.mdx +11 -0
  312. package/examples/content-collections/db/docs/schema-workflow.mdx +10 -0
  313. package/examples/content-collections/db/site.schema.jsonc +21 -0
  314. package/examples/content-collections/db.config.mjs +26 -0
  315. package/examples/content-collections/example.json +5 -0
  316. package/examples/content-collections/src/content-preview.mjs +66 -0
  317. package/examples/content-collections/src/generated/db.types.d.ts +81 -0
  318. package/examples/csv/README.md +52 -0
  319. package/examples/csv/db/customers.csv +4 -0
  320. package/examples/csv/db.config.mjs +13 -0
  321. package/examples/csv/example.json +5 -0
  322. package/examples/data-first/README.md +54 -0
  323. package/examples/data-first/db/posts.json +16 -0
  324. package/examples/data-first/db/settings.json +8 -0
  325. package/examples/data-first/db/users.json +14 -0
  326. package/examples/data-first/db.config.mjs +13 -0
  327. package/examples/data-first/example.json +5 -0
  328. package/examples/diagnostics/README.md +55 -0
  329. package/examples/diagnostics/db/projects.schema.jsonc +27 -0
  330. package/examples/diagnostics/db/users.json +9 -0
  331. package/examples/diagnostics/db/users.schema.jsonc +23 -0
  332. package/examples/diagnostics/db.config.mjs +16 -0
  333. package/examples/diagnostics/example.json +5 -0
  334. package/examples/free-plan-upgrade/README.md +22 -0
  335. package/examples/free-plan-upgrade/db/appSettings.json +4 -0
  336. package/examples/free-plan-upgrade/db/projects.json +7 -0
  337. package/examples/free-plan-upgrade/example.json +5 -0
  338. package/examples/free-plan-upgrade/src/upgrade-tenant-to-paid.mjs +105 -0
  339. package/examples/hono-auth/README.md +74 -0
  340. package/examples/hono-auth/db/pages.schema.jsonc +44 -0
  341. package/examples/hono-auth/db/users.schema.jsonc +42 -0
  342. package/examples/hono-auth/db.config.mjs +17 -0
  343. package/examples/hono-auth/example.json +5 -0
  344. package/examples/hono-auth/package.json +14 -0
  345. package/examples/hono-auth/src/app.mjs +79 -0
  346. package/examples/hono-auth/src/server.mjs +13 -0
  347. package/examples/production-json/README.md +102 -0
  348. package/examples/production-json/db/appSettings.schema.jsonc +41 -0
  349. package/examples/production-json/db/featureFlags.schema.jsonc +84 -0
  350. package/examples/production-json/db/operations/get-control-plane.jsonc +6 -0
  351. package/examples/production-json/db/operations/get-feature-flag.jsonc +9 -0
  352. package/examples/production-json/db/operations/list-feature-flags.jsonc +8 -0
  353. package/examples/production-json/db/operations/read-public-settings.jsonc +8 -0
  354. package/examples/production-json/db.config.mjs +33 -0
  355. package/examples/production-json/example.json +5 -0
  356. package/examples/production-json/src/client-demo.mjs +28 -0
  357. package/examples/production-json/src/generated/db.types.d.ts +60 -0
  358. package/examples/relations/README.md +56 -0
  359. package/examples/relations/db/posts.schema.jsonc +46 -0
  360. package/examples/relations/db/users.schema.jsonc +34 -0
  361. package/examples/relations/db.config.mjs +13 -0
  362. package/examples/relations/example.json +5 -0
  363. package/examples/rest-client/README.md +54 -0
  364. package/examples/rest-client/db/settings.json +5 -0
  365. package/examples/rest-client/db/users.schema.jsonc +42 -0
  366. package/examples/rest-client/db.config.mjs +13 -0
  367. package/examples/rest-client/example.json +5 -0
  368. package/examples/rest-client/src/client-demo.mjs +24 -0
  369. package/examples/schema-first/README.md +55 -0
  370. package/examples/schema-first/db/auditEvents.schema.jsonc +24 -0
  371. package/examples/schema-first/db/settings.schema.jsonc +29 -0
  372. package/examples/schema-first/db/users.schema.jsonc +36 -0
  373. package/examples/schema-first/db.config.mjs +15 -0
  374. package/examples/schema-first/example.json +5 -0
  375. package/examples/schema-first/src/generated/db.types.d.ts +47 -0
  376. package/examples/schema-manifest/README.md +50 -0
  377. package/examples/schema-manifest/db/projects.schema.jsonc +48 -0
  378. package/examples/schema-manifest/db/users.schema.jsonc +35 -0
  379. package/examples/schema-manifest/db.config.mjs +41 -0
  380. package/examples/schema-manifest/example.json +5 -0
  381. package/examples/schema-manifest/src/generated/db.schema.json +130 -0
  382. package/examples/schema-manifest/src/generated/db.types.d.ts +50 -0
  383. package/examples/schema-ui/README.md +103 -0
  384. package/examples/schema-ui/db/pages.schema.jsonc +53 -0
  385. package/examples/schema-ui/db/users.schema.jsonc +30 -0
  386. package/examples/schema-ui/db.config.mjs +55 -0
  387. package/examples/schema-ui/example.json +5 -0
  388. package/examples/schema-ui/src/cms-ssr.mjs +276 -0
  389. package/examples/schema-ui/src/generated/db.schema.json +133 -0
  390. package/examples/schema-ui/src/generated/db.types.d.ts +46 -0
  391. package/examples/schema-ui/src/render-admin.mjs +175 -0
  392. package/examples/schema-ui/src/schema-ui-ssr-handler.mjs +149 -0
  393. package/examples/schema-ui/src/start-schema-ui-server.mjs +140 -0
  394. package/examples/standard-schema/README.md +55 -0
  395. package/examples/standard-schema/db/settings.schema.mjs +22 -0
  396. package/examples/standard-schema/db/users.schema.mjs +72 -0
  397. package/examples/standard-schema/example.json +5 -0
  398. package/package.json +108 -0
@@ -0,0 +1,1086 @@
1
+ import path from 'node:path';
2
+ import { dbError, listChoices } from '../../errors.js';
3
+ import { readText, writeText } from '../../fs-utils.js';
4
+ import { resolveResource } from '../../names.js';
5
+ import { loadProjectSchema } from '../../schema.js';
6
+ import { generateSchemaManifest } from '../../schema-manifest.js';
7
+ import { isHelpRequested, valueAfter } from '../args.js';
8
+ import { printDiagnostic, printSchemaHelp } from '../output.js';
9
+ import { promptForSchemaTarget } from '../schema-prompt.js';
10
+ export async function runSchema(config, args) {
11
+ if (isHelpRequested(args)) {
12
+ printSchemaHelp();
13
+ return;
14
+ }
15
+ if (args[0] === 'infer') {
16
+ await runSchemaInfer(config, args);
17
+ return;
18
+ }
19
+ const project = await loadProjectSchema(config);
20
+ if (args[0] === 'manifest') {
21
+ const result = await generateSchemaManifest(config, {
22
+ project,
23
+ outFile: valueAfter(args, '--out'),
24
+ });
25
+ if (result.outFiles.length === 0) {
26
+ console.log(result.content);
27
+ return;
28
+ }
29
+ for (const filePath of result.outFiles) {
30
+ console.log(`Generated ${path.relative(config.cwd, filePath)}`);
31
+ }
32
+ return;
33
+ }
34
+ if (args[0] === 'unbundle') {
35
+ const prompted = await promptedSchemaTarget('unbundle', project, args);
36
+ if (hasFlag(args, '--all') || prompted?.all) {
37
+ await runSchemaUnbundleAll(config, project, args);
38
+ return;
39
+ }
40
+ await runSchemaUnbundle(config, project, args, { resourceName: prompted?.resourceName });
41
+ return;
42
+ }
43
+ if (args[0] === 'bundle') {
44
+ const prompted = await promptedSchemaTarget('bundle', project, args);
45
+ if (hasFlag(args, '--all') || prompted?.all) {
46
+ await runSchemaBundleAll(config, project, args);
47
+ return;
48
+ }
49
+ await runSchemaBundle(config, project, args, { resourceName: prompted?.resourceName });
50
+ return;
51
+ }
52
+ if (args[0] === 'validate') {
53
+ for (const diagnostic of project.diagnostics) {
54
+ printDiagnostic(diagnostic);
55
+ }
56
+ const errorCount = project.diagnostics.filter((diagnostic) => diagnostic.severity === 'error').length;
57
+ if (errorCount > 0) {
58
+ process.exitCode = 1;
59
+ return;
60
+ }
61
+ console.log(project.diagnostics.length === 0 ? 'Schema valid' : 'Schema valid with warnings');
62
+ return;
63
+ }
64
+ if (args[0]) {
65
+ const resourceMap = new Map(project.resources.map((resource) => [resource.name, resource]));
66
+ const { resource, candidates } = resolveResource(resourceMap, args[0]);
67
+ if (!resource) {
68
+ throw dbError('SCHEMA_UNKNOWN_RESOURCE', `Unknown schema resource "${args[0]}".`, {
69
+ status: 404,
70
+ hint: `Use one of: ${listChoices(project.resources.map((resource) => resource.name))}.`,
71
+ details: {
72
+ resource: args[0],
73
+ requestedResource: args[0],
74
+ normalizedCandidates: candidates,
75
+ availableResources: project.resources.map((resource) => resource.name),
76
+ },
77
+ });
78
+ }
79
+ console.log(JSON.stringify(project.schema.resources[resource.name], null, 2));
80
+ return;
81
+ }
82
+ console.log(JSON.stringify(project.schema, null, 2));
83
+ }
84
+ async function runSchemaUnbundle(config, project, args, options = {}) {
85
+ const resourceName = options.resourceName ?? positionalArgs(args.slice(1))[0];
86
+ if (!resourceName) {
87
+ const example = schemaTargetExample(project);
88
+ throw dbError('SCHEMA_UNBUNDLE_REQUIRES_RESOURCE', `SCHEMA_UNBUNDLE_REQUIRES_RESOURCE: schema unbundle requires a resource name. Use async-db schema unbundle ${example}, or async-db schema unbundle --all.`, {
89
+ hint: `Use async-db schema unbundle ${example}, or async-db schema unbundle --all.`,
90
+ });
91
+ }
92
+ const resource = requireSchemaResource(project, resourceName);
93
+ const explicitSchemaOutFile = outputPath(config, valueAfter(args, '--schema-out'));
94
+ if (!explicitSchemaOutFile && isExecutableSchemaFile(resource.schemaPath)) {
95
+ throw dbError('SCHEMA_UNBUNDLE_SCHEMA_MODULE_REQUIRES_OUT', `SCHEMA_UNBUNDLE_SCHEMA_MODULE_REQUIRES_OUT: schema unbundle cannot rewrite ${path.relative(config.cwd, resource.schemaPath)} in place.`, {
96
+ hint: 'Use --schema-out to write a JSON/JSONC schema source, then replace the executable schema module when you are ready.',
97
+ });
98
+ }
99
+ const schemaOutFile = explicitSchemaOutFile ?? defaultSchemaOutFile(config, resource);
100
+ const explicitSeedOutFile = outputPath(config, valueAfter(args, '--seed-out'));
101
+ const force = hasFlag(args, '--force');
102
+ const includeEmptySeed = hasFlag(args, '--empty-seed');
103
+ const shouldWriteSeed = (explicitSeedOutFile !== undefined || !resource.dataPath)
104
+ && (includeEmptySeed || !isEmptySeed(resource.seed, resource.kind));
105
+ const seedOutFile = explicitSeedOutFile ?? defaultSeedOutFile(config, resource);
106
+ const generated = [];
107
+ if (shouldWriteSeed) {
108
+ await writeOutput(seedOutFile, `${JSON.stringify(resource.seed, null, 2)}\n`, config, { force });
109
+ generated.push(seedOutFile);
110
+ }
111
+ if (!explicitSchemaOutFile && resource.schemaPath?.endsWith('.schema.jsonc')) {
112
+ console.error(`warn: schema unbundle rewrites ${path.relative(config.cwd, schemaOutFile)} without preserving JSONC comments.`);
113
+ }
114
+ await writeText(schemaOutFile, `${JSON.stringify(schemaSourceForResource(resource), null, 2)}\n`);
115
+ generated.push(schemaOutFile);
116
+ for (const filePath of generated) {
117
+ console.log(`Generated ${path.relative(config.cwd, filePath)}`);
118
+ }
119
+ }
120
+ async function runSchemaBundle(config, project, args, options = {}) {
121
+ const resourceName = options.resourceName ?? positionalArgs(args.slice(1))[0];
122
+ if (!resourceName) {
123
+ const example = schemaTargetExample(project);
124
+ throw dbError('SCHEMA_BUNDLE_REQUIRES_RESOURCE', `SCHEMA_BUNDLE_REQUIRES_RESOURCE: schema bundle requires a resource name. Use async-db schema bundle ${example} --out artifacts/${example}.bundle.schema.json, or async-db schema bundle --all.`, {
125
+ hint: `Use async-db schema bundle ${example} --out artifacts/${example}.bundle.schema.json, or async-db schema bundle --all.`,
126
+ });
127
+ }
128
+ const resource = requireSchemaResource(project, resourceName);
129
+ const content = `${JSON.stringify(schemaSourceForResource(resource, { includeSeed: true }), null, 2)}\n`;
130
+ const outFile = outputPath(config, valueAfter(args, '--out'));
131
+ if (!outFile) {
132
+ console.log(content.trimEnd());
133
+ return;
134
+ }
135
+ const force = hasFlag(args, '--force');
136
+ if (isInsidePath(config.sourceDir, outFile) && !force) {
137
+ throw dbError('SCHEMA_BUNDLE_LIVE_OUTPUT_REQUIRES_FORCE', `SCHEMA_BUNDLE_LIVE_OUTPUT_REQUIRES_FORCE: schema bundle output ${path.relative(config.cwd, outFile)} is inside the active fixture directory.`, {
138
+ hint: 'Write bundled schema artifacts outside db/, or pass --force if you intentionally want a live bundled schema source.',
139
+ });
140
+ }
141
+ await writeOutput(outFile, content, config, { force });
142
+ console.log(`Generated ${path.relative(config.cwd, outFile)}`);
143
+ }
144
+ async function runSchemaBundleAll(config, project, args) {
145
+ const outFile = outputPath(config, valueAfter(args, '--out')) ?? await defaultRootSchemaOutFile(config, project);
146
+ const force = hasFlag(args, '--force');
147
+ const duplicate = bundleDuplicateResourceDiagnostic(config, project);
148
+ if (duplicate) {
149
+ throw dbError(duplicate.code, `${duplicate.code}: ${duplicate.message}`, {
150
+ hint: duplicate.hint,
151
+ details: duplicate.details,
152
+ });
153
+ }
154
+ if (isInsidePath(config.sourceDir, outFile) && !force) {
155
+ const relative = path.relative(config.cwd, outFile);
156
+ throw dbError('SCHEMA_BUNDLE_LIVE_OUTPUT_REQUIRES_FORCE', `SCHEMA_BUNDLE_LIVE_OUTPUT_REQUIRES_FORCE: schema bundle output ${relative} is inside the active fixture directory.`, {
157
+ hint: 'Write the root schema outside db/, or pass --force if you intentionally want a live schema source inside db/.',
158
+ details: {
159
+ command: 'schema bundle --all',
160
+ file: relative,
161
+ sourceDir: path.relative(config.cwd, config.sourceDir),
162
+ severity: 'error',
163
+ },
164
+ });
165
+ }
166
+ const result = renderRootSchemaBundle(config, project, outFile);
167
+ const isRootOutput = isRootSchemaOutput(config, outFile);
168
+ const plannedWrites = [
169
+ ...bundleAllSeedWrites(config, project, outFile, { force }),
170
+ {
171
+ filePath: outFile,
172
+ content: result.content,
173
+ options: {
174
+ force,
175
+ existsCode: isRootOutput ? 'SCHEMA_BUNDLE_ROOT_EXISTS' : 'SCHEMA_BUNDLE_OUTPUT_EXISTS',
176
+ existsHint: isRootOutput
177
+ ? 'Review the existing root schema, choose a different --out path, or pass --force to replace it.'
178
+ : 'Review the existing output, choose a different --out path, or pass --force to overwrite it.',
179
+ command: 'schema bundle --all',
180
+ },
181
+ },
182
+ ];
183
+ const preflight = [];
184
+ for (const write of plannedWrites) {
185
+ preflight.push({
186
+ ...write,
187
+ result: await preflightOutput(write.filePath, write.content, config, write.options),
188
+ });
189
+ }
190
+ for (const diagnostic of result.diagnostics) {
191
+ printDiagnostic(diagnostic);
192
+ }
193
+ for (const write of preflight) {
194
+ if (!write.result.shouldWrite) {
195
+ continue;
196
+ }
197
+ await writeText(write.filePath, write.content);
198
+ if (write.diagnostic) {
199
+ printDiagnostic(write.diagnostic);
200
+ }
201
+ if (write.kind === 'seed') {
202
+ console.log(`Generated ${path.relative(config.cwd, write.filePath)}`);
203
+ }
204
+ }
205
+ console.log(`Generated ${path.relative(config.cwd, outFile)}`);
206
+ }
207
+ async function runSchemaUnbundleAll(config, project, args) {
208
+ const schemaDir = outputPath(config, valueAfter(args, '--schema-dir')) ?? config.sourceDir;
209
+ const force = hasFlag(args, '--force');
210
+ if (!project.rootSchema?.found) {
211
+ throw dbError('SCHEMA_UNBUNDLE_ROOT_REQUIRED', 'SCHEMA_UNBUNDLE_ROOT_REQUIRED: schema unbundle --all requires db.schema.js or db.schema.mjs.', {
212
+ hint: 'Create a root schema first with async-db schema bundle --all, or unbundle a single resource by name.',
213
+ details: {
214
+ command: 'schema unbundle --all',
215
+ file: 'db.schema.js|db.schema.mjs',
216
+ severity: 'error',
217
+ },
218
+ });
219
+ }
220
+ printDiagnostic({
221
+ code: 'SCHEMA_UNBUNDLE_SEED_NOT_MOVED',
222
+ severity: 'warn',
223
+ message: 'SCHEMA_UNBUNDLE_SEED_NOT_MOVED: schema unbundle --all writes schema files only; seed/data fixtures are left untouched.',
224
+ hint: 'Use single-resource schema unbundle with --seed-out when you want to move embedded seed data.',
225
+ details: {
226
+ command: 'schema unbundle --all',
227
+ },
228
+ });
229
+ const executableOutput = await executableSchemaOutputPlan(config, schemaDir);
230
+ const hasExecutableOutput = project.resources.some((resource) => resourceHasExecutableSchema(resource));
231
+ if (hasExecutableOutput && executableOutput.packageWrite) {
232
+ const wrote = await writeOutput(executableOutput.packageWrite.filePath, executableOutput.packageWrite.content, config, executableOutput.packageWrite.options);
233
+ if (wrote) {
234
+ console.log(`Generated ${path.relative(config.cwd, executableOutput.packageWrite.filePath)}`);
235
+ }
236
+ }
237
+ const rootSchemaPath = projectRootSchemaPath(config, project);
238
+ for (const resource of project.resources) {
239
+ const executable = resourceHasExecutableSchema(resource);
240
+ const outFile = resource.source
241
+ ? path.join(schemaDir, resource.name, `index.schema.${executableOutput.extension}`)
242
+ : path.join(schemaDir, `${resource.name}.schema.${executable ? executableOutput.extension : 'jsonc'}`);
243
+ const content = executable
244
+ ? renderUnbundledSchemaModule(config, project, resource, outFile, rootSchemaPath)
245
+ : `${JSON.stringify(schemaSourceForResource(resource), null, 2)}\n`;
246
+ if (resourceHasExecutableFunctions(resource)) {
247
+ printDiagnostic(executableUnbundleDiagnostic(config, resource, outFile));
248
+ }
249
+ await writeOutput(outFile, content, config, {
250
+ force,
251
+ existsCode: 'SCHEMA_UNBUNDLE_OUTPUT_EXISTS',
252
+ existsHint: 'Review the existing per-resource schema file, choose a different --schema-dir, or pass --force to overwrite it.',
253
+ command: 'schema unbundle --all',
254
+ resource: resource.name,
255
+ });
256
+ console.log(`Generated ${path.relative(config.cwd, outFile)}`);
257
+ }
258
+ }
259
+ async function runSchemaInfer(config, args) {
260
+ const resourceName = positionalArgs(args.slice(1))[0];
261
+ const outFile = valueAfter(args, '--out');
262
+ const inferredConfig = {
263
+ ...config,
264
+ schema: {
265
+ ...config.schema,
266
+ source: 'data',
267
+ },
268
+ };
269
+ const project = await loadProjectSchema(inferredConfig);
270
+ if (outFile && !resourceName) {
271
+ throw dbError('SCHEMA_INFER_OUT_REQUIRES_RESOURCE', 'SCHEMA_INFER_OUT_REQUIRES_RESOURCE: schema infer --out requires a resource name.', {
272
+ hint: 'Use async-db schema infer users --out db/users.schema.jsonc.',
273
+ });
274
+ }
275
+ if (resourceName) {
276
+ const resource = requireSchemaResource(project, resourceName);
277
+ if (outFile) {
278
+ const outputPath = path.resolve(config.cwd, outFile);
279
+ await writeText(outputPath, `${JSON.stringify(schemaSourceForResource(resource), null, 2)}\n`);
280
+ console.log(`Generated ${path.relative(config.cwd, outputPath)}`);
281
+ return;
282
+ }
283
+ console.log(JSON.stringify(project.schema.resources[resource.name], null, 2));
284
+ return;
285
+ }
286
+ console.log(JSON.stringify(project.schema, null, 2));
287
+ }
288
+ async function promptedSchemaTarget(command, project, args) {
289
+ if (hasFlag(args, '--all') || positionalArgs(args.slice(1))[0]) {
290
+ return undefined;
291
+ }
292
+ return promptForSchemaTarget({
293
+ command,
294
+ resources: project.resources.map((resource) => resource.name),
295
+ });
296
+ }
297
+ function schemaTargetExample(project) {
298
+ return project.resources[0]?.name ?? '<resource>';
299
+ }
300
+ function renderRootSchemaBundle(config, project, outFile) {
301
+ const imports = new Map();
302
+ const diagnostics = [];
303
+ for (const resource of project.resources) {
304
+ if (!isExecutableSchemaFile(resource.schemaPath) || !resourceHasExecutableFunctions(resource)) {
305
+ continue;
306
+ }
307
+ ensureResourceImport(resource, imports);
308
+ if (resourceHasStandardValidator(resource)) {
309
+ diagnostics.push(importedValidatorDiagnostic(config, resource, outFile));
310
+ }
311
+ if (!resourceHasResolvers(resource)) {
312
+ continue;
313
+ }
314
+ for (const [fieldName, resolver] of Object.entries(resource.resolvers?.fields ?? {})) {
315
+ for (const resolverKind of ['resolve', 'resolveMany']) {
316
+ if (!resolver[resolverKind]) {
317
+ continue;
318
+ }
319
+ diagnostics.push(importedResolverDiagnostic(config, resource, fieldName, resolverKind, outFile));
320
+ if (isArrowLikeFunction(resolver[resolverKind])) {
321
+ diagnostics.push(arrowResolverDiagnostic(config, resource, fieldName, resolverKind, outFile));
322
+ }
323
+ }
324
+ }
325
+ }
326
+ const lines = [
327
+ '// Generated by async-db schema bundle --all.',
328
+ '',
329
+ `import { collection, document, field, files } from '@async/db/schema';`,
330
+ ];
331
+ for (const [sourceFile, alias] of imports) {
332
+ lines.push(`import ${alias} from '${moduleSpecifier(outFile, sourceFile)}';`);
333
+ }
334
+ lines.push('', 'export default {');
335
+ for (const resource of project.resources) {
336
+ lines.push(...renderRootSchemaResource(config, resource, imports));
337
+ }
338
+ lines.push('};', '');
339
+ return {
340
+ content: lines.join('\n'),
341
+ diagnostics,
342
+ };
343
+ }
344
+ function renderRootSchemaResource(config, resource, imports) {
345
+ const helper = resource.kind === 'document' ? 'document' : 'collection';
346
+ const validator = resourceHasStandardValidator(resource)
347
+ ? validatorAccess(resource, imports)
348
+ : undefined;
349
+ const standardSchemaFirst = shouldEmitStandardSchemaFirst(config, resource) && validator;
350
+ const lines = [
351
+ standardSchemaFirst
352
+ ? ` ${propertyName(resource.name)}: ${helper}(${validator}, {`
353
+ : ` ${propertyName(resource.name)}: ${helper}({`,
354
+ ];
355
+ if (resource.description) {
356
+ lines.push(` description: ${JSON.stringify(resource.description)},`);
357
+ }
358
+ if (resource.kind === 'collection') {
359
+ lines.push(` idField: ${JSON.stringify(resource.idField)},`);
360
+ }
361
+ if (resource.source) {
362
+ lines.push(` source: ${renderSourceExpression(rootSchemaSourceGlob(config, resource))},`);
363
+ }
364
+ if (validator && !standardSchemaFirst) {
365
+ lines.push(` validator: ${validator},`);
366
+ }
367
+ lines.push(' fields: {');
368
+ for (const [fieldName, field] of Object.entries(resource.fields ?? {})) {
369
+ lines.push(` ${propertyName(fieldName)}: ${renderFieldExpression(field, resource, fieldName, imports)},`);
370
+ }
371
+ lines.push(' },');
372
+ lines.push(' }),', '');
373
+ return lines;
374
+ }
375
+ function rootSchemaSourceGlob(config, resource) {
376
+ if (!isFolderMarkerResource(config, resource)) {
377
+ return resource.source;
378
+ }
379
+ const source = filesSource(resource.source);
380
+ if (source?.kind === 'files') {
381
+ return {
382
+ ...source,
383
+ patterns: (source.patterns ?? []).map((source) => rebaseFolderSourceGlob(config, resource, source)),
384
+ };
385
+ }
386
+ if (Array.isArray(resource.source)) {
387
+ return resource.source.map((source) => rebaseFolderSourceGlob(config, resource, source));
388
+ }
389
+ return rebaseFolderSourceGlob(config, resource, resource.source);
390
+ }
391
+ function isFolderMarkerResource(config, resource) {
392
+ if (!resource.schemaPath) {
393
+ return false;
394
+ }
395
+ const relative = path.relative(config.cwd, resource.schemaPath).split(path.sep).join('/');
396
+ return relative.endsWith('/index.schema.mjs') || relative.endsWith('/index.schema.js');
397
+ }
398
+ function rebaseFolderSourceGlob(config, resource, source) {
399
+ if (typeof source !== 'string' || path.isAbsolute(source)) {
400
+ return source;
401
+ }
402
+ const normalizedSource = source.split('\\').join('/');
403
+ const schemaDir = path.dirname(resource.schemaPath);
404
+ const relativeSchemaDir = path.relative(config.cwd, schemaDir).split(path.sep).join('/');
405
+ const sourcePath = normalizedSource.replace(/^\.\//u, '');
406
+ const rebased = path.posix.normalize(path.posix.join(relativeSchemaDir, sourcePath));
407
+ return rebased.startsWith('.') ? rebased : `./${rebased}`;
408
+ }
409
+ function renderSourceExpression(source) {
410
+ const sourceObject = filesSource(source);
411
+ const normalized = sourceObject?.kind === 'files'
412
+ ? sourceObject
413
+ : {
414
+ kind: 'files',
415
+ patterns: Array.isArray(source) ? source : [source],
416
+ read: 'frontmatter',
417
+ };
418
+ const patterns = normalized.patterns ?? [];
419
+ const patternExpression = patterns.length === 1 ? JSON.stringify(patterns[0]) : literal(patterns);
420
+ return `files(${patternExpression}, ${objectLiteral({ read: normalized.read ?? 'frontmatter' })})`;
421
+ }
422
+ function filesSource(source) {
423
+ return source && typeof source === 'object' && !Array.isArray(source)
424
+ ? source
425
+ : null;
426
+ }
427
+ function renderFieldExpression(field, resource, fieldName, imports, fieldPath = fieldName, options = {}) {
428
+ const computed = field.computed === true;
429
+ const base = renderBaseFieldExpression(field, resource, fieldPath, imports);
430
+ if (!computed) {
431
+ return base;
432
+ }
433
+ const resolver = resource.resolvers?.fields?.[fieldName];
434
+ if (!resolver) {
435
+ return `field.computed(${base})`;
436
+ }
437
+ const fieldAccess = resolverFieldAccess(resource, fieldName, imports, options);
438
+ if (!fieldAccess) {
439
+ return `field.computed(${base})`;
440
+ }
441
+ if (resolver.resolve && resolver.resolveMany) {
442
+ return [
443
+ `field.computed(${base}, {`,
444
+ ` resolve: function ${resolverFunctionName(resource.name, fieldName, 'resolve')}(context) {`,
445
+ ` return ${fieldAccess}.resolve.call(this, context);`,
446
+ ' },',
447
+ ` resolveMany: function ${resolverFunctionName(resource.name, fieldName, 'resolveMany')}(context) {`,
448
+ ` return ${fieldAccess}.resolveMany.call(this, context);`,
449
+ ' },',
450
+ ' })',
451
+ ].join('\n');
452
+ }
453
+ if (resolver.resolveMany) {
454
+ return [
455
+ `field.computed(${base}, {`,
456
+ ` resolveMany: function ${resolverFunctionName(resource.name, fieldName, 'resolveMany')}(context) {`,
457
+ ` return ${fieldAccess}.resolveMany.call(this, context);`,
458
+ ' },',
459
+ ' })',
460
+ ].join('\n');
461
+ }
462
+ return [
463
+ `field.computed(${base}, function ${resolverFunctionName(resource.name, fieldName, 'resolve')}(context) {`,
464
+ ` return ${fieldAccess}.resolve.call(this, context);`,
465
+ ' })',
466
+ ].join('\n');
467
+ }
468
+ function renderBaseFieldExpression(field, resource, fieldPath, imports) {
469
+ const options = fieldOptions(field);
470
+ switch (field.type) {
471
+ case 'string':
472
+ return renderFieldCall('field.string', options);
473
+ case 'datetime':
474
+ return renderFieldCall('field.datetime', options);
475
+ case 'number':
476
+ return renderFieldCall('field.number', options);
477
+ case 'boolean':
478
+ return renderFieldCall('field.boolean', options);
479
+ case 'enum':
480
+ return renderFieldCall('field.enum', options, [literal(field.values ?? [])]);
481
+ case 'array':
482
+ return renderFieldCall('field.array', options, [
483
+ renderBaseFieldExpression(field.items ?? { type: 'unknown' }, resource, `${fieldPath}Item`, imports),
484
+ ]);
485
+ case 'object':
486
+ return renderObjectFieldExpression(field, resource, fieldPath, imports, options);
487
+ case 'unknown':
488
+ default:
489
+ return renderFieldCall('field.json', options);
490
+ }
491
+ }
492
+ function renderObjectFieldExpression(field, resource, fieldPath, imports, options) {
493
+ const fields = field.fields ?? {};
494
+ const fieldEntries = Object.entries(fields);
495
+ if (fieldEntries.length === 0) {
496
+ return renderFieldCall('field.object', options);
497
+ }
498
+ const lines = ['field.object({'];
499
+ for (const [childName, childField] of fieldEntries) {
500
+ lines.push(` ${propertyName(childName)}: ${renderBaseFieldExpression(childField, resource, `${fieldPath}${childName}`, imports)},`);
501
+ }
502
+ const optionText = renderOptions(options);
503
+ lines.push(` }${optionText ? `, ${optionText}` : ''})`);
504
+ return lines.join('\n');
505
+ }
506
+ function fieldOptions(field) {
507
+ const options = {};
508
+ if (field.required === true) {
509
+ options.required = true;
510
+ }
511
+ if (field.nullable === true) {
512
+ options.nullable = true;
513
+ }
514
+ if (field.description !== undefined) {
515
+ options.description = field.description;
516
+ }
517
+ if (field.default !== undefined) {
518
+ options.default = field.default;
519
+ }
520
+ if (field.unique === true) {
521
+ options.unique = true;
522
+ }
523
+ for (const key of ['min', 'max', 'minLength', 'maxLength', 'pattern']) {
524
+ if (field[key] !== undefined) {
525
+ options[key] = field[key];
526
+ }
527
+ }
528
+ if (field.additionalProperties !== undefined) {
529
+ options.additionalProperties = field.additionalProperties;
530
+ }
531
+ if (field.relation !== undefined) {
532
+ options.relation = field.relation;
533
+ }
534
+ return options;
535
+ }
536
+ function renderFieldCall(callee, options, args = []) {
537
+ const renderedArgs = [...args];
538
+ const optionText = renderOptions(options);
539
+ if (optionText) {
540
+ renderedArgs.push(optionText);
541
+ }
542
+ return `${callee}(${renderedArgs.join(', ')})`;
543
+ }
544
+ function renderOptions(options) {
545
+ return Object.keys(options).length === 0 ? '' : objectLiteral(options);
546
+ }
547
+ function renderUnbundledSchemaModule(config, project, resource, outFile, rootSchemaPath = projectRootSchemaPath(config, project)) {
548
+ const imports = new Map();
549
+ if (resourceHasExecutableFunctions(resource)) {
550
+ imports.set(rootSchemaPath, 'rootSchema');
551
+ }
552
+ return renderSchemaModule(resource, {
553
+ config,
554
+ imports,
555
+ outFile,
556
+ rootSchemaAlias: imports.get(rootSchemaPath),
557
+ });
558
+ }
559
+ function renderSchemaModule(resource, options = {}) {
560
+ const helper = resource.kind === 'document' ? 'document' : 'collection';
561
+ const lines = [
562
+ `import { collection, document, field, files } from '@async/db/schema';`,
563
+ ];
564
+ for (const [sourceFile, alias] of options.imports ?? []) {
565
+ lines.push(`import ${alias} from '${moduleSpecifier(options.outFile, sourceFile)}';`);
566
+ }
567
+ const validator = resourceHasStandardValidator(resource)
568
+ ? validatorAccess(resource, options.imports ?? new Map(), options)
569
+ : undefined;
570
+ const standardSchemaFirst = shouldEmitStandardSchemaFirst(options.config, resource) && validator;
571
+ lines.push('', standardSchemaFirst
572
+ ? `export default ${helper}(${validator}, {`
573
+ : `export default ${helper}({`);
574
+ if (resource.description) {
575
+ lines.push(` description: ${JSON.stringify(resource.description)},`);
576
+ }
577
+ if (resource.source) {
578
+ lines.push(` source: ${renderSourceExpression(resource.source)},`);
579
+ }
580
+ if (resource.kind === 'collection') {
581
+ lines.push(` idField: ${JSON.stringify(resource.idField)},`);
582
+ }
583
+ if (validator && !standardSchemaFirst) {
584
+ lines.push(` validator: ${validator},`);
585
+ }
586
+ lines.push(' fields: {');
587
+ for (const [fieldName, field] of Object.entries(resource.fields ?? {})) {
588
+ lines.push(` ${propertyName(fieldName)}: ${renderFieldExpression(field, resource, fieldName, options.imports ?? new Map(), fieldName, {
589
+ rootSchemaAlias: options.rootSchemaAlias,
590
+ })},`);
591
+ }
592
+ lines.push(' },');
593
+ lines.push('});', '');
594
+ return lines.join('\n');
595
+ }
596
+ function bundleAllSeedWrites(config, project, rootOutFile, options = {}) {
597
+ return project.resources
598
+ .filter((resource) => (resource.schemaHasSeed
599
+ && !resource.dataPath
600
+ && !isEmptySeed(resource.schemaSeed, resource.kind)))
601
+ .map((resource) => {
602
+ const filePath = defaultSeedOutFile(config, resource);
603
+ return {
604
+ kind: 'seed',
605
+ filePath,
606
+ content: `${JSON.stringify(resource.schemaSeed, null, 2)}\n`,
607
+ diagnostic: bundleSeedUnbundledDiagnostic(config, resource, filePath, rootOutFile),
608
+ options: {
609
+ force: options.force,
610
+ existsCode: 'SCHEMA_BUNDLE_SEED_OUTPUT_EXISTS',
611
+ existsHint: 'Review the existing seed fixture, remove embedded schema seed, choose a different fixture source, or pass --force to overwrite it.',
612
+ command: 'schema bundle --all',
613
+ resource: resource.name,
614
+ },
615
+ };
616
+ });
617
+ }
618
+ function importedResolverDiagnostic(config, resource, fieldName, resolverKind, rootOutFile) {
619
+ const relative = path.relative(config.cwd, resource.schemaPath);
620
+ const wrapper = resolverFunctionName(resource.name, fieldName, resolverKind);
621
+ const rootFile = path.relative(config.cwd, rootOutFile).split(path.sep).join('/');
622
+ return {
623
+ code: 'SCHEMA_BUNDLE_IMPORTED_RESOLVER',
624
+ severity: 'warn',
625
+ resource: resource.name,
626
+ file: relative,
627
+ message: `SCHEMA_BUNDLE_IMPORTED_RESOLVER: ${resource.name}.${fieldName} uses a ${resolverKind} resolver from ${relative}. The root schema will import the original module and generate an inline named wrapper to preserve behavior.`,
628
+ hint: `This is safe and non-destructive. To make ${rootFile} fully standalone, move the resolver body into ${wrapper} manually.`,
629
+ details: {
630
+ command: 'schema bundle --all',
631
+ resource: resource.name,
632
+ field: fieldName,
633
+ resolver: resolverKind,
634
+ wrapper,
635
+ strategy: 'inline-wrapper-import-original-module',
636
+ },
637
+ };
638
+ }
639
+ function importedValidatorDiagnostic(config, resource, rootOutFile) {
640
+ const relative = path.relative(config.cwd, resource.schemaPath);
641
+ const rootFile = path.relative(config.cwd, rootOutFile).split(path.sep).join('/');
642
+ return {
643
+ code: 'SCHEMA_BUNDLE_IMPORTED_VALIDATOR',
644
+ severity: 'warn',
645
+ resource: resource.name,
646
+ file: relative,
647
+ message: `SCHEMA_BUNDLE_IMPORTED_VALIDATOR: ${resource.name} uses a Standard Schema validator from ${relative}. The root schema will import the original module and reference its validator to preserve behavior.`,
648
+ hint: `This is safe and non-destructive. Keep the original schema module available, or move the validator definition into ${rootFile} manually.`,
649
+ details: {
650
+ command: 'schema bundle --all',
651
+ resource: resource.name,
652
+ strategy: 'import-original-module-validator-reference',
653
+ },
654
+ };
655
+ }
656
+ function bundleSeedUnbundledDiagnostic(config, resource, outFile, rootOutFile) {
657
+ const relative = path.relative(config.cwd, outFile);
658
+ const rootFile = path.relative(config.cwd, rootOutFile).split(path.sep).join('/');
659
+ return {
660
+ code: 'SCHEMA_BUNDLE_SEED_UNBUNDLED',
661
+ severity: 'warn',
662
+ resource: resource.name,
663
+ file: relative,
664
+ message: `SCHEMA_BUNDLE_SEED_UNBUNDLED: ${resource.name} has embedded schema seed. schema bundle --all wrote ${relative} so ${rootFile} can stay schema-only.`,
665
+ hint: `Keep seed data in ${relative}. The generated root schema intentionally omits seed.`,
666
+ details: {
667
+ command: 'schema bundle --all',
668
+ resource: resource.name,
669
+ file: relative,
670
+ strategy: 'split-schema-seed-before-root-bundle',
671
+ },
672
+ };
673
+ }
674
+ function arrowResolverDiagnostic(config, resource, fieldName, resolverKind, rootOutFile) {
675
+ const relative = path.relative(config.cwd, resource.schemaPath);
676
+ const wrapper = resolverFunctionName(resource.name, fieldName, resolverKind);
677
+ const rootFile = path.relative(config.cwd, rootOutFile).split(path.sep).join('/');
678
+ return {
679
+ code: 'SCHEMA_BUNDLE_ARROW_RESOLVER_WRAPPED',
680
+ severity: 'warn',
681
+ resource: resource.name,
682
+ file: relative,
683
+ message: `SCHEMA_BUNDLE_ARROW_RESOLVER_WRAPPED: ${resource.name}.${fieldName} ${resolverKind} is an arrow-like resolver. The generated wrapper preserves behavior, but the original resolver still cannot use runtime this.`,
684
+ hint: `To use services through this, move the resolver body into ${wrapper} in ${rootFile}.`,
685
+ details: {
686
+ command: 'schema bundle --all',
687
+ resource: resource.name,
688
+ field: fieldName,
689
+ resolver: resolverKind,
690
+ wrapper,
691
+ },
692
+ };
693
+ }
694
+ function executableUnbundleDiagnostic(config, resource, outFile) {
695
+ const relative = path.relative(config.cwd, outFile);
696
+ const reasons = executableSchemaFunctionReasons(resource);
697
+ const label = reasons.includes('computed-resolver') && reasons.includes('standard-validator')
698
+ ? 'computed resolvers and Standard Schema validators'
699
+ : reasons.includes('standard-validator')
700
+ ? 'Standard Schema validators'
701
+ : 'executable resolver functions';
702
+ return {
703
+ code: 'SCHEMA_UNBUNDLE_EXECUTABLE_REQUIRES_MODULE',
704
+ severity: 'warn',
705
+ resource: resource.name,
706
+ file: relative,
707
+ message: `SCHEMA_UNBUNDLE_EXECUTABLE_REQUIRES_MODULE: ${resource.name} contains ${label}, so schema unbundle --all will write ${relative} instead of JSONC.`,
708
+ hint: 'Keep the executable schema module output so behavior is preserved through imports and inline wrappers.',
709
+ details: {
710
+ command: 'schema unbundle --all',
711
+ resource: resource.name,
712
+ file: relative,
713
+ outputFormat: path.extname(outFile).slice(1),
714
+ reason: reasons.length === 1 ? reasons[0] : reasons,
715
+ },
716
+ };
717
+ }
718
+ function bundleDuplicateResourceDiagnostic(config, project) {
719
+ const duplicate = project.diagnostics.find((diagnostic) => diagnostic.code === 'DUPLICATE_RESOURCE_NAME');
720
+ if (!duplicate) {
721
+ return undefined;
722
+ }
723
+ const files = duplicate.details?.files ?? (duplicate.file ? [duplicate.file] : []);
724
+ return {
725
+ code: 'SCHEMA_BUNDLE_DUPLICATE_RESOURCE',
726
+ severity: 'error',
727
+ resource: duplicate.resource,
728
+ files,
729
+ message: `Multiple schema or data sources resolve to resource "${duplicate.resource}".`,
730
+ hint: duplicate.hint ?? 'Rename one source or configure resource naming before bundling all schemas.',
731
+ details: {
732
+ command: 'schema bundle --all',
733
+ resource: duplicate.resource,
734
+ files,
735
+ severity: 'error',
736
+ originalCode: duplicate.code,
737
+ cwd: config.cwd,
738
+ },
739
+ };
740
+ }
741
+ function resourceHasResolvers(resource) {
742
+ return Object.keys(resource.resolvers?.fields ?? {}).length > 0;
743
+ }
744
+ function resourceHasStandardValidator(resource) {
745
+ return Boolean(resource.validators?.standard);
746
+ }
747
+ function shouldEmitStandardSchemaFirst(config, resource) {
748
+ return Boolean(config?.schema?.standardSchema && resourceHasStandardValidator(resource));
749
+ }
750
+ function resourceHasExecutableFunctions(resource) {
751
+ return resourceHasResolvers(resource) || resourceHasStandardValidator(resource);
752
+ }
753
+ function resourceHasExecutableSchema(resource) {
754
+ return Boolean(resource.source) || resourceHasExecutableFunctions(resource);
755
+ }
756
+ function executableSchemaFunctionReasons(resource) {
757
+ const reasons = [];
758
+ if (resourceHasResolvers(resource)) {
759
+ reasons.push('computed-resolver');
760
+ }
761
+ if (resourceHasStandardValidator(resource)) {
762
+ reasons.push('standard-validator');
763
+ }
764
+ return reasons;
765
+ }
766
+ function ensureResourceImport(resource, imports) {
767
+ const alias = imports.get(resource.schemaPath) ?? importAliasForResource(resource.name, imports);
768
+ imports.set(resource.schemaPath, alias);
769
+ return alias;
770
+ }
771
+ function resolverFieldAccess(resource, fieldName, imports, options = {}) {
772
+ if (options.rootSchemaAlias) {
773
+ return memberExpression(memberExpression(memberExpression(options.rootSchemaAlias, resource.name), 'fields'), fieldName);
774
+ }
775
+ const alias = imports.get(resource.schemaPath);
776
+ if (!alias) {
777
+ return undefined;
778
+ }
779
+ return memberExpression(memberExpression(alias, 'fields'), fieldName);
780
+ }
781
+ function validatorAccess(resource, imports, options = {}) {
782
+ const base = options.rootSchemaAlias
783
+ ? memberExpression(options.rootSchemaAlias, resource.name)
784
+ : imports.get(resource.schemaPath);
785
+ if (!base) {
786
+ return undefined;
787
+ }
788
+ return memberExpression(base, resource.validatorSource ?? 'validator');
789
+ }
790
+ function resolverFunctionName(resourceName, fieldName, resolverKind) {
791
+ const suffix = resolverKind === 'resolveMany' ? 'resolveMany' : 'resolver';
792
+ let name = `${resourceName}_${fieldName}_${suffix}`.replace(/[^A-Za-z0-9_$]/g, '_');
793
+ if (!/^[A-Za-z_$]/.test(name)) {
794
+ name = `resource_${name}`;
795
+ }
796
+ return name;
797
+ }
798
+ function importAliasForResource(resourceName, imports) {
799
+ let alias = `${resourceName}Source`.replace(/[^A-Za-z0-9_$]/g, '_');
800
+ if (!/^[A-Za-z_$]/.test(alias)) {
801
+ alias = `resource_${alias}`;
802
+ }
803
+ const used = new Set(imports.values());
804
+ let next = alias;
805
+ let suffix = 2;
806
+ while (used.has(next)) {
807
+ next = `${alias}${suffix}`;
808
+ suffix += 1;
809
+ }
810
+ return next;
811
+ }
812
+ function moduleSpecifier(fromFile, sourceFile) {
813
+ let relative = path.relative(path.dirname(fromFile), sourceFile).split(path.sep).join('/');
814
+ if (!relative.startsWith('.')) {
815
+ relative = `./${relative}`;
816
+ }
817
+ return relative;
818
+ }
819
+ async function defaultRootSchemaOutFile(config, project) {
820
+ if (typeof project.rootSchema?.file === 'string' && project.rootSchema.file) {
821
+ return project.rootSchema.file;
822
+ }
823
+ return await rootPackageIsModule(config)
824
+ ? path.join(config.cwd, 'db.schema.js')
825
+ : path.join(config.cwd, 'db.schema.mjs');
826
+ }
827
+ function projectRootSchemaPath(config, project) {
828
+ return typeof project.rootSchema?.file === 'string' && project.rootSchema.file
829
+ ? project.rootSchema.file
830
+ : path.join(config.cwd, 'db.schema.mjs');
831
+ }
832
+ function isRootSchemaOutput(config, filePath) {
833
+ const resolved = path.resolve(filePath);
834
+ return path.dirname(resolved) === path.resolve(config.cwd)
835
+ && (path.basename(resolved) === 'db.schema.mjs' || path.basename(resolved) === 'db.schema.js');
836
+ }
837
+ function isExecutableSchemaFile(filePath) {
838
+ return Boolean(filePath?.endsWith('.schema.mjs') || filePath?.endsWith('.schema.js'));
839
+ }
840
+ function propertyName(name) {
841
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
842
+ }
843
+ function memberExpression(base, key) {
844
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)
845
+ ? `${base}.${key}`
846
+ : `${base}[${JSON.stringify(key)}]`;
847
+ }
848
+ function literal(value, indent = ' ') {
849
+ return JSON.stringify(value, null, 2)
850
+ .split('\n')
851
+ .join(`\n${indent}`);
852
+ }
853
+ function objectLiteral(value) {
854
+ const entries = Object.entries(value);
855
+ const inline = `{ ${entries.map(([key, entry]) => `${propertyName(key)}: ${JSON.stringify(entry)}`).join(', ')} }`;
856
+ if (inline.length <= 100 && !inline.includes('\n')) {
857
+ return inline;
858
+ }
859
+ return `{\n${entries.map(([key, entry]) => ` ${propertyName(key)}: ${literal(entry, ' ')}`).join(',\n')}\n }`;
860
+ }
861
+ function isArrowLikeFunction(value) {
862
+ return typeof value === 'function' && value.prototype === undefined;
863
+ }
864
+ function requireSchemaResource(project, name) {
865
+ const resourceMap = new Map(project.resources.map((resource) => [resource.name, resource]));
866
+ const { resource, candidates } = resolveResource(resourceMap, name);
867
+ if (!resource) {
868
+ throw dbError('SCHEMA_UNKNOWN_RESOURCE', `Unknown schema resource "${name}".`, {
869
+ status: 404,
870
+ hint: `Use one of: ${listChoices(project.resources.map((resource) => resource.name))}.`,
871
+ details: {
872
+ resource: name,
873
+ requestedResource: name,
874
+ normalizedCandidates: candidates,
875
+ availableResources: project.resources.map((resource) => resource.name),
876
+ },
877
+ });
878
+ }
879
+ return resource;
880
+ }
881
+ function schemaSourceForResource(resource, options = {}) {
882
+ const source = {
883
+ kind: resource.kind,
884
+ fields: resource.fields,
885
+ };
886
+ if (resource.kind === 'collection') {
887
+ source.idField = resource.idField;
888
+ }
889
+ if (resource.source) {
890
+ source.source = resource.source;
891
+ }
892
+ if (resource.store) {
893
+ source.store = resource.store;
894
+ }
895
+ if (resource.parser) {
896
+ source.parser = resource.parser;
897
+ }
898
+ if (options.includeSeed) {
899
+ source.seed = resource.seed;
900
+ }
901
+ return source;
902
+ }
903
+ function outputPath(config, maybePath) {
904
+ return maybePath ? path.resolve(config.cwd, maybePath) : undefined;
905
+ }
906
+ function defaultSchemaOutFile(config, resource) {
907
+ if (resource.schemaPath && !isExecutableSchemaFile(resource.schemaPath)) {
908
+ return resource.schemaPath;
909
+ }
910
+ return path.join(config.sourceDir, `${resource.name}.schema.jsonc`);
911
+ }
912
+ function defaultSeedOutFile(config, resource) {
913
+ return resource.dataPath ?? path.join(config.sourceDir, `${resource.name}.json`);
914
+ }
915
+ async function executableSchemaOutputPlan(config, schemaDir) {
916
+ const nearestPackage = await nearestPackageInfo(schemaDir);
917
+ if (nearestPackage?.type === 'module') {
918
+ return { extension: 'js' };
919
+ }
920
+ if (await shouldCreateFixtureModulePackageJson(config, schemaDir, nearestPackage)) {
921
+ return {
922
+ extension: 'js',
923
+ packageWrite: {
924
+ kind: 'module-package',
925
+ filePath: path.join(config.sourceDir, 'package.json'),
926
+ content: `${JSON.stringify({ type: 'module' }, null, 2)}\n`,
927
+ options: {
928
+ existsCode: 'SCHEMA_UNBUNDLE_MODULE_PACKAGE_EXISTS',
929
+ existsHint: 'Review the existing fixture package marker, choose a different --schema-dir, or disable schema.autoModulePackageJson.',
930
+ command: 'schema unbundle --all',
931
+ },
932
+ },
933
+ };
934
+ }
935
+ return { extension: 'mjs' };
936
+ }
937
+ async function rootPackageIsModule(config) {
938
+ return (await packageInfo(path.join(config.cwd, 'package.json')))?.type === 'module';
939
+ }
940
+ async function shouldCreateFixtureModulePackageJson(config, schemaDir, nearestPackage) {
941
+ if (config.schema?.autoModulePackageJson === false || !config.cwd || !config.sourceDir) {
942
+ return false;
943
+ }
944
+ if (!isInsidePath(config.sourceDir, schemaDir)) {
945
+ return false;
946
+ }
947
+ const fixturePackageFile = path.join(config.sourceDir, 'package.json');
948
+ if (nearestPackage && (path.resolve(nearestPackage.file) === path.resolve(fixturePackageFile)
949
+ || isInsidePath(config.sourceDir, nearestPackage.file))) {
950
+ return false;
951
+ }
952
+ return !await fileExists(fixturePackageFile);
953
+ }
954
+ async function nearestPackageInfo(directory) {
955
+ let current = path.resolve(directory);
956
+ while (true) {
957
+ const packageFile = path.join(current, 'package.json');
958
+ const info = await packageInfo(packageFile);
959
+ if (info) {
960
+ return info;
961
+ }
962
+ const parent = path.dirname(current);
963
+ if (parent === current) {
964
+ return null;
965
+ }
966
+ current = parent;
967
+ }
968
+ }
969
+ async function packageInfo(packageFile) {
970
+ try {
971
+ const json = JSON.parse(await readText(packageFile));
972
+ return {
973
+ file: packageFile,
974
+ type: typeof json?.type === 'string' ? json.type : null,
975
+ };
976
+ }
977
+ catch (error) {
978
+ if (error.code === 'ENOENT') {
979
+ return null;
980
+ }
981
+ return {
982
+ file: packageFile,
983
+ type: null,
984
+ };
985
+ }
986
+ }
987
+ async function fileExists(filePath) {
988
+ try {
989
+ await readText(filePath);
990
+ return true;
991
+ }
992
+ catch (error) {
993
+ if (error.code === 'ENOENT') {
994
+ return false;
995
+ }
996
+ throw error;
997
+ }
998
+ }
999
+ async function writeOutput(filePath, content, config, options = {}) {
1000
+ const result = await preflightOutput(filePath, content, config, options);
1001
+ if (!result.shouldWrite) {
1002
+ return false;
1003
+ }
1004
+ await writeText(filePath, content);
1005
+ return true;
1006
+ }
1007
+ async function preflightOutput(filePath, content, config, options = {}) {
1008
+ if (options.force) {
1009
+ return { shouldWrite: true };
1010
+ }
1011
+ if (!options.force) {
1012
+ try {
1013
+ const existing = await readText(filePath);
1014
+ if (contentMatches(existing, content)) {
1015
+ return { shouldWrite: false };
1016
+ }
1017
+ const relative = path.relative(config.cwd, filePath);
1018
+ const code = options.existsCode ?? 'SCHEMA_OUTPUT_EXISTS';
1019
+ throw dbError(code, `${code}: ${relative} already exists with different content.`, {
1020
+ hint: options.existsHint ?? 'Review the existing file, choose a different output path, or pass --force to overwrite it.',
1021
+ details: {
1022
+ command: options.command,
1023
+ resource: options.resource,
1024
+ file: relative,
1025
+ severity: 'error',
1026
+ },
1027
+ });
1028
+ }
1029
+ catch (error) {
1030
+ if (error.code !== 'ENOENT') {
1031
+ throw error;
1032
+ }
1033
+ }
1034
+ }
1035
+ return { shouldWrite: true };
1036
+ }
1037
+ function contentMatches(existing, next) {
1038
+ if (existing === next) {
1039
+ return true;
1040
+ }
1041
+ try {
1042
+ return stableJsonStringify(JSON.parse(existing)) === stableJsonStringify(JSON.parse(next));
1043
+ }
1044
+ catch {
1045
+ return false;
1046
+ }
1047
+ }
1048
+ function stableJsonStringify(value) {
1049
+ if (Array.isArray(value)) {
1050
+ return `[${value.map((item) => stableJsonStringify(item)).join(',')}]`;
1051
+ }
1052
+ if (value && typeof value === 'object') {
1053
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJsonStringify(value[key])}`).join(',')}}`;
1054
+ }
1055
+ return JSON.stringify(value);
1056
+ }
1057
+ function isEmptySeed(seed, kind) {
1058
+ if (kind === 'collection') {
1059
+ return Array.isArray(seed) && seed.length === 0;
1060
+ }
1061
+ return seed && typeof seed === 'object' && !Array.isArray(seed) && Object.keys(seed).length === 0;
1062
+ }
1063
+ function isInsidePath(parent, child) {
1064
+ const relative = path.relative(parent, child);
1065
+ return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
1066
+ }
1067
+ function hasFlag(args, flag) {
1068
+ return args.includes(flag);
1069
+ }
1070
+ function positionalArgs(args) {
1071
+ const output = [];
1072
+ for (let index = 0; index < args.length; index += 1) {
1073
+ const arg = args[index];
1074
+ if (arg === '--out' || arg === '--schema-out' || arg === '--seed-out' || arg === '--schema-dir' || arg === '--cwd' || arg === '--config') {
1075
+ index += 1;
1076
+ continue;
1077
+ }
1078
+ if (arg === '--all') {
1079
+ continue;
1080
+ }
1081
+ if (!String(arg).startsWith('-')) {
1082
+ output.push(arg);
1083
+ }
1084
+ }
1085
+ return output;
1086
+ }