@warlock.js/core 5.34.3 → 5.36.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 (281) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/esm/cli/cli-commands.manager.mjs +1 -1
  3. package/esm/cli/cli-commands.manager.mjs.map +1 -1
  4. package/esm/cli/commands/add.command.mjs +1 -0
  5. package/esm/cli/commands/add.command.mjs.map +1 -1
  6. package/esm/cli/commands/build.command.mjs +30 -3
  7. package/esm/cli/commands/build.command.mjs.map +1 -1
  8. package/esm/cli/commands/check/check-command.action.mjs +1 -0
  9. package/esm/cli/commands/check/check-command.action.mjs.map +1 -1
  10. package/esm/cli/commands/check.command.mjs +5 -0
  11. package/esm/cli/commands/check.command.mjs.map +1 -1
  12. package/esm/cli/commands/explain/explain-command.action.mjs +21 -0
  13. package/esm/cli/commands/explain/explain-command.action.mjs.map +1 -1
  14. package/esm/cli/commands/explain.command.mjs +14 -4
  15. package/esm/cli/commands/explain.command.mjs.map +1 -1
  16. package/esm/cli/commands/generate/generate.command.mjs +19 -1
  17. package/esm/cli/commands/generate/generate.command.mjs.map +1 -1
  18. package/esm/cli/commands/generate/generators/endpoint.generator.mjs +1 -1
  19. package/esm/cli/commands/generate/generators/endpoint.generator.mjs.map +1 -1
  20. package/esm/cli/commands/generate/generators/web.generator.mjs +169 -0
  21. package/esm/cli/commands/generate/generators/web.generator.mjs.map +1 -0
  22. package/esm/cli/commands/generate/templates/web-stubs.mjs +231 -0
  23. package/esm/cli/commands/generate/templates/web-stubs.mjs.map +1 -0
  24. package/esm/cli/commands/inspect/inspect-command.action.mjs +4 -3
  25. package/esm/cli/commands/inspect/inspect-command.action.mjs.map +1 -1
  26. package/esm/cli/commands/inspect.command.mjs +13 -8
  27. package/esm/cli/commands/inspect.command.mjs.map +1 -1
  28. package/esm/cli/commands/mcp/mcp-command.action.mjs +1 -1
  29. package/esm/cli/commands/mcp/mcp-command.action.mjs.map +1 -1
  30. package/esm/config/config-loader.d.mts.map +1 -1
  31. package/esm/config/config-loader.mjs +2 -0
  32. package/esm/config/config-loader.mjs.map +1 -1
  33. package/esm/config/load-config-files.mjs +4 -0
  34. package/esm/config/load-config-files.mjs.map +1 -1
  35. package/esm/dev-server/file-event-handler.mjs +11 -1
  36. package/esm/dev-server/file-event-handler.mjs.map +1 -1
  37. package/esm/dev-server/file-manager.d.mts +1 -1
  38. package/esm/dev-server/file-manager.d.mts.map +1 -1
  39. package/esm/dev-server/file-manager.mjs.map +1 -1
  40. package/esm/dev-server/files-orchestrator.mjs +16 -1
  41. package/esm/dev-server/files-orchestrator.mjs.map +1 -1
  42. package/esm/dev-server/files-watcher.mjs +13 -4
  43. package/esm/dev-server/files-watcher.mjs.map +1 -1
  44. package/esm/dev-server/loader/loader-port-acks.mjs +21 -9
  45. package/esm/dev-server/loader/loader-port-acks.mjs.map +1 -1
  46. package/esm/dev-server/loader/register-loader.mjs +31 -12
  47. package/esm/dev-server/loader/register-loader.mjs.map +1 -1
  48. package/esm/dev-server/module-loader.mjs +15 -1
  49. package/esm/dev-server/module-loader.mjs.map +1 -1
  50. package/esm/dev-server/parse-imports.mjs +1 -1
  51. package/esm/dev-server/special-file-patterns.mjs +4 -1
  52. package/esm/dev-server/special-file-patterns.mjs.map +1 -1
  53. package/esm/dev-server/type-generator.mjs +1 -1
  54. package/esm/e2e/cdp.d.mts.map +1 -1
  55. package/esm/e2e/cdp.mjs +9 -2
  56. package/esm/e2e/cdp.mjs.map +1 -1
  57. package/esm/e2e/index.d.mts +2 -2
  58. package/esm/e2e/page.d.mts +14 -1
  59. package/esm/e2e/page.d.mts.map +1 -1
  60. package/esm/e2e/page.mjs +81 -8
  61. package/esm/e2e/page.mjs.map +1 -1
  62. package/esm/e2e/types.d.mts +49 -0
  63. package/esm/e2e/types.d.mts.map +1 -1
  64. package/esm/e2e/types.mjs.map +1 -1
  65. package/esm/errors/error-codes.d.mts +72 -0
  66. package/esm/errors/error-codes.d.mts.map +1 -1
  67. package/esm/errors/error-codes.mjs +72 -0
  68. package/esm/errors/error-codes.mjs.map +1 -1
  69. package/esm/errors/index.d.mts +2 -2
  70. package/esm/errors/index.mjs +2 -2
  71. package/esm/generations/add-command.action.mjs +2 -0
  72. package/esm/generations/add-command.action.mjs.map +1 -1
  73. package/esm/generations/design-system-payload.mjs +53 -0
  74. package/esm/generations/design-system-payload.mjs.map +1 -0
  75. package/esm/generations/features/design-system.feature.mjs +38 -0
  76. package/esm/generations/features/design-system.feature.mjs.map +1 -0
  77. package/esm/generations/features/index.mjs +3 -1
  78. package/esm/generations/features/index.mjs.map +1 -1
  79. package/esm/generations/features/notifications.feature.mjs +13 -2
  80. package/esm/generations/features/notifications.feature.mjs.map +1 -1
  81. package/esm/generations/features/test.feature.mjs +48 -13
  82. package/esm/generations/features/test.feature.mjs.map +1 -1
  83. package/esm/generations/features/web.feature.mjs +3 -3
  84. package/esm/generations/features/web.feature.mjs.map +1 -1
  85. package/esm/generations/stubs.mjs +9 -5
  86. package/esm/generations/stubs.mjs.map +1 -1
  87. package/esm/http/error-mapper.d.mts +1 -1
  88. package/esm/http/error-mapper.mjs +3 -3
  89. package/esm/http/error-mapper.mjs.map +1 -1
  90. package/esm/http/error-response.d.mts +3 -0
  91. package/esm/http/error-response.d.mts.map +1 -1
  92. package/esm/http/error-response.mjs +8 -2
  93. package/esm/http/error-response.mjs.map +1 -1
  94. package/esm/http/errors/errors.d.mts +8 -0
  95. package/esm/http/errors/errors.d.mts.map +1 -1
  96. package/esm/http/errors/errors.mjs +13 -1
  97. package/esm/http/errors/errors.mjs.map +1 -1
  98. package/esm/http/index.d.mts +3 -2
  99. package/esm/http/index.mjs +3 -2
  100. package/esm/http/list-endpoint.d.mts +35 -0
  101. package/esm/http/list-endpoint.d.mts.map +1 -0
  102. package/esm/http/list-endpoint.mjs +28 -0
  103. package/esm/http/list-endpoint.mjs.map +1 -0
  104. package/esm/http/middleware/inject-request-context.d.mts.map +1 -1
  105. package/esm/http/middleware/inject-request-context.mjs +12 -2
  106. package/esm/http/middleware/inject-request-context.mjs.map +1 -1
  107. package/esm/http/server.mjs +1 -1
  108. package/esm/index.d.mts +10 -6
  109. package/esm/index.mjs +5 -2
  110. package/esm/localization/index.mjs +3 -1
  111. package/esm/localization/translation-usage-graph.d.mts +49 -0
  112. package/esm/localization/translation-usage-graph.d.mts.map +1 -0
  113. package/esm/localization/translation-usage-graph.mjs +128 -0
  114. package/esm/localization/translation-usage-graph.mjs.map +1 -0
  115. package/esm/localization/translation-usage.d.mts +85 -0
  116. package/esm/localization/translation-usage.d.mts.map +1 -0
  117. package/esm/localization/translation-usage.mjs +307 -0
  118. package/esm/localization/translation-usage.mjs.map +1 -0
  119. package/esm/openapi/security.mjs +12 -4
  120. package/esm/openapi/security.mjs.map +1 -1
  121. package/esm/openapi/types.d.mts +2 -0
  122. package/esm/openapi/types.d.mts.map +1 -1
  123. package/esm/production/build-budgets.d.mts +64 -0
  124. package/esm/production/build-budgets.d.mts.map +1 -0
  125. package/esm/production/build-budgets.mjs +109 -0
  126. package/esm/production/build-budgets.mjs.map +1 -0
  127. package/esm/production/production-builder.mjs +13 -1
  128. package/esm/production/production-builder.mjs.map +1 -1
  129. package/esm/production/resolve-build-config.d.mts +1 -1
  130. package/esm/production/resolve-build-config.d.mts.map +1 -1
  131. package/esm/production/resolve-build-config.mjs.map +1 -1
  132. package/esm/production/route-registration-snapshot.mjs +5 -3
  133. package/esm/production/route-registration-snapshot.mjs.map +1 -1
  134. package/esm/restful/restful.d.mts +1 -1
  135. package/esm/router/router.d.mts +2 -0
  136. package/esm/router/router.d.mts.map +1 -1
  137. package/esm/router/router.mjs +4 -1
  138. package/esm/router/router.mjs.map +1 -1
  139. package/esm/router/types.d.mts +19 -0
  140. package/esm/router/types.d.mts.map +1 -1
  141. package/esm/tests/fakes/storage-fake.d.mts +3 -1
  142. package/esm/tests/fakes/storage-fake.d.mts.map +1 -1
  143. package/esm/tests/fakes/storage-fake.mjs +3 -3
  144. package/esm/tests/fakes/storage-fake.mjs.map +1 -1
  145. package/esm/tests/fakes/test-fakes.d.mts +3 -1
  146. package/esm/tests/fakes/test-fakes.d.mts.map +1 -1
  147. package/esm/tests/fakes/test-fakes.mjs +3 -2
  148. package/esm/tests/fakes/test-fakes.mjs.map +1 -1
  149. package/esm/tests/index.d.mts +4 -2
  150. package/esm/tests/index.mjs +3 -1
  151. package/esm/tests/load-unit-config.mjs +24 -0
  152. package/esm/tests/load-unit-config.mjs.map +1 -0
  153. package/esm/tests/response-contract.d.mts +32 -0
  154. package/esm/tests/response-contract.d.mts.map +1 -0
  155. package/esm/tests/response-contract.mjs +116 -0
  156. package/esm/tests/response-contract.mjs.map +1 -0
  157. package/esm/tests/start-http-development-server.d.mts.map +1 -1
  158. package/esm/tests/start-http-development-server.mjs +10 -2
  159. package/esm/tests/start-http-development-server.mjs.map +1 -1
  160. package/esm/tests/test-lifecycle-state.mjs.map +1 -1
  161. package/esm/tests/test-locales.mjs +33 -0
  162. package/esm/tests/test-locales.mjs.map +1 -0
  163. package/esm/tests/test-runtime-scope.d.mts +15 -0
  164. package/esm/tests/test-runtime-scope.d.mts.map +1 -0
  165. package/esm/tests/test-runtime-scope.mjs +80 -0
  166. package/esm/tests/test-runtime-scope.mjs.map +1 -0
  167. package/esm/tests/vitest-setup.d.mts +13 -3
  168. package/esm/tests/vitest-setup.d.mts.map +1 -1
  169. package/esm/tests/vitest-setup.mjs +146 -18
  170. package/esm/tests/vitest-setup.mjs.map +1 -1
  171. package/esm/tooling/check/affected-files.d.mts +5 -0
  172. package/esm/tooling/check/affected-files.d.mts.map +1 -0
  173. package/esm/tooling/check/affected-files.mjs +56 -0
  174. package/esm/tooling/check/affected-files.mjs.map +1 -0
  175. package/esm/tooling/check/api-route-references.d.mts +16 -0
  176. package/esm/tooling/check/api-route-references.d.mts.map +1 -0
  177. package/esm/tooling/check/api-route-references.mjs +146 -0
  178. package/esm/tooling/check/api-route-references.mjs.map +1 -0
  179. package/esm/tooling/check/changed-files.d.mts +2 -0
  180. package/esm/tooling/check/changed-files.d.mts.map +1 -1
  181. package/esm/tooling/check/changed-files.mjs +2 -2
  182. package/esm/tooling/check/changed-files.mjs.map +1 -1
  183. package/esm/tooling/check/conventions-step.d.mts +7 -3
  184. package/esm/tooling/check/conventions-step.d.mts.map +1 -1
  185. package/esm/tooling/check/conventions-step.mjs +59 -8
  186. package/esm/tooling/check/conventions-step.mjs.map +1 -1
  187. package/esm/tooling/check/fixes.d.mts +8 -0
  188. package/esm/tooling/check/fixes.d.mts.map +1 -0
  189. package/esm/tooling/check/fixes.mjs +31 -0
  190. package/esm/tooling/check/fixes.mjs.map +1 -0
  191. package/esm/tooling/check/index.d.mts +12 -0
  192. package/esm/tooling/check/index.mjs +3 -2
  193. package/esm/tooling/check/run-check.d.mts +2 -0
  194. package/esm/tooling/check/run-check.d.mts.map +1 -1
  195. package/esm/tooling/check/run-check.mjs +23 -5
  196. package/esm/tooling/check/run-check.mjs.map +1 -1
  197. package/esm/tooling/check/run-tests.mjs +1 -1
  198. package/esm/tooling/check/source-ast.d.mts +1 -0
  199. package/esm/tooling/check/translation-conventions.mjs +32 -0
  200. package/esm/tooling/check/translation-conventions.mjs.map +1 -0
  201. package/esm/tooling/check/web-conventions.d.mts +10 -0
  202. package/esm/tooling/check/web-conventions.d.mts.map +1 -0
  203. package/esm/tooling/check/web-conventions.mjs +126 -0
  204. package/esm/tooling/check/web-conventions.mjs.map +1 -0
  205. package/esm/tooling/index.d.mts +7 -2
  206. package/esm/tooling/index.mjs +4 -2
  207. package/esm/tooling/inspect/collect-files.mjs +172 -0
  208. package/esm/tooling/inspect/collect-files.mjs.map +1 -0
  209. package/esm/tooling/inspect/collect-pages.mjs +3 -2
  210. package/esm/tooling/inspect/collect-pages.mjs.map +1 -1
  211. package/esm/tooling/inspect/collect-routes.mjs +1 -1
  212. package/esm/tooling/inspect/collect-routes.mjs.map +1 -1
  213. package/esm/tooling/inspect/explain-file.d.mts +12 -0
  214. package/esm/tooling/inspect/explain-file.d.mts.map +1 -0
  215. package/esm/tooling/inspect/explain-file.mjs +45 -0
  216. package/esm/tooling/inspect/explain-file.mjs.map +1 -0
  217. package/esm/tooling/inspect/index.d.mts +3 -2
  218. package/esm/tooling/inspect/index.mjs +2 -1
  219. package/esm/tooling/inspect/inspect-app.d.mts.map +1 -1
  220. package/esm/tooling/inspect/inspect-app.mjs +9 -3
  221. package/esm/tooling/inspect/inspect-app.mjs.map +1 -1
  222. package/esm/tooling/inspect/inspect-report.schema.mjs +34 -1
  223. package/esm/tooling/inspect/inspect-report.schema.mjs.map +1 -1
  224. package/esm/tooling/inspect/inspect-report.types.d.mts +17 -1
  225. package/esm/tooling/inspect/inspect-report.types.d.mts.map +1 -1
  226. package/esm/tooling/inspect/inspect-report.types.mjs +2 -1
  227. package/esm/tooling/inspect/inspect-report.types.mjs.map +1 -1
  228. package/esm/tooling/mcp/mcp-tools.d.mts.map +1 -1
  229. package/esm/tooling/mcp/mcp-tools.mjs +8 -2
  230. package/esm/tooling/mcp/mcp-tools.mjs.map +1 -1
  231. package/esm/tooling/problem.d.mts +4 -0
  232. package/esm/tooling/problem.d.mts.map +1 -1
  233. package/esm/tooling/problem.mjs +1 -0
  234. package/esm/tooling/problem.mjs.map +1 -1
  235. package/esm/tooling/syntax/ast.d.mts +2 -0
  236. package/esm/tooling/typecheck/run-typecheck.mjs +5 -1
  237. package/esm/tooling/typecheck/run-typecheck.mjs.map +1 -1
  238. package/esm/upgrade/codemods/index.mjs +2 -0
  239. package/esm/upgrade/codemods/index.mjs.map +1 -1
  240. package/esm/upgrade/codemods/vite-vitest.mjs +170 -0
  241. package/esm/upgrade/codemods/vite-vitest.mjs.map +1 -0
  242. package/esm/upgrade/notes.mjs +4 -0
  243. package/esm/upgrade/notes.mjs.map +1 -1
  244. package/esm/vite/index.d.mts +3 -1
  245. package/esm/vite/index.mjs +3 -1
  246. package/esm/vite/test-setup-reporter.d.mts +16 -0
  247. package/esm/vite/test-setup-reporter.d.mts.map +1 -0
  248. package/esm/vite/test-setup-reporter.mjs +55 -0
  249. package/esm/vite/test-setup-reporter.mjs.map +1 -0
  250. package/esm/vite/test-workers.d.mts +5 -0
  251. package/esm/vite/test-workers.d.mts.map +1 -0
  252. package/esm/vite/test-workers.mjs +38 -0
  253. package/esm/vite/test-workers.mjs.map +1 -0
  254. package/esm/warlock-config/index.d.mts +2 -1
  255. package/esm/warlock-config/types.d.mts +3 -0
  256. package/esm/warlock-config/types.d.mts.map +1 -1
  257. package/llms-full.txt +874 -9
  258. package/llms.txt +2 -0
  259. package/package.json +15 -14
  260. package/schemas/inspect-report.schema.json +47 -1
  261. package/skills/build-budgets/SKILL.md +51 -0
  262. package/skills/build-restful/SKILL.md +56 -0
  263. package/skills/configure-app/SKILL.md +7 -0
  264. package/skills/create-module/SKILL.md +9 -0
  265. package/skills/generate-web-ui/SKILL.md +71 -0
  266. package/skills/index.md +2 -2
  267. package/skills/register-route/SKILL.md +13 -0
  268. package/skills/run-app/SKILL.md +1 -1
  269. package/skills/send-mail/SKILL.md +25 -0
  270. package/skills/send-response/SKILL.md +50 -0
  271. package/skills/test-browser/SKILL.md +53 -0
  272. package/skills/test-http/SKILL.md +91 -0
  273. package/skills/test-service/SKILL.md +161 -3
  274. package/skills/upgrade-from-5-29/SKILL.md +109 -0
  275. package/skills/use-localization/SKILL.md +25 -0
  276. package/skills/warlock-check/SKILL.md +75 -1
  277. package/skills/warlock-inspect/SKILL.md +45 -2
  278. package/skills/warlock-mcp/SKILL.md +4 -0
  279. package/skills/write-cli-command/SKILL.md +18 -0
  280. package/esm/production/build-app-production.mjs +0 -14
  281. package/esm/production/build-app-production.mjs.map +0 -1
@@ -71,9 +71,10 @@ function exportsName(file, name) {
71
71
  *
72
72
  * @param pages The connector's installed page records; see {@link installedPagesFromConnectors}.
73
73
  */
74
- function collectPages(pages, cwd, warnings) {
74
+ function collectPages(pages, cwd, warnings, files) {
75
75
  if (!pages) return [];
76
76
  const collected = [];
77
+ const exports = files ? new Map(files.map((file) => [file.file, file.exports])) : void 0;
77
78
  for (const page of pages) {
78
79
  if (!isInstalledPage(page)) {
79
80
  warnings.push({
@@ -85,7 +86,7 @@ function collectPages(pages, cwd, warnings) {
85
86
  }
86
87
  const pageFile = path.isAbsolute(page.file) ? page.file : path.join(cwd, page.file);
87
88
  const layouts = layoutChainOf(pageFile, cwd);
88
- const loaders = [...layouts, pageFile].filter((file) => exportsName(file, "loader"));
89
+ const loaders = [...layouts, pageFile].filter((file) => exports ? exports.get(relativeTo(cwd, file))?.includes("loader") === true : exportsName(file, "loader"));
89
90
  const actions = Array.isArray(page.actions) ? page.actions.filter((action) => typeof action === "string") : [];
90
91
  collected.push({
91
92
  path: page.path,
@@ -1 +1 @@
1
- {"version":3,"file":"collect-pages.mjs","names":["ast.parseSourceFile","ast.topLevelDeclarations","ast.hasModifier","ast.isVariableStatement","ast.isIdentifier","ast.nameNode","ast.valueText","ast.isFunctionDeclaration","ast.declarationName","ast.isExportDeclaration"],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/collect-pages.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport * as ast from \"../syntax/ast\";\nimport { connectorsManager } from \"../../connectors/connectors-manager\";\nimport type { InspectPage, InspectWarning } from \"./inspect-report.types\";\n\n/** The fields of `@warlock.js/web`'s installed page record that inspect reads. */\ntype InstalledPageLike = {\n path: string;\n name?: unknown;\n file: string;\n actions?: unknown;\n guard?: unknown;\n};\n\nfunction isInstalledPage(value: unknown): value is InstalledPageLike {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof Reflect.get(value, \"path\") === \"string\" &&\n typeof Reflect.get(value, \"file\") === \"string\"\n );\n}\n\n/**\n * The pages the `web` connector installed, read through its public\n * `getInstalledPages()` without importing `@warlock.js/web`. `undefined` when\n * no such connector is registered (an API-only app).\n */\nexport function installedPagesFromConnectors(): unknown[] | undefined {\n const web = connectorsManager.list().find((connector) => connector.name === \"web\");\n const read = web ? Reflect.get(web, \"getInstalledPages\") : undefined;\n\n if (typeof read !== \"function\") return undefined;\n\n const pages: unknown = read.call(web);\n\n return Array.isArray(pages) ? pages : undefined;\n}\n\nfunction toPosix(file: string): string {\n return file.split(path.sep).join(\"/\");\n}\n\nfunction relativeTo(cwd: string, file: string): string {\n return toPosix(path.isAbsolute(file) ? path.relative(cwd, file) : file);\n}\n\n/**\n * The page's layout chain, outermost first: every `layout.tsx` from the web\n * root (the nearest ancestor holding `root.tsx`, else `src/`) down to the\n * page's own directory — the rule `@warlock.js/web` applies.\n */\nexport function layoutChainOf(pageFile: string, cwd: string): string[] {\n const srcRoot = path.join(cwd, \"src\");\n const directories: string[] = [];\n let current = path.dirname(pageFile);\n\n while (current.startsWith(srcRoot)) {\n directories.unshift(current);\n\n if (existsSync(path.join(current, \"root.tsx\")) || current === srcRoot) break;\n\n const parent = path.dirname(current);\n\n if (parent === current) break;\n\n current = parent;\n }\n\n return directories\n .map((directory) => path.join(directory, \"layout.tsx\"))\n .filter((candidate) => existsSync(candidate));\n}\n\n/**\n * Whether a module's source exports a binding named `name`, read with the\n * OXC parser (the page files are TSX that Node cannot import directly).\n */\nexport function exportsName(file: string, name: string): boolean {\n let source: string;\n\n try {\n source = readFileSync(file, \"utf8\");\n } catch {\n return false;\n }\n\n const sourceFile = ast.parseSourceFile(file, source);\n\n for (const statement of ast.topLevelDeclarations(sourceFile)) {\n const exported = ast.hasModifier(statement, \"export\");\n\n if (exported && ast.isVariableStatement(statement)) {\n if (\n statement.declarations.some(\n (declaration) =>\n ast.isIdentifier(ast.nameNode(declaration)) && ast.valueText(declaration.id) === name,\n )\n ) {\n return true;\n }\n }\n\n if (\n exported &&\n ast.isFunctionDeclaration(statement) &&\n ast.declarationName(statement) === name\n ) {\n return true;\n }\n\n if (\n ast.isExportDeclaration(statement) &&\n statement.specifiers.some((element) => ast.valueText(element.exported) === name)\n ) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Describe the installed pages: route path and name, page file, layout chain,\n * the files on that chain exporting a `loader`, actions and guard.\n *\n * @param pages The connector's installed page records; see {@link installedPagesFromConnectors}.\n */\nexport function collectPages(\n pages: readonly unknown[] | undefined,\n cwd: string,\n warnings: InspectWarning[],\n): InspectPage[] {\n if (!pages) return [];\n\n const collected: InspectPage[] = [];\n\n for (const page of pages) {\n if (!isInstalledPage(page)) {\n warnings.push({ code: null, message: \"A page record has no path or file.\", source: \"pages\" });\n continue;\n }\n\n const pageFile = path.isAbsolute(page.file) ? page.file : path.join(cwd, page.file);\n const layouts = layoutChainOf(pageFile, cwd);\n const loaders = [...layouts, pageFile].filter((file) => exportsName(file, \"loader\"));\n const actions = Array.isArray(page.actions)\n ? page.actions.filter((action): action is string => typeof action === \"string\")\n : [];\n\n collected.push({\n path: page.path,\n name: typeof page.name === \"string\" && page.name.length > 0 ? page.name : null,\n file: relativeTo(cwd, pageFile),\n layouts: layouts.map((file) => relativeTo(cwd, file)),\n loaders: loaders.map((file) => relativeTo(cwd, file)),\n actions: [...actions].sort(),\n guard: typeof page.guard === \"string\" ? page.guard : null,\n });\n }\n\n return collected.sort((first, second) => {\n if (first.path !== second.path) return first.path < second.path ? -1 : 1;\n\n return first.file.localeCompare(second.file);\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"collect-pages.mjs","names":["ast.parseSourceFile","ast.topLevelDeclarations","ast.hasModifier","ast.isVariableStatement","ast.isIdentifier","ast.nameNode","ast.valueText","ast.isFunctionDeclaration","ast.declarationName","ast.isExportDeclaration"],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/collect-pages.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport * as ast from \"../syntax/ast\";\nimport { connectorsManager } from \"../../connectors/connectors-manager\";\nimport type { InspectFile, InspectPage, InspectWarning } from \"./inspect-report.types\";\n\n/** The fields of `@warlock.js/web`'s installed page record that inspect reads. */\ntype InstalledPageLike = {\n path: string;\n name?: unknown;\n file: string;\n actions?: unknown;\n guard?: unknown;\n};\n\nfunction isInstalledPage(value: unknown): value is InstalledPageLike {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof Reflect.get(value, \"path\") === \"string\" &&\n typeof Reflect.get(value, \"file\") === \"string\"\n );\n}\n\n/**\n * The pages the `web` connector installed, read through its public\n * `getInstalledPages()` without importing `@warlock.js/web`. `undefined` when\n * no such connector is registered (an API-only app).\n */\nexport function installedPagesFromConnectors(): unknown[] | undefined {\n const web = connectorsManager.list().find((connector) => connector.name === \"web\");\n const read = web ? Reflect.get(web, \"getInstalledPages\") : undefined;\n\n if (typeof read !== \"function\") return undefined;\n\n const pages: unknown = read.call(web);\n\n return Array.isArray(pages) ? pages : undefined;\n}\n\nfunction toPosix(file: string): string {\n return file.split(path.sep).join(\"/\");\n}\n\nfunction relativeTo(cwd: string, file: string): string {\n return toPosix(path.isAbsolute(file) ? path.relative(cwd, file) : file);\n}\n\n/**\n * The page's layout chain, outermost first: every `layout.tsx` from the web\n * root (the nearest ancestor holding `root.tsx`, else `src/`) down to the\n * page's own directory — the rule `@warlock.js/web` applies.\n */\nexport function layoutChainOf(pageFile: string, cwd: string): string[] {\n const srcRoot = path.join(cwd, \"src\");\n const directories: string[] = [];\n let current = path.dirname(pageFile);\n\n while (current.startsWith(srcRoot)) {\n directories.unshift(current);\n\n if (existsSync(path.join(current, \"root.tsx\")) || current === srcRoot) break;\n\n const parent = path.dirname(current);\n\n if (parent === current) break;\n\n current = parent;\n }\n\n return directories\n .map((directory) => path.join(directory, \"layout.tsx\"))\n .filter((candidate) => existsSync(candidate));\n}\n\n/**\n * Whether a module's source exports a binding named `name`, read with the\n * OXC parser (the page files are TSX that Node cannot import directly).\n */\nexport function exportsName(file: string, name: string): boolean {\n let source: string;\n\n try {\n source = readFileSync(file, \"utf8\");\n } catch {\n return false;\n }\n\n const sourceFile = ast.parseSourceFile(file, source);\n\n for (const statement of ast.topLevelDeclarations(sourceFile)) {\n const exported = ast.hasModifier(statement, \"export\");\n\n if (exported && ast.isVariableStatement(statement)) {\n if (\n statement.declarations.some(\n (declaration) =>\n ast.isIdentifier(ast.nameNode(declaration)) && ast.valueText(declaration.id) === name,\n )\n ) {\n return true;\n }\n }\n\n if (\n exported &&\n ast.isFunctionDeclaration(statement) &&\n ast.declarationName(statement) === name\n ) {\n return true;\n }\n\n if (\n ast.isExportDeclaration(statement) &&\n statement.specifiers.some((element) => ast.valueText(element.exported) === name)\n ) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Describe the installed pages: route path and name, page file, layout chain,\n * the files on that chain exporting a `loader`, actions and guard.\n *\n * @param pages The connector's installed page records; see {@link installedPagesFromConnectors}.\n */\nexport function collectPages(\n pages: readonly unknown[] | undefined,\n cwd: string,\n warnings: InspectWarning[],\n files?: readonly InspectFile[],\n): InspectPage[] {\n if (!pages) return [];\n\n const collected: InspectPage[] = [];\n const exports = files ? new Map(files.map((file) => [file.file, file.exports])) : undefined;\n\n for (const page of pages) {\n if (!isInstalledPage(page)) {\n warnings.push({ code: null, message: \"A page record has no path or file.\", source: \"pages\" });\n continue;\n }\n\n const pageFile = path.isAbsolute(page.file) ? page.file : path.join(cwd, page.file);\n const layouts = layoutChainOf(pageFile, cwd);\n const loaders = [...layouts, pageFile].filter((file) =>\n exports\n ? exports.get(relativeTo(cwd, file))?.includes(\"loader\") === true\n : exportsName(file, \"loader\"),\n );\n const actions = Array.isArray(page.actions)\n ? page.actions.filter((action): action is string => typeof action === \"string\")\n : [];\n\n collected.push({\n path: page.path,\n name: typeof page.name === \"string\" && page.name.length > 0 ? page.name : null,\n file: relativeTo(cwd, pageFile),\n layouts: layouts.map((file) => relativeTo(cwd, file)),\n loaders: loaders.map((file) => relativeTo(cwd, file)),\n actions: [...actions].sort(),\n guard: typeof page.guard === \"string\" ? page.guard : null,\n });\n }\n\n return collected.sort((first, second) => {\n if (first.path !== second.path) return first.path < second.path ? -1 : 1;\n\n return first.file.localeCompare(second.file);\n });\n}\n"],"mappings":"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"}
@@ -134,7 +134,7 @@ function collectRoutes(routes, registry, warnings) {
134
134
  isPage: route.isPage === true,
135
135
  middleware: (route.middleware ?? []).map(functionName),
136
136
  auth: auth ? {
137
- required: true,
137
+ required: auth.required !== false,
138
138
  sources: auth.sources,
139
139
  userTypes: auth.userTypes
140
140
  } : {
@@ -1 +1 @@
1
- {"version":3,"file":"collect-routes.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/collect-routes.ts"],"sourcesContent":["import { config } from \"../../config/config-getter\";\nimport { buildRateLimitOptions } from \"../../http/build-rate-limit-options\";\nimport type { HttpLoggingConfig } from \"../../http/request-log-snapshot\";\nimport { expandMethods } from \"../../openapi/paths\";\nimport { buildRequestParts } from \"../../openapi/request-schemas\";\nimport { buildDeclaredResponses } from \"../../openapi/response-schemas\";\nimport type { SchemaRegistry } from \"../../openapi/schema-registry\";\nimport { readRouteAuth } from \"../../openapi/security\";\nimport type { Route } from \"../../router/types\";\nimport type {\n InspectRoute,\n InspectRouteLogging,\n InspectRouteRateLimit,\n InspectWarning,\n JsonSchema,\n} from \"./inspect-report.types\";\n\n/** Display order of methods within one path, matching `warlock routes`. */\nconst METHOD_ORDER = [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"OPTIONS\", \"HEAD\", \"ALL\"];\n\nfunction methodRank(method: string): number {\n const index = METHOD_ORDER.indexOf(method);\n\n return index === -1 ? METHOD_ORDER.length : index;\n}\n\n/** The name of a function, without the `bound ` prefix `bind()` adds. */\nexport function functionName(value: unknown): string {\n if (typeof value !== \"function\") return \"anonymous\";\n\n const name = value.name.replace(/^bound /, \"\").trim();\n\n return name.length > 0 ? name : \"anonymous\";\n}\n\nfunction limitValue(value: unknown): number | \"dynamic\" | null {\n if (typeof value === \"number\") return value;\n\n return value === undefined || value === null ? null : \"dynamic\";\n}\n\nfunction windowValue(value: unknown): number | string | null {\n if (typeof value === \"number\" || typeof value === \"string\") return value;\n\n return value === undefined || value === null ? null : \"dynamic\";\n}\n\n/**\n * The limiter a route runs under: its own `rateLimit` options, else the global\n * `http.rateLimit` limiter (built with the same defaults the HTTP connector\n * uses), else none. `rateLimit: false` exempts the route from the global\n * limiter; `rateLimit: true` keeps it under the global policy.\n */\nfunction readRateLimit(\n route: Route,\n global: Record<string, unknown> | null,\n): InspectRouteRateLimit {\n if (typeof route.rateLimit === \"object\" && route.rateLimit !== null) {\n return { source: \"route\", max: route.rateLimit.max, timeWindow: route.rateLimit.timeWindow };\n }\n\n if (!global || route.rateLimit === false) {\n return { source: \"none\", max: null, timeWindow: null };\n }\n\n return {\n source: \"global\",\n max: limitValue(global.max),\n timeWindow: windowValue(global.timeWindow),\n };\n}\n\n/**\n * What the route's request logs keep: the route's `logging` option over\n * `http.logging`, the same precedence `resolveRequestLoggingOptions` applies.\n * Private URL rules can only remove more, per URL, so they are flagged rather\n * than evaluated.\n */\nfunction readLogging(route: Route, global: HttpLoggingConfig): InspectRouteLogging {\n return {\n body: route.logging?.body ?? global.body ?? true,\n query: route.logging?.query ?? global.query ?? true,\n privateRules: (global.private?.length ?? 0) > 0,\n };\n}\n\nfunction globalRateLimit(warnings: InspectWarning[]): Record<string, unknown> | null {\n try {\n const options = buildRateLimitOptions(config.get(\"http.rateLimit\"));\n\n return options ? { max: options.max, timeWindow: options.timeWindow } : null;\n } catch (error) {\n warnings.push({\n code: null,\n message: `http.rateLimit could not be read: ${error instanceof Error ? error.message : String(error)}`,\n source: \"routes\",\n });\n\n return null;\n }\n}\n\n/**\n * Describe every route: identity, middleware chain, guard, limits, logging and\n * the request/response schemas the OpenAPI generator derives (the same\n * `buildRequestParts` / `buildDeclaredResponses` code, so `inspect` and\n * `generate.openapi` never disagree). Resource `$ref`s land in `registry`.\n */\nexport function collectRoutes(\n routes: readonly Route[],\n registry: SchemaRegistry,\n warnings: InspectWarning[],\n): InspectRoute[] {\n const rateLimit = globalRateLimit(warnings);\n const logging = (config.get(\"http.logging\") ?? {}) as HttpLoggingConfig;\n\n const collected = routes.map((route): InspectRoute => {\n const method = String(route.method).toUpperCase();\n const label = `${method} ${route.path}`;\n const warn = (message: string) => {\n warnings.push({\n code: message.includes(\"JSON Schema\") ? \"WL4001\" : null,\n message: `${label}: ${message}`,\n source: route.sourceFile || null,\n });\n };\n const handler = route.handler as Route[\"handler\"] | undefined;\n const validation = handler?.validation;\n const auth = readRouteAuth(route.middleware, warn);\n const request = buildRequestParts({\n method: expandMethods(route.method)[0] ?? \"get\",\n path: route.path,\n validation,\n warn,\n });\n const body = request.requestBody?.content[\"application/json\"]?.schema;\n const responses: InspectRoute[\"responses\"] = {};\n\n for (const [status, response] of Object.entries(\n buildDeclaredResponses(handler?.responseSchema, registry, warn),\n )) {\n const schema: JsonSchema | undefined = response.content?.[\"application/json\"]?.schema;\n\n responses[status] = { description: response.description, schema: schema ?? null };\n }\n\n return {\n method,\n path: route.path,\n name: route.name ? route.name : null,\n sourceFile: route.sourceFile ? route.sourceFile : null,\n handler: functionName(handler),\n description: route.description ?? handler?.description ?? null,\n isPage: route.isPage === true,\n middleware: (route.middleware ?? []).map(functionName),\n auth: auth\n ? { required: true, sources: auth.sources, userTypes: auth.userTypes }\n : { required: false, sources: [], userTypes: [] },\n csrf: route.csrf !== false,\n rateLimit: readRateLimit(route, rateLimit),\n logging: readLogging(route, logging),\n request: {\n parameters: request.parameters.map((parameter) => ({\n name: parameter.name,\n in: parameter.in,\n required: parameter.required === true,\n schema: parameter.schema,\n })),\n body: body ?? null,\n customValidation: typeof validation?.validate === \"function\",\n },\n responses,\n };\n });\n\n return collected.sort((first, second) => {\n if (first.path !== second.path) return first.path < second.path ? -1 : 1;\n\n return methodRank(first.method) - methodRank(second.method);\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"collect-routes.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/collect-routes.ts"],"sourcesContent":["import { config } from \"../../config/config-getter\";\nimport { buildRateLimitOptions } from \"../../http/build-rate-limit-options\";\nimport type { HttpLoggingConfig } from \"../../http/request-log-snapshot\";\nimport { expandMethods } from \"../../openapi/paths\";\nimport { buildRequestParts } from \"../../openapi/request-schemas\";\nimport { buildDeclaredResponses } from \"../../openapi/response-schemas\";\nimport type { SchemaRegistry } from \"../../openapi/schema-registry\";\nimport { readRouteAuth } from \"../../openapi/security\";\nimport type { Route } from \"../../router/types\";\nimport type {\n InspectRoute,\n InspectRouteLogging,\n InspectRouteRateLimit,\n InspectWarning,\n JsonSchema,\n} from \"./inspect-report.types\";\n\n/** Display order of methods within one path, matching `warlock routes`. */\nconst METHOD_ORDER = [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"OPTIONS\", \"HEAD\", \"ALL\"];\n\nfunction methodRank(method: string): number {\n const index = METHOD_ORDER.indexOf(method);\n\n return index === -1 ? METHOD_ORDER.length : index;\n}\n\n/** The name of a function, without the `bound ` prefix `bind()` adds. */\nexport function functionName(value: unknown): string {\n if (typeof value !== \"function\") return \"anonymous\";\n\n const name = value.name.replace(/^bound /, \"\").trim();\n\n return name.length > 0 ? name : \"anonymous\";\n}\n\nfunction limitValue(value: unknown): number | \"dynamic\" | null {\n if (typeof value === \"number\") return value;\n\n return value === undefined || value === null ? null : \"dynamic\";\n}\n\nfunction windowValue(value: unknown): number | string | null {\n if (typeof value === \"number\" || typeof value === \"string\") return value;\n\n return value === undefined || value === null ? null : \"dynamic\";\n}\n\n/**\n * The limiter a route runs under: its own `rateLimit` options, else the global\n * `http.rateLimit` limiter (built with the same defaults the HTTP connector\n * uses), else none. `rateLimit: false` exempts the route from the global\n * limiter; `rateLimit: true` keeps it under the global policy.\n */\nfunction readRateLimit(\n route: Route,\n global: Record<string, unknown> | null,\n): InspectRouteRateLimit {\n if (typeof route.rateLimit === \"object\" && route.rateLimit !== null) {\n return { source: \"route\", max: route.rateLimit.max, timeWindow: route.rateLimit.timeWindow };\n }\n\n if (!global || route.rateLimit === false) {\n return { source: \"none\", max: null, timeWindow: null };\n }\n\n return {\n source: \"global\",\n max: limitValue(global.max),\n timeWindow: windowValue(global.timeWindow),\n };\n}\n\n/**\n * What the route's request logs keep: the route's `logging` option over\n * `http.logging`, the same precedence `resolveRequestLoggingOptions` applies.\n * Private URL rules can only remove more, per URL, so they are flagged rather\n * than evaluated.\n */\nfunction readLogging(route: Route, global: HttpLoggingConfig): InspectRouteLogging {\n return {\n body: route.logging?.body ?? global.body ?? true,\n query: route.logging?.query ?? global.query ?? true,\n privateRules: (global.private?.length ?? 0) > 0,\n };\n}\n\nfunction globalRateLimit(warnings: InspectWarning[]): Record<string, unknown> | null {\n try {\n const options = buildRateLimitOptions(config.get(\"http.rateLimit\"));\n\n return options ? { max: options.max, timeWindow: options.timeWindow } : null;\n } catch (error) {\n warnings.push({\n code: null,\n message: `http.rateLimit could not be read: ${error instanceof Error ? error.message : String(error)}`,\n source: \"routes\",\n });\n\n return null;\n }\n}\n\n/**\n * Describe every route: identity, middleware chain, guard, limits, logging and\n * the request/response schemas the OpenAPI generator derives (the same\n * `buildRequestParts` / `buildDeclaredResponses` code, so `inspect` and\n * `generate.openapi` never disagree). Resource `$ref`s land in `registry`.\n */\nexport function collectRoutes(\n routes: readonly Route[],\n registry: SchemaRegistry,\n warnings: InspectWarning[],\n): InspectRoute[] {\n const rateLimit = globalRateLimit(warnings);\n const logging = (config.get(\"http.logging\") ?? {}) as HttpLoggingConfig;\n\n const collected = routes.map((route): InspectRoute => {\n const method = String(route.method).toUpperCase();\n const label = `${method} ${route.path}`;\n const warn = (message: string) => {\n warnings.push({\n code: message.includes(\"JSON Schema\") ? \"WL4001\" : null,\n message: `${label}: ${message}`,\n source: route.sourceFile || null,\n });\n };\n const handler = route.handler as Route[\"handler\"] | undefined;\n const validation = handler?.validation;\n const auth = readRouteAuth(route.middleware, warn);\n const request = buildRequestParts({\n method: expandMethods(route.method)[0] ?? \"get\",\n path: route.path,\n validation,\n warn,\n });\n const body = request.requestBody?.content[\"application/json\"]?.schema;\n const responses: InspectRoute[\"responses\"] = {};\n\n for (const [status, response] of Object.entries(\n buildDeclaredResponses(handler?.responseSchema, registry, warn),\n )) {\n const schema: JsonSchema | undefined = response.content?.[\"application/json\"]?.schema;\n\n responses[status] = { description: response.description, schema: schema ?? null };\n }\n\n return {\n method,\n path: route.path,\n name: route.name ? route.name : null,\n sourceFile: route.sourceFile ? route.sourceFile : null,\n handler: functionName(handler),\n description: route.description ?? handler?.description ?? null,\n isPage: route.isPage === true,\n middleware: (route.middleware ?? []).map(functionName),\n auth: auth\n ? { required: auth.required !== false, sources: auth.sources, userTypes: auth.userTypes }\n : { required: false, sources: [], userTypes: [] },\n csrf: route.csrf !== false,\n rateLimit: readRateLimit(route, rateLimit),\n logging: readLogging(route, logging),\n request: {\n parameters: request.parameters.map((parameter) => ({\n name: parameter.name,\n in: parameter.in,\n required: parameter.required === true,\n schema: parameter.schema,\n })),\n body: body ?? null,\n customValidation: typeof validation?.validate === \"function\",\n },\n responses,\n };\n });\n\n return collected.sort((first, second) => {\n if (first.path !== second.path) return first.path < second.path ? -1 : 1;\n\n return methodRank(first.method) - methodRank(second.method);\n });\n}\n"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { InspectFile, InspectPage, InspectReport, InspectRoute } from "./inspect-report.types.mjs";
2
+ //#region ../../packages/core/src/tooling/inspect/explain-file.d.ts
3
+ export type ExplainedFile = InspectFile & {
4
+ /** Entry points whose static imports transitively reach this file. */
5
+ routes: InspectRoute[];
6
+ pages: InspectPage[];
7
+ warnings: InspectReport["warnings"];
8
+ };
9
+ /** Explain a project-relative or absolute source path against one inspect snapshot. */
10
+ export declare function explainFile(requested: string, report: InspectReport): ExplainedFile;
11
+ //#endregion
12
+ //# sourceMappingURL=explain-file.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain-file.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/explain-file.ts"],"mappings":";;YAGY,gBAAgB;;EAE1B,QAAQ;EACR,OAAO;EACP,UAAU;;;wBAII,YAAY,mBAAmB,QAAQ,gBAAgB"}
@@ -0,0 +1,45 @@
1
+ import { projectFile } from "./collect-files.mjs";
2
+
3
+ //#region ../../packages/core/src/tooling/inspect/explain-file.ts
4
+ /** Explain a project-relative or absolute source path against one inspect snapshot. */
5
+ function explainFile(requested, report) {
6
+ const requestedFile = projectFile(report.app.root, requested);
7
+ const files = new Map((report.files ?? []).map((file) => [file.file, file]));
8
+ const file = files.get(requestedFile);
9
+ if (!file) throw new Error(`Source file ${JSON.stringify(requested)} was not found under src/.`);
10
+ const reached = /* @__PURE__ */ new Set();
11
+ const pending = [file.file];
12
+ while (pending.length > 0) {
13
+ const current = pending.pop();
14
+ if (current === void 0 || reached.has(current)) continue;
15
+ reached.add(current);
16
+ pending.push(...files.get(current)?.importedBy ?? []);
17
+ }
18
+ const reaches = (entry) => reached.has(projectFile(report.app.root, entry));
19
+ return {
20
+ ...file,
21
+ routes: (report.routes ?? []).filter((route) => route.sourceFile !== null && reaches(route.sourceFile)),
22
+ pages: (report.pages ?? []).filter((page) => [
23
+ page.file,
24
+ ...page.layouts,
25
+ ...page.loaders
26
+ ].some(reaches)),
27
+ warnings: report.warnings
28
+ };
29
+ }
30
+ function formatFileExplanation(file) {
31
+ return [
32
+ `${file.file} (${file.role})`,
33
+ ` Module: ${file.module}`,
34
+ ` Exports: ${file.exports.join(", ") || "none"}`,
35
+ ` Imports: ${file.imports.map((entry) => entry.file ?? entry.specifier).join(", ") || "none"}`,
36
+ ` Imported by: ${file.importedBy.join(", ") || "none"}`,
37
+ ` Routes: ${file.routes.map((route) => `${route.method} ${route.path}`).join(", ") || "none"}`,
38
+ ` Pages: ${file.pages.map((page) => page.path).join(", ") || "none"}`,
39
+ ...file.warnings.map((warning) => ` Warning: ${warning.message}`)
40
+ ];
41
+ }
42
+
43
+ //#endregion
44
+ export { explainFile, formatFileExplanation };
45
+ //# sourceMappingURL=explain-file.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain-file.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/explain-file.ts"],"sourcesContent":["import type { InspectFile, InspectPage, InspectReport, InspectRoute } from \"./inspect-report.types\";\nimport { projectFile } from \"./collect-files\";\n\nexport type ExplainedFile = InspectFile & {\n /** Entry points whose static imports transitively reach this file. */\n routes: InspectRoute[];\n pages: InspectPage[];\n warnings: InspectReport[\"warnings\"];\n};\n\n/** Explain a project-relative or absolute source path against one inspect snapshot. */\nexport function explainFile(requested: string, report: InspectReport): ExplainedFile {\n const requestedFile = projectFile(report.app.root, requested);\n const files = new Map((report.files ?? []).map((file) => [file.file, file]));\n const file = files.get(requestedFile);\n if (!file) throw new Error(`Source file ${JSON.stringify(requested)} was not found under src/.`);\n\n // Walk reverse edges once, including cycles and the entry point itself.\n const reached = new Set<string>();\n const pending = [file.file];\n while (pending.length > 0) {\n const current = pending.pop();\n if (current === undefined || reached.has(current)) continue;\n reached.add(current);\n pending.push(...(files.get(current)?.importedBy ?? []));\n }\n const reaches = (entry: string): boolean => reached.has(projectFile(report.app.root, entry));\n return {\n ...file,\n routes: (report.routes ?? []).filter(\n (route) => route.sourceFile !== null && reaches(route.sourceFile),\n ),\n pages: (report.pages ?? []).filter((page) =>\n [page.file, ...page.layouts, ...page.loaders].some(reaches),\n ),\n warnings: report.warnings,\n };\n}\n\nexport function formatFileExplanation(file: ExplainedFile): string[] {\n return [\n `${file.file} (${file.role})`,\n ` Module: ${file.module}`,\n ` Exports: ${file.exports.join(\", \") || \"none\"}`,\n ` Imports: ${file.imports.map((entry) => entry.file ?? entry.specifier).join(\", \") || \"none\"}`,\n ` Imported by: ${file.importedBy.join(\", \") || \"none\"}`,\n ` Routes: ${file.routes.map((route) => `${route.method} ${route.path}`).join(\", \") || \"none\"}`,\n ` Pages: ${file.pages.map((page) => page.path).join(\", \") || \"none\"}`,\n ...file.warnings.map((warning) => ` Warning: ${warning.message}`),\n ];\n}\n"],"mappings":";;;;AAWA,SAAgB,YAAY,WAAmB,QAAsC;CACnF,MAAM,gBAAgB,YAAY,OAAO,IAAI,MAAM,SAAS;CAC5D,MAAM,QAAQ,IAAI,KAAK,OAAO,SAAS,CAAC,EAAC,CAAE,KAAK,SAAS,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC;CAC3E,MAAM,OAAO,MAAM,IAAI,aAAa;CACpC,IAAI,CAAC,MAAM,MAAM,IAAI,MAAM,eAAe,KAAK,UAAU,SAAS,EAAE,2BAA2B;CAG/F,MAAM,0BAAU,IAAI,IAAY;CAChC,MAAM,UAAU,CAAC,KAAK,IAAI;CAC1B,OAAO,QAAQ,SAAS,GAAG;EACzB,MAAM,UAAU,QAAQ,IAAI;EAC5B,IAAI,YAAY,UAAa,QAAQ,IAAI,OAAO,GAAG;EACnD,QAAQ,IAAI,OAAO;EACnB,QAAQ,KAAK,GAAI,MAAM,IAAI,OAAO,CAAC,EAAE,cAAc,CAAC,CAAE;CACxD;CACA,MAAM,WAAW,UAA2B,QAAQ,IAAI,YAAY,OAAO,IAAI,MAAM,KAAK,CAAC;CAC3F,OAAO;EACL,GAAG;EACH,SAAS,OAAO,UAAU,CAAC,EAAC,CAAE,QAC3B,UAAU,MAAM,eAAe,QAAQ,QAAQ,MAAM,UAAU,CAClE;EACA,QAAQ,OAAO,SAAS,CAAC,EAAC,CAAE,QAAQ,SAClC;GAAC,KAAK;GAAM,GAAG,KAAK;GAAS,GAAG,KAAK;EAAO,CAAC,CAAC,KAAK,OAAO,CAC5D;EACA,UAAU,OAAO;CACnB;AACF;AAEA,SAAgB,sBAAsB,MAA+B;CACnE,OAAO;EACL,GAAG,KAAK,KAAK,KAAK,KAAK,KAAK;EAC5B,aAAa,KAAK;EAClB,cAAc,KAAK,QAAQ,KAAK,IAAI,KAAK;EACzC,cAAc,KAAK,QAAQ,KAAK,UAAU,MAAM,QAAQ,MAAM,SAAS,CAAC,CAAC,KAAK,IAAI,KAAK;EACvF,kBAAkB,KAAK,WAAW,KAAK,IAAI,KAAK;EAChD,aAAa,KAAK,OAAO,KAAK,UAAU,GAAG,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,CAAC,KAAK,IAAI,KAAK;EACvF,YAAY,KAAK,MAAM,KAAK,SAAS,KAAK,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK;EAC9D,GAAG,KAAK,SAAS,KAAK,YAAY,cAAc,QAAQ,SAAS;CACnE;AACF"}
@@ -1,8 +1,9 @@
1
- import { INSPECT_SCHEMA_VERSION, INSPECT_SECTIONS, InspectConfigKey, InspectEvent, InspectJob, InspectModel, InspectModelColumn, InspectModelRelation, InspectPackage, InspectPage, InspectParameter, InspectReport, InspectResource, InspectRoute, InspectRouteAuth, InspectRouteLogging, InspectRouteRateLimit, InspectSchedule, InspectSection, InspectWarning, JsonSchema } from "./inspect-report.types.mjs";
1
+ import { INSPECT_SCHEMA_VERSION, INSPECT_SECTIONS, InspectConfigKey, InspectEvent, InspectFile, InspectJob, InspectModel, InspectModelColumn, InspectModelRelation, InspectPackage, InspectPage, InspectParameter, InspectReport, InspectResource, InspectRoute, InspectRouteAuth, InspectRouteLogging, InspectRouteRateLimit, InspectSchedule, InspectSection, InspectWarning, JsonSchema } from "./inspect-report.types.mjs";
2
2
  import { EventRecorder, RecordedListener, groupListeners } from "./event-recorder.mjs";
3
3
  import { InspectModelModule } from "./collect-models.mjs";
4
4
  import { AppModuleImporter } from "./collect-packages.mjs";
5
5
  import { InspectOptions, inspectApp, isInspectSection, parseInspectSections } from "./inspect-app.mjs";
6
6
  import { InspectBootResult, bootForInspect, inspectOptionsFromBoot } from "./boot-for-inspect.mjs";
7
7
  import { INSPECT_REPORT_JSON_SCHEMA } from "./inspect-report.schema.mjs";
8
- export { type AppModuleImporter, EventRecorder, INSPECT_REPORT_JSON_SCHEMA, INSPECT_SCHEMA_VERSION, INSPECT_SECTIONS, type InspectBootResult, InspectConfigKey, InspectEvent, InspectJob, InspectModel, InspectModelColumn, type InspectModelModule, InspectModelRelation, type InspectOptions, InspectPackage, InspectPage, InspectParameter, InspectReport, InspectResource, InspectRoute, InspectRouteAuth, InspectRouteLogging, InspectRouteRateLimit, InspectSchedule, InspectSection, InspectWarning, JsonSchema, type RecordedListener, bootForInspect, groupListeners, inspectApp, inspectOptionsFromBoot, isInspectSection, parseInspectSections };
8
+ import { ExplainedFile, explainFile } from "./explain-file.mjs";
9
+ export { type AppModuleImporter, EventRecorder, type ExplainedFile, INSPECT_REPORT_JSON_SCHEMA, INSPECT_SCHEMA_VERSION, INSPECT_SECTIONS, type InspectBootResult, InspectConfigKey, InspectEvent, InspectFile, InspectJob, InspectModel, InspectModelColumn, type InspectModelModule, InspectModelRelation, type InspectOptions, InspectPackage, InspectPage, InspectParameter, InspectReport, InspectResource, InspectRoute, InspectRouteAuth, InspectRouteLogging, InspectRouteRateLimit, InspectSchedule, InspectSection, InspectWarning, JsonSchema, type RecordedListener, bootForInspect, explainFile, groupListeners, inspectApp, inspectOptionsFromBoot, isInspectSection, parseInspectSections };
@@ -2,6 +2,7 @@ import { EventRecorder, groupListeners } from "./event-recorder.mjs";
2
2
  import { bootForInspect, inspectOptionsFromBoot } from "./boot-for-inspect.mjs";
3
3
  import { INSPECT_SCHEMA_VERSION, INSPECT_SECTIONS } from "./inspect-report.types.mjs";
4
4
  import { inspectApp, isInspectSection, parseInspectSections } from "./inspect-app.mjs";
5
+ import { explainFile } from "./explain-file.mjs";
5
6
  import { INSPECT_REPORT_JSON_SCHEMA } from "./inspect-report.schema.mjs";
6
7
 
7
- export { EventRecorder, INSPECT_REPORT_JSON_SCHEMA, INSPECT_SCHEMA_VERSION, INSPECT_SECTIONS, bootForInspect, groupListeners, inspectApp, inspectOptionsFromBoot, isInspectSection, parseInspectSections };
8
+ export { EventRecorder, INSPECT_REPORT_JSON_SCHEMA, INSPECT_SCHEMA_VERSION, INSPECT_SECTIONS, bootForInspect, explainFile, groupListeners, inspectApp, inspectOptionsFromBoot, isInspectSection, parseInspectSections };
@@ -1 +1 @@
1
- {"version":3,"file":"inspect-app.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/inspect-app.ts"],"mappings":";;;;;;;YA0BY;;EAEV;;EAEA,oBAAoB;;EAEpB,kBAAkB;;EAElB,wBAAwB;;EAExB,kBAAkB;;EAElB,oBAAoB;;EAEpB;IAA4B;IAAc;;;EAE1C;;;;;EAKA,uBAAuB;;EAEvB,SAAS;;EAET,gBAAgB;;EAEhB,YAAY;;;wBAIE,iBAAiB,gBAAgB,SAAS;;;;;wBAQ1C,qBAAqB,4BAA4B;;;;;;;;;;;;;;wBA+B3C,WAAW,UAAS,iBAAsB,QAAQ"}
1
+ {"version":3,"file":"inspect-app.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/inspect-app.ts"],"mappings":";;;;;;;YA2BY;;EAEV;;EAEA,oBAAoB;;EAEpB,kBAAkB;;EAElB,wBAAwB;;EAExB,kBAAkB;;EAElB,oBAAoB;;EAEpB;IAA4B;IAAc;;;EAE1C;;;;;EAKA,uBAAuB;;EAEvB,SAAS;;EAET,gBAAgB;;EAEhB,YAAY;;;wBAIE,iBAAiB,gBAAgB,SAAS;;;;;wBAQ1C,qBAAqB,4BAA4B;;;;;;;;;;;;;;wBA+B3C,WAAW,UAAS,iBAAsB,QAAQ"}
@@ -2,6 +2,7 @@ import { Application } from "../../application/application.mjs";
2
2
  import { router } from "../../router/router.mjs";
3
3
  import { SchemaRegistry } from "../../openapi/schema-registry.mjs";
4
4
  import { groupListeners } from "./event-recorder.mjs";
5
+ import { collectFiles } from "./collect-files.mjs";
5
6
  import { collectConfig } from "./collect-config.mjs";
6
7
  import { collectModels, collectResources } from "./collect-models.mjs";
7
8
  import { collectJobs, collectPackages, collectSchedules, createAppModuleImporter, readAppPackage } from "./collect-packages.mjs";
@@ -72,14 +73,19 @@ async function inspectApp(options = {}) {
72
73
  components: { schemas: {} },
73
74
  warnings
74
75
  };
75
- const routes = collectRoutes(options.routes ?? router.list(), registry, warnings);
76
- const { models, resourceModels } = collectModels(options.modelModules ?? [], registry, warnings);
76
+ const filesOnly = sections.every((section) => section === "files");
77
+ const routes = !filesOnly ? collectRoutes(options.routes ?? router.list(), registry, warnings) : [];
78
+ const { models, resourceModels } = !filesOnly ? collectModels(options.modelModules ?? [], registry, warnings) : {
79
+ models: [],
80
+ resourceModels: /* @__PURE__ */ new Map()
81
+ };
82
+ if (wants.has("files")) report.files = collectFiles(cwd, warnings);
77
83
  if (wants.has("routes")) report.routes = routes;
78
84
  if (wants.has("models")) report.models = models;
79
85
  if (wants.has("resources")) report.resources = collectResources(registry, resourceModels);
80
86
  if (wants.has("config")) report.config = collectConfig(cwd, options.config);
81
87
  if (wants.has("events")) report.events = groupListeners(options.events ?? []);
82
- if (wants.has("pages")) report.pages = collectPages(options.pages ?? installedPagesFromConnectors(), cwd, warnings);
88
+ if (wants.has("pages")) report.pages = collectPages(options.pages ?? installedPagesFromConnectors(), cwd, warnings, report.files);
83
89
  if (wants.has("jobs")) report.jobs = await collectJobs(importFromApp, warnings);
84
90
  if (wants.has("schedules")) report.schedules = await collectSchedules(importFromApp, warnings);
85
91
  if (wants.has("packages")) report.packages = collectPackages(cwd);
@@ -1 +1 @@
1
- {"version":3,"file":"inspect-app.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/inspect-app.ts"],"sourcesContent":["import { Application } from \"../../application/application\";\nimport { SchemaRegistry } from \"../../openapi/schema-registry\";\nimport { router } from \"../../router/router\";\nimport type { Route } from \"../../router/types\";\nimport { collectConfig } from \"./collect-config\";\nimport { collectModels, collectResources, type InspectModelModule } from \"./collect-models\";\nimport {\n type AppModuleImporter,\n collectJobs,\n collectPackages,\n collectSchedules,\n createAppModuleImporter,\n readAppPackage,\n} from \"./collect-packages\";\nimport { collectPages, installedPagesFromConnectors } from \"./collect-pages\";\nimport { collectRoutes } from \"./collect-routes\";\nimport { groupListeners, type RecordedListener } from \"./event-recorder\";\nimport {\n INSPECT_SCHEMA_VERSION,\n INSPECT_SECTIONS,\n type InspectReport,\n type InspectSection,\n type InspectWarning,\n} from \"./inspect-report.types\";\n\n/** Inputs of {@link inspectApp}. Every field is optional. */\nexport type InspectOptions = {\n /** Project root. Default: `process.cwd()`. */\n cwd?: string;\n /** The sections to include. Default: all of {@link INSPECT_SECTIONS}. */\n sections?: readonly InspectSection[];\n /** The routes to describe. Default: `router.list()`. */\n routes?: readonly Route[];\n /** Model modules the boot pass imported (their exports are scanned for model classes). */\n modelModules?: readonly InspectModelModule[];\n /** Listeners recorded while app modules were imported (see `EventRecorder`). */\n events?: readonly RecordedListener[];\n /** Warnings found before inspecting (by the boot pass); listed first. */\n warnings?: readonly InspectWarning[];\n /** App modules that failed to import; each becomes a `WL2001` warning. */\n moduleFailures?: readonly { file: string; message: string }[];\n /** The `web` connector's installed pages. Default: read from the registered connectors. */\n pages?: readonly unknown[];\n /**\n * Name a resource class in `components.schemas`, usually by its export name\n * (`PostResource`). Unnamed resources fall back to the class name.\n */\n resolveResourceName?: (resource: unknown) => string | undefined;\n /** The loaded config tree. Default: everything `config` holds. */\n config?: Record<string, unknown>;\n /** How packages are imported as the app resolves them (`@warlock.js/queue`, `/scheduler`). */\n importFromApp?: AppModuleImporter;\n /** Clock, for `generatedAt`. */\n now?: () => Date;\n};\n\n/** Whether a string is a section name. */\nexport function isInspectSection(value: string): value is InspectSection {\n return (INSPECT_SECTIONS as readonly string[]).includes(value);\n}\n\n/**\n * Parse a `--section routes,models` value. Throws on an unknown name, listing\n * the valid ones. An empty value means every section.\n */\nexport function parseInspectSections(value: string | undefined): InspectSection[] {\n if (value === undefined || value.trim() === \"\") return [...INSPECT_SECTIONS];\n\n const requested = value\n .split(\",\")\n .map((name) => name.trim())\n .filter((name) => name.length > 0);\n const unknown = requested.filter((name) => !isInspectSection(name));\n\n if (unknown.length > 0) {\n throw new Error(\n `Unknown inspect section(s): ${unknown.join(\", \")}. Valid sections: ${INSPECT_SECTIONS.join(\", \")}.`,\n );\n }\n\n return INSPECT_SECTIONS.filter((section) => requested.includes(section));\n}\n\n/**\n * Describe the application from its in-process registries: routes, models,\n * resources, config keys, event listeners, pages, queue jobs, scheduled\n * tasks and installed `@warlock.js/*` packages.\n *\n * Reads what is ALREADY registered and boots nothing, so it can run inside a\n * live dev process as well as after the `warlock inspect` boot pass. Never\n * throws for one unreadable item: it becomes an entry in `warnings`.\n *\n * @example\n * const report = await inspectApp({ sections: [\"routes\"] });\n * report.routes?.filter((route) => !route.auth.required && route.method !== \"GET\");\n */\nexport async function inspectApp(options: InspectOptions = {}): Promise<InspectReport> {\n const cwd = options.cwd ?? process.cwd();\n const sections = options.sections ? [...options.sections] : [...INSPECT_SECTIONS];\n const wants = new Set<InspectSection>(sections);\n const warnings: InspectWarning[] = [...(options.warnings ?? [])];\n const registry = new SchemaRegistry(options.resolveResourceName, (message) => {\n warnings.push({ code: null, message, source: \"resources\" });\n });\n const importFromApp = options.importFromApp ?? createAppModuleImporter(cwd);\n\n for (const failure of options.moduleFailures ?? []) {\n warnings.push({\n code: \"WL2001\",\n message: `${failure.file} failed to load: ${failure.message}`,\n source: failure.file,\n });\n }\n\n const app = readAppPackage(cwd);\n const report: InspectReport = {\n schemaVersion: INSPECT_SCHEMA_VERSION,\n generatedAt: (options.now ?? (() => new Date()))().toISOString(),\n app: {\n name: app.name,\n version: app.version,\n root: cwd,\n node: process.version,\n environment: String(Application.environment ?? \"development\"),\n runtimeStrategy: String(Application.runtimeStrategy ?? \"development\"),\n },\n sections: INSPECT_SECTIONS.filter((section) => wants.has(section)),\n components: { schemas: {} },\n warnings,\n };\n\n // Routes and models register the resources they reference, so `resources`\n // (and `components`) are filled from both even when only one is printed.\n const routes = collectRoutes(options.routes ?? router.list(), registry, warnings);\n const { models, resourceModels } = collectModels(options.modelModules ?? [], registry, warnings);\n\n if (wants.has(\"routes\")) report.routes = routes;\n if (wants.has(\"models\")) report.models = models;\n if (wants.has(\"resources\")) report.resources = collectResources(registry, resourceModels);\n if (wants.has(\"config\")) report.config = collectConfig(cwd, options.config);\n if (wants.has(\"events\")) report.events = groupListeners(options.events ?? []);\n\n if (wants.has(\"pages\")) {\n report.pages = collectPages(options.pages ?? installedPagesFromConnectors(), cwd, warnings);\n }\n\n if (wants.has(\"jobs\")) report.jobs = await collectJobs(importFromApp, warnings);\n if (wants.has(\"schedules\")) report.schedules = await collectSchedules(importFromApp, warnings);\n if (wants.has(\"packages\")) report.packages = collectPackages(cwd);\n\n report.components.schemas = registry.schemas;\n\n return report;\n}\n"],"mappings":";;;;;;;;;;;;;AAyDA,SAAgB,iBAAiB,OAAwC;CACvE,OAAQ,iBAAuC,SAAS,KAAK;AAC/D;;;;;AAMA,SAAgB,qBAAqB,OAA6C;CAChF,IAAI,UAAU,UAAa,MAAM,KAAK,MAAM,IAAI,OAAO,CAAC,GAAG,gBAAgB;CAE3E,MAAM,YAAY,MACf,MAAM,GAAG,CAAC,CACV,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAC1B,QAAQ,SAAS,KAAK,SAAS,CAAC;CACnC,MAAM,UAAU,UAAU,QAAQ,SAAS,CAAC,iBAAiB,IAAI,CAAC;CAElE,IAAI,QAAQ,SAAS,GACnB,MAAM,IAAI,MACR,+BAA+B,QAAQ,KAAK,IAAI,EAAE,oBAAoB,iBAAiB,KAAK,IAAI,EAAE,EACpG;CAGF,OAAO,iBAAiB,QAAQ,YAAY,UAAU,SAAS,OAAO,CAAC;AACzE;;;;;;;;;;;;;;AAeA,eAAsB,WAAW,UAA0B,CAAC,GAA2B;CACrF,MAAM,MAAM,QAAQ,OAAO,QAAQ,IAAI;CACvC,MAAM,WAAW,QAAQ,WAAW,CAAC,GAAG,QAAQ,QAAQ,IAAI,CAAC,GAAG,gBAAgB;CAChF,MAAM,QAAQ,IAAI,IAAoB,QAAQ;CAC9C,MAAM,WAA6B,CAAC,GAAI,QAAQ,YAAY,CAAC,CAAE;CAC/D,MAAM,WAAW,IAAI,eAAe,QAAQ,sBAAsB,YAAY;EAC5E,SAAS,KAAK;GAAE,MAAM;GAAM;GAAS,QAAQ;EAAY,CAAC;CAC5D,CAAC;CACD,MAAM,gBAAgB,QAAQ,iBAAiB,wBAAwB,GAAG;CAE1E,KAAK,MAAM,WAAW,QAAQ,kBAAkB,CAAC,GAC/C,SAAS,KAAK;EACZ,MAAM;EACN,SAAS,GAAG,QAAQ,KAAK,mBAAmB,QAAQ;EACpD,QAAQ,QAAQ;CAClB,CAAC;CAGH,MAAM,MAAM,eAAe,GAAG;CAC9B,MAAM,SAAwB;EAC5B;EACA,cAAc,QAAQ,8BAAc,IAAI,KAAK,GAAE,CAAE,CAAC,CAAC,YAAY;EAC/D,KAAK;GACH,MAAM,IAAI;GACV,SAAS,IAAI;GACb,MAAM;GACN,MAAM,QAAQ;GACd,aAAa,OAAO,YAAY,eAAe,aAAa;GAC5D,iBAAiB,OAAO,YAAY,mBAAmB,aAAa;EACtE;EACA,UAAU,iBAAiB,QAAQ,YAAY,MAAM,IAAI,OAAO,CAAC;EACjE,YAAY,EAAE,SAAS,CAAC,EAAE;EAC1B;CACF;CAIA,MAAM,SAAS,cAAc,QAAQ,UAAU,OAAO,KAAK,GAAG,UAAU,QAAQ;CAChF,MAAM,EAAE,QAAQ,mBAAmB,cAAc,QAAQ,gBAAgB,CAAC,GAAG,UAAU,QAAQ;CAE/F,IAAI,MAAM,IAAI,QAAQ,GAAG,OAAO,SAAS;CACzC,IAAI,MAAM,IAAI,QAAQ,GAAG,OAAO,SAAS;CACzC,IAAI,MAAM,IAAI,WAAW,GAAG,OAAO,YAAY,iBAAiB,UAAU,cAAc;CACxF,IAAI,MAAM,IAAI,QAAQ,GAAG,OAAO,SAAS,cAAc,KAAK,QAAQ,MAAM;CAC1E,IAAI,MAAM,IAAI,QAAQ,GAAG,OAAO,SAAS,eAAe,QAAQ,UAAU,CAAC,CAAC;CAE5E,IAAI,MAAM,IAAI,OAAO,GACnB,OAAO,QAAQ,aAAa,QAAQ,SAAS,6BAA6B,GAAG,KAAK,QAAQ;CAG5F,IAAI,MAAM,IAAI,MAAM,GAAG,OAAO,OAAO,MAAM,YAAY,eAAe,QAAQ;CAC9E,IAAI,MAAM,IAAI,WAAW,GAAG,OAAO,YAAY,MAAM,iBAAiB,eAAe,QAAQ;CAC7F,IAAI,MAAM,IAAI,UAAU,GAAG,OAAO,WAAW,gBAAgB,GAAG;CAEhE,OAAO,WAAW,UAAU,SAAS;CAErC,OAAO;AACT"}
1
+ {"version":3,"file":"inspect-app.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/inspect-app.ts"],"sourcesContent":["import { Application } from \"../../application/application\";\nimport { SchemaRegistry } from \"../../openapi/schema-registry\";\nimport { router } from \"../../router/router\";\nimport type { Route } from \"../../router/types\";\nimport { collectFiles } from \"./collect-files\";\nimport { collectConfig } from \"./collect-config\";\nimport { collectModels, collectResources, type InspectModelModule } from \"./collect-models\";\nimport {\n type AppModuleImporter,\n collectJobs,\n collectPackages,\n collectSchedules,\n createAppModuleImporter,\n readAppPackage,\n} from \"./collect-packages\";\nimport { collectPages, installedPagesFromConnectors } from \"./collect-pages\";\nimport { collectRoutes } from \"./collect-routes\";\nimport { groupListeners, type RecordedListener } from \"./event-recorder\";\nimport {\n INSPECT_SCHEMA_VERSION,\n INSPECT_SECTIONS,\n type InspectReport,\n type InspectSection,\n type InspectWarning,\n} from \"./inspect-report.types\";\n\n/** Inputs of {@link inspectApp}. Every field is optional. */\nexport type InspectOptions = {\n /** Project root. Default: `process.cwd()`. */\n cwd?: string;\n /** The sections to include. Default: all of {@link INSPECT_SECTIONS}. */\n sections?: readonly InspectSection[];\n /** The routes to describe. Default: `router.list()`. */\n routes?: readonly Route[];\n /** Model modules the boot pass imported (their exports are scanned for model classes). */\n modelModules?: readonly InspectModelModule[];\n /** Listeners recorded while app modules were imported (see `EventRecorder`). */\n events?: readonly RecordedListener[];\n /** Warnings found before inspecting (by the boot pass); listed first. */\n warnings?: readonly InspectWarning[];\n /** App modules that failed to import; each becomes a `WL2001` warning. */\n moduleFailures?: readonly { file: string; message: string }[];\n /** The `web` connector's installed pages. Default: read from the registered connectors. */\n pages?: readonly unknown[];\n /**\n * Name a resource class in `components.schemas`, usually by its export name\n * (`PostResource`). Unnamed resources fall back to the class name.\n */\n resolveResourceName?: (resource: unknown) => string | undefined;\n /** The loaded config tree. Default: everything `config` holds. */\n config?: Record<string, unknown>;\n /** How packages are imported as the app resolves them (`@warlock.js/queue`, `/scheduler`). */\n importFromApp?: AppModuleImporter;\n /** Clock, for `generatedAt`. */\n now?: () => Date;\n};\n\n/** Whether a string is a section name. */\nexport function isInspectSection(value: string): value is InspectSection {\n return (INSPECT_SECTIONS as readonly string[]).includes(value);\n}\n\n/**\n * Parse a `--section routes,models` value. Throws on an unknown name, listing\n * the valid ones. An empty value means every section.\n */\nexport function parseInspectSections(value: string | undefined): InspectSection[] {\n if (value === undefined || value.trim() === \"\") return [...INSPECT_SECTIONS];\n\n const requested = value\n .split(\",\")\n .map((name) => name.trim())\n .filter((name) => name.length > 0);\n const unknown = requested.filter((name) => !isInspectSection(name));\n\n if (unknown.length > 0) {\n throw new Error(\n `Unknown inspect section(s): ${unknown.join(\", \")}. Valid sections: ${INSPECT_SECTIONS.join(\", \")}.`,\n );\n }\n\n return INSPECT_SECTIONS.filter((section) => requested.includes(section));\n}\n\n/**\n * Describe the application from its in-process registries: routes, models,\n * resources, config keys, event listeners, pages, queue jobs, scheduled\n * tasks and installed `@warlock.js/*` packages.\n *\n * Reads what is ALREADY registered and boots nothing, so it can run inside a\n * live dev process as well as after the `warlock inspect` boot pass. Never\n * throws for one unreadable item: it becomes an entry in `warnings`.\n *\n * @example\n * const report = await inspectApp({ sections: [\"routes\"] });\n * report.routes?.filter((route) => !route.auth.required && route.method !== \"GET\");\n */\nexport async function inspectApp(options: InspectOptions = {}): Promise<InspectReport> {\n const cwd = options.cwd ?? process.cwd();\n const sections = options.sections ? [...options.sections] : [...INSPECT_SECTIONS];\n const wants = new Set<InspectSection>(sections);\n const warnings: InspectWarning[] = [...(options.warnings ?? [])];\n const registry = new SchemaRegistry(options.resolveResourceName, (message) => {\n warnings.push({ code: null, message, source: \"resources\" });\n });\n const importFromApp = options.importFromApp ?? createAppModuleImporter(cwd);\n\n for (const failure of options.moduleFailures ?? []) {\n warnings.push({\n code: \"WL2001\",\n message: `${failure.file} failed to load: ${failure.message}`,\n source: failure.file,\n });\n }\n\n const app = readAppPackage(cwd);\n const report: InspectReport = {\n schemaVersion: INSPECT_SCHEMA_VERSION,\n generatedAt: (options.now ?? (() => new Date()))().toISOString(),\n app: {\n name: app.name,\n version: app.version,\n root: cwd,\n node: process.version,\n environment: String(Application.environment ?? \"development\"),\n runtimeStrategy: String(Application.runtimeStrategy ?? \"development\"),\n },\n sections: INSPECT_SECTIONS.filter((section) => wants.has(section)),\n components: { schemas: {} },\n warnings,\n };\n\n // Routes and models register the resources they reference, so `resources`\n // (and `components`) are filled from both even when only one is printed.\n const filesOnly = sections.every((section) => section === \"files\");\n const routes = !filesOnly\n ? collectRoutes(options.routes ?? router.list(), registry, warnings)\n : [];\n const { models, resourceModels } = !filesOnly\n ? collectModels(options.modelModules ?? [], registry, warnings)\n : { models: [], resourceModels: new Map<string, string[]>() };\n\n if (wants.has(\"files\")) report.files = collectFiles(cwd, warnings);\n\n if (wants.has(\"routes\")) report.routes = routes;\n if (wants.has(\"models\")) report.models = models;\n if (wants.has(\"resources\")) report.resources = collectResources(registry, resourceModels);\n if (wants.has(\"config\")) report.config = collectConfig(cwd, options.config);\n if (wants.has(\"events\")) report.events = groupListeners(options.events ?? []);\n\n if (wants.has(\"pages\")) {\n report.pages = collectPages(\n options.pages ?? installedPagesFromConnectors(),\n cwd,\n warnings,\n report.files,\n );\n }\n\n if (wants.has(\"jobs\")) report.jobs = await collectJobs(importFromApp, warnings);\n if (wants.has(\"schedules\")) report.schedules = await collectSchedules(importFromApp, warnings);\n if (wants.has(\"packages\")) report.packages = collectPackages(cwd);\n\n report.components.schemas = registry.schemas;\n\n return report;\n}\n"],"mappings":"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"}
@@ -404,7 +404,8 @@ const INSPECT_REPORT_JSON_SCHEMA = {
404
404
  "pages",
405
405
  "jobs",
406
406
  "schedules",
407
- "packages"
407
+ "packages",
408
+ "files"
408
409
  ] }
409
410
  },
410
411
  routes: {
@@ -443,6 +444,38 @@ const INSPECT_REPORT_JSON_SCHEMA = {
443
444
  type: "array",
444
445
  items: installedPackage
445
446
  },
447
+ files: {
448
+ type: "array",
449
+ items: {
450
+ type: "object",
451
+ required: [
452
+ "file",
453
+ "module",
454
+ "role",
455
+ "exports",
456
+ "imports",
457
+ "importedBy"
458
+ ],
459
+ properties: {
460
+ file: { type: "string" },
461
+ module: { type: "string" },
462
+ role: { type: "string" },
463
+ exports: stringArray,
464
+ importedBy: stringArray,
465
+ imports: {
466
+ type: "array",
467
+ items: {
468
+ type: "object",
469
+ required: ["specifier", "file"],
470
+ properties: {
471
+ specifier: { type: "string" },
472
+ file: nullableString
473
+ }
474
+ }
475
+ }
476
+ }
477
+ }
478
+ },
446
479
  components: {
447
480
  type: "object",
448
481
  required: ["schemas"],
@@ -1 +1 @@
1
- {"version":3,"file":"inspect-report.schema.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/inspect-report.schema.ts"],"sourcesContent":["/**\n * JSON Schema (draft 2020-12) of the `warlock inspect` report, schema version 1.\n *\n * Shipped twice: as this constant, and as\n * `@warlock.js/core/schemas/inspect-report.schema.json` for tools that are not\n * JavaScript. A test keeps the two identical. Objects allow additional\n * properties on purpose: within schema version 1 fields are only added, and a\n * validator written today must accept tomorrow's reports.\n */\n\nconst nullableString = { type: [\"string\", \"null\"] };\nconst stringArray = { type: \"array\", items: { type: \"string\" } };\nconst jsonSchema = { type: \"object\" };\n\nconst authSource = {\n oneOf: [\n { const: \"header\" },\n {\n type: \"object\",\n required: [\"cookie\"],\n properties: { cookie: { type: \"string\" } },\n },\n ],\n};\n\nconst route = {\n type: \"object\",\n required: [\n \"method\",\n \"path\",\n \"name\",\n \"sourceFile\",\n \"handler\",\n \"description\",\n \"isPage\",\n \"middleware\",\n \"auth\",\n \"csrf\",\n \"rateLimit\",\n \"logging\",\n \"request\",\n \"responses\",\n ],\n properties: {\n method: { type: \"string\" },\n path: { type: \"string\" },\n name: nullableString,\n sourceFile: nullableString,\n handler: { type: \"string\" },\n description: nullableString,\n isPage: { type: \"boolean\" },\n middleware: stringArray,\n auth: {\n type: \"object\",\n required: [\"required\", \"sources\", \"userTypes\"],\n properties: {\n required: { type: \"boolean\" },\n sources: { type: \"array\", items: authSource },\n userTypes: stringArray,\n },\n },\n csrf: { type: \"boolean\" },\n rateLimit: {\n type: \"object\",\n required: [\"source\", \"max\", \"timeWindow\"],\n properties: {\n source: { enum: [\"route\", \"global\", \"none\"] },\n max: { oneOf: [{ type: \"number\" }, { const: \"dynamic\" }, { type: \"null\" }] },\n timeWindow: { type: [\"number\", \"string\", \"null\"] },\n },\n },\n logging: {\n type: \"object\",\n required: [\"body\", \"query\", \"privateRules\"],\n properties: {\n body: { type: \"boolean\" },\n query: { type: \"boolean\" },\n privateRules: { type: \"boolean\" },\n },\n },\n request: {\n type: \"object\",\n required: [\"parameters\", \"body\", \"customValidation\"],\n properties: {\n parameters: {\n type: \"array\",\n items: {\n type: \"object\",\n required: [\"name\", \"in\", \"required\", \"schema\"],\n properties: {\n name: { type: \"string\" },\n in: { enum: [\"path\", \"query\", \"header\", \"cookie\"] },\n required: { type: \"boolean\" },\n schema: jsonSchema,\n },\n },\n },\n body: { type: [\"object\", \"null\"] },\n customValidation: { type: \"boolean\" },\n },\n },\n responses: {\n type: \"object\",\n additionalProperties: {\n type: \"object\",\n required: [\"description\", \"schema\"],\n properties: {\n description: { type: \"string\" },\n schema: { type: [\"object\", \"null\"] },\n },\n },\n },\n },\n};\n\nconst model = {\n type: \"object\",\n required: [\n \"name\",\n \"table\",\n \"primaryKey\",\n \"dataSource\",\n \"sourceFile\",\n \"registered\",\n \"columns\",\n \"relations\",\n \"resource\",\n \"deleteStrategy\",\n \"createdAtColumn\",\n \"updatedAtColumn\",\n \"deletedAtColumn\",\n ],\n properties: {\n name: { type: \"string\" },\n table: nullableString,\n primaryKey: nullableString,\n dataSource: nullableString,\n sourceFile: nullableString,\n registered: { type: \"boolean\" },\n columns: {\n type: \"array\",\n items: {\n type: \"object\",\n required: [\"name\", \"required\", \"schema\"],\n properties: {\n name: { type: \"string\" },\n required: { type: \"boolean\" },\n schema: jsonSchema,\n },\n },\n },\n relations: {\n type: \"array\",\n items: {\n type: \"object\",\n required: [\"name\", \"type\", \"model\", \"foreignKey\", \"localKey\"],\n properties: {\n name: { type: \"string\" },\n type: { type: \"string\" },\n model: nullableString,\n foreignKey: nullableString,\n localKey: nullableString,\n },\n },\n },\n resource: nullableString,\n deleteStrategy: nullableString,\n createdAtColumn: nullableString,\n updatedAtColumn: nullableString,\n deletedAtColumn: nullableString,\n },\n};\n\nconst resource = {\n type: \"object\",\n required: [\"name\", \"schema\", \"models\"],\n properties: {\n name: { type: \"string\" },\n schema: jsonSchema,\n models: stringArray,\n },\n};\n\nconst configKey = {\n type: \"object\",\n required: [\"key\", \"type\", \"file\"],\n properties: {\n key: { type: \"string\" },\n type: { type: \"string\" },\n file: nullableString,\n },\n};\n\nconst event = {\n type: \"object\",\n required: [\"event\", \"listeners\"],\n properties: {\n event: { type: \"string\" },\n listeners: {\n type: \"array\",\n items: {\n type: \"object\",\n required: [\"name\", \"sourceFile\"],\n properties: { name: { type: \"string\" }, sourceFile: { type: \"string\" } },\n },\n },\n },\n};\n\nconst page = {\n type: \"object\",\n required: [\"path\", \"name\", \"file\", \"layouts\", \"loaders\", \"actions\", \"guard\"],\n properties: {\n path: { type: \"string\" },\n name: nullableString,\n file: { type: \"string\" },\n layouts: stringArray,\n loaders: stringArray,\n actions: stringArray,\n guard: nullableString,\n },\n};\n\nconst job = {\n type: \"object\",\n required: [\"name\", \"queue\", \"attempts\", \"backoff\", \"removeOnComplete\", \"removeOnFail\"],\n properties: {\n name: { type: \"string\" },\n queue: { type: \"string\" },\n attempts: { type: [\"number\", \"null\"] },\n backoff: {\n oneOf: [\n { type: \"number\" },\n { type: \"null\" },\n {\n type: \"object\",\n required: [\"type\", \"delay\"],\n properties: { type: { type: \"string\" }, delay: { type: \"number\" } },\n },\n ],\n },\n removeOnComplete: { type: [\"boolean\", \"number\", \"null\"] },\n removeOnFail: { type: [\"boolean\", \"number\", \"null\"] },\n },\n};\n\nconst schedule = {\n type: \"object\",\n required: [\"name\", \"cron\", \"intervals\", \"nextRun\"],\n properties: {\n name: { type: \"string\" },\n cron: nullableString,\n intervals: { type: \"object\" },\n nextRun: nullableString,\n },\n};\n\nconst installedPackage = {\n type: \"object\",\n required: [\"name\", \"version\"],\n properties: { name: { type: \"string\" }, version: { type: \"string\" } },\n};\n\nconst warning = {\n type: \"object\",\n required: [\"code\", \"message\", \"source\"],\n properties: {\n code: { oneOf: [{ type: \"string\", pattern: \"^WL[0-9]{4}$\" }, { type: \"null\" }] },\n message: { type: \"string\" },\n source: nullableString,\n },\n};\n\n/** The report's JSON Schema, draft 2020-12. */\nexport const INSPECT_REPORT_JSON_SCHEMA: Record<string, unknown> = {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n title: \"Warlock inspect report\",\n description: \"Output of `warlock inspect --json`, schema version 1.\",\n type: \"object\",\n required: [\"schemaVersion\", \"generatedAt\", \"app\", \"sections\", \"components\", \"warnings\"],\n properties: {\n schemaVersion: { const: 1 },\n generatedAt: { type: \"string\" },\n app: {\n type: \"object\",\n required: [\"name\", \"version\", \"root\", \"node\", \"environment\", \"runtimeStrategy\"],\n properties: {\n name: nullableString,\n version: nullableString,\n root: { type: \"string\" },\n node: { type: \"string\" },\n environment: { type: \"string\" },\n runtimeStrategy: { type: \"string\" },\n },\n },\n sections: {\n type: \"array\",\n items: {\n enum: [\n \"routes\",\n \"models\",\n \"resources\",\n \"config\",\n \"events\",\n \"pages\",\n \"jobs\",\n \"schedules\",\n \"packages\",\n ],\n },\n },\n routes: { type: \"array\", items: route },\n models: { type: \"array\", items: model },\n resources: { type: \"array\", items: resource },\n config: { type: \"array\", items: configKey },\n events: { type: \"array\", items: event },\n pages: { type: \"array\", items: page },\n jobs: { type: \"array\", items: job },\n schedules: { type: \"array\", items: schedule },\n packages: { type: \"array\", items: installedPackage },\n components: {\n type: \"object\",\n required: [\"schemas\"],\n properties: {\n schemas: { type: \"object\", additionalProperties: jsonSchema },\n },\n },\n warnings: { type: \"array\", items: warning },\n },\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"inspect-report.schema.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/inspect-report.schema.ts"],"sourcesContent":["/**\n * JSON Schema (draft 2020-12) of the `warlock inspect` report, schema version 1.\n *\n * Shipped twice: as this constant, and as\n * `@warlock.js/core/schemas/inspect-report.schema.json` for tools that are not\n * JavaScript. A test keeps the two identical. Objects allow additional\n * properties on purpose: within schema version 1 fields are only added, and a\n * validator written today must accept tomorrow's reports.\n */\n\nconst nullableString = { type: [\"string\", \"null\"] };\nconst stringArray = { type: \"array\", items: { type: \"string\" } };\nconst jsonSchema = { type: \"object\" };\n\nconst authSource = {\n oneOf: [\n { const: \"header\" },\n {\n type: \"object\",\n required: [\"cookie\"],\n properties: { cookie: { type: \"string\" } },\n },\n ],\n};\n\nconst route = {\n type: \"object\",\n required: [\n \"method\",\n \"path\",\n \"name\",\n \"sourceFile\",\n \"handler\",\n \"description\",\n \"isPage\",\n \"middleware\",\n \"auth\",\n \"csrf\",\n \"rateLimit\",\n \"logging\",\n \"request\",\n \"responses\",\n ],\n properties: {\n method: { type: \"string\" },\n path: { type: \"string\" },\n name: nullableString,\n sourceFile: nullableString,\n handler: { type: \"string\" },\n description: nullableString,\n isPage: { type: \"boolean\" },\n middleware: stringArray,\n auth: {\n type: \"object\",\n required: [\"required\", \"sources\", \"userTypes\"],\n properties: {\n required: { type: \"boolean\" },\n sources: { type: \"array\", items: authSource },\n userTypes: stringArray,\n },\n },\n csrf: { type: \"boolean\" },\n rateLimit: {\n type: \"object\",\n required: [\"source\", \"max\", \"timeWindow\"],\n properties: {\n source: { enum: [\"route\", \"global\", \"none\"] },\n max: { oneOf: [{ type: \"number\" }, { const: \"dynamic\" }, { type: \"null\" }] },\n timeWindow: { type: [\"number\", \"string\", \"null\"] },\n },\n },\n logging: {\n type: \"object\",\n required: [\"body\", \"query\", \"privateRules\"],\n properties: {\n body: { type: \"boolean\" },\n query: { type: \"boolean\" },\n privateRules: { type: \"boolean\" },\n },\n },\n request: {\n type: \"object\",\n required: [\"parameters\", \"body\", \"customValidation\"],\n properties: {\n parameters: {\n type: \"array\",\n items: {\n type: \"object\",\n required: [\"name\", \"in\", \"required\", \"schema\"],\n properties: {\n name: { type: \"string\" },\n in: { enum: [\"path\", \"query\", \"header\", \"cookie\"] },\n required: { type: \"boolean\" },\n schema: jsonSchema,\n },\n },\n },\n body: { type: [\"object\", \"null\"] },\n customValidation: { type: \"boolean\" },\n },\n },\n responses: {\n type: \"object\",\n additionalProperties: {\n type: \"object\",\n required: [\"description\", \"schema\"],\n properties: {\n description: { type: \"string\" },\n schema: { type: [\"object\", \"null\"] },\n },\n },\n },\n },\n};\n\nconst model = {\n type: \"object\",\n required: [\n \"name\",\n \"table\",\n \"primaryKey\",\n \"dataSource\",\n \"sourceFile\",\n \"registered\",\n \"columns\",\n \"relations\",\n \"resource\",\n \"deleteStrategy\",\n \"createdAtColumn\",\n \"updatedAtColumn\",\n \"deletedAtColumn\",\n ],\n properties: {\n name: { type: \"string\" },\n table: nullableString,\n primaryKey: nullableString,\n dataSource: nullableString,\n sourceFile: nullableString,\n registered: { type: \"boolean\" },\n columns: {\n type: \"array\",\n items: {\n type: \"object\",\n required: [\"name\", \"required\", \"schema\"],\n properties: {\n name: { type: \"string\" },\n required: { type: \"boolean\" },\n schema: jsonSchema,\n },\n },\n },\n relations: {\n type: \"array\",\n items: {\n type: \"object\",\n required: [\"name\", \"type\", \"model\", \"foreignKey\", \"localKey\"],\n properties: {\n name: { type: \"string\" },\n type: { type: \"string\" },\n model: nullableString,\n foreignKey: nullableString,\n localKey: nullableString,\n },\n },\n },\n resource: nullableString,\n deleteStrategy: nullableString,\n createdAtColumn: nullableString,\n updatedAtColumn: nullableString,\n deletedAtColumn: nullableString,\n },\n};\n\nconst resource = {\n type: \"object\",\n required: [\"name\", \"schema\", \"models\"],\n properties: {\n name: { type: \"string\" },\n schema: jsonSchema,\n models: stringArray,\n },\n};\n\nconst configKey = {\n type: \"object\",\n required: [\"key\", \"type\", \"file\"],\n properties: {\n key: { type: \"string\" },\n type: { type: \"string\" },\n file: nullableString,\n },\n};\n\nconst event = {\n type: \"object\",\n required: [\"event\", \"listeners\"],\n properties: {\n event: { type: \"string\" },\n listeners: {\n type: \"array\",\n items: {\n type: \"object\",\n required: [\"name\", \"sourceFile\"],\n properties: { name: { type: \"string\" }, sourceFile: { type: \"string\" } },\n },\n },\n },\n};\n\nconst page = {\n type: \"object\",\n required: [\"path\", \"name\", \"file\", \"layouts\", \"loaders\", \"actions\", \"guard\"],\n properties: {\n path: { type: \"string\" },\n name: nullableString,\n file: { type: \"string\" },\n layouts: stringArray,\n loaders: stringArray,\n actions: stringArray,\n guard: nullableString,\n },\n};\n\nconst job = {\n type: \"object\",\n required: [\"name\", \"queue\", \"attempts\", \"backoff\", \"removeOnComplete\", \"removeOnFail\"],\n properties: {\n name: { type: \"string\" },\n queue: { type: \"string\" },\n attempts: { type: [\"number\", \"null\"] },\n backoff: {\n oneOf: [\n { type: \"number\" },\n { type: \"null\" },\n {\n type: \"object\",\n required: [\"type\", \"delay\"],\n properties: { type: { type: \"string\" }, delay: { type: \"number\" } },\n },\n ],\n },\n removeOnComplete: { type: [\"boolean\", \"number\", \"null\"] },\n removeOnFail: { type: [\"boolean\", \"number\", \"null\"] },\n },\n};\n\nconst schedule = {\n type: \"object\",\n required: [\"name\", \"cron\", \"intervals\", \"nextRun\"],\n properties: {\n name: { type: \"string\" },\n cron: nullableString,\n intervals: { type: \"object\" },\n nextRun: nullableString,\n },\n};\n\nconst installedPackage = {\n type: \"object\",\n required: [\"name\", \"version\"],\n properties: { name: { type: \"string\" }, version: { type: \"string\" } },\n};\n\nconst warning = {\n type: \"object\",\n required: [\"code\", \"message\", \"source\"],\n properties: {\n code: { oneOf: [{ type: \"string\", pattern: \"^WL[0-9]{4}$\" }, { type: \"null\" }] },\n message: { type: \"string\" },\n source: nullableString,\n },\n};\n\n/** The report's JSON Schema, draft 2020-12. */\nexport const INSPECT_REPORT_JSON_SCHEMA: Record<string, unknown> = {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n title: \"Warlock inspect report\",\n description: \"Output of `warlock inspect --json`, schema version 1.\",\n type: \"object\",\n required: [\"schemaVersion\", \"generatedAt\", \"app\", \"sections\", \"components\", \"warnings\"],\n properties: {\n schemaVersion: { const: 1 },\n generatedAt: { type: \"string\" },\n app: {\n type: \"object\",\n required: [\"name\", \"version\", \"root\", \"node\", \"environment\", \"runtimeStrategy\"],\n properties: {\n name: nullableString,\n version: nullableString,\n root: { type: \"string\" },\n node: { type: \"string\" },\n environment: { type: \"string\" },\n runtimeStrategy: { type: \"string\" },\n },\n },\n sections: {\n type: \"array\",\n items: {\n enum: [\n \"routes\",\n \"models\",\n \"resources\",\n \"config\",\n \"events\",\n \"pages\",\n \"jobs\",\n \"schedules\",\n \"packages\",\n \"files\",\n ],\n },\n },\n routes: { type: \"array\", items: route },\n models: { type: \"array\", items: model },\n resources: { type: \"array\", items: resource },\n config: { type: \"array\", items: configKey },\n events: { type: \"array\", items: event },\n pages: { type: \"array\", items: page },\n jobs: { type: \"array\", items: job },\n schedules: { type: \"array\", items: schedule },\n packages: { type: \"array\", items: installedPackage },\n files: {\n type: \"array\",\n items: {\n type: \"object\",\n required: [\"file\", \"module\", \"role\", \"exports\", \"imports\", \"importedBy\"],\n properties: {\n file: { type: \"string\" },\n module: { type: \"string\" },\n role: { type: \"string\" },\n exports: stringArray,\n importedBy: stringArray,\n imports: {\n type: \"array\",\n items: {\n type: \"object\",\n required: [\"specifier\", \"file\"],\n properties: { specifier: { type: \"string\" }, file: nullableString },\n },\n },\n },\n },\n },\n components: {\n type: \"object\",\n required: [\"schemas\"],\n properties: {\n schemas: { type: \"object\", additionalProperties: jsonSchema },\n },\n },\n warnings: { type: \"array\", items: warning },\n },\n};\n"],"mappings":"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"}
@@ -17,7 +17,7 @@ import { WarlockErrorCode } from "../../errors/error-codes.mjs";
17
17
  /** The version of the report shape. Bumped only for a breaking change. */
18
18
  export declare const INSPECT_SCHEMA_VERSION = 1;
19
19
  /** Every section the report can contain, in output order. */
20
- export declare const INSPECT_SECTIONS: readonly ["routes", "models", "resources", "config", "events", "pages", "jobs", "schedules", "packages"];
20
+ export declare const INSPECT_SECTIONS: readonly ["routes", "models", "resources", "config", "events", "pages", "jobs", "schedules", "packages", "files"];
21
21
  /** One section name. */
22
22
  export type InspectSection = (typeof INSPECT_SECTIONS)[number];
23
23
  /** A JSON Schema (draft 2020-12) fragment. */
@@ -218,11 +218,27 @@ export type InspectReport = {
218
218
  jobs?: InspectJob[];
219
219
  schedules?: InspectSchedule[];
220
220
  packages?: InspectPackage[];
221
+ files?: InspectFile[];
221
222
  /** Shared schemas that `$ref`s point at (`#/components/schemas/<name>`). */
222
223
  components: {
223
224
  schemas: Record<string, JsonSchema>;
224
225
  };
225
226
  warnings: InspectWarning[];
226
227
  };
228
+ /** A source file and its static module graph, with project-relative paths. */
229
+ export type InspectFile = {
230
+ file: string;
231
+ /** src/app/<module>, or the containing top-level src directory. */
232
+ module: string;
233
+ role: string;
234
+ /** Public export names; default and * represent default and star exports. */
235
+ exports: string[];
236
+ /** Literal imports and re-exports; null means external or unresolved. */
237
+ imports: {
238
+ specifier: string;
239
+ file: string | null;
240
+ }[];
241
+ importedBy: string[];
242
+ };
227
243
  //#endregion
228
244
  //# sourceMappingURL=inspect-report.types.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"inspect-report.types.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/inspect-report.types.ts"],"mappings":";;;;;;;;;;;;;;;;;qBAkBa;;qBAGA;;YAaD,yBAAyB;;YAGzB,aAAa;;YAGb;;EAEV;;EAEA;IAAuB;;;EAEvB;;;YAIU;;EAEV;;EAEA;;EAEA;;;YAIU;;EAEV;;EAEA;;EAEA;;;YAIU;EACV;EACA;EACA;EACA,QAAQ;;;YAIE;;EAEV;EACA;EACA;;EAEA;;EAEA;EACA;;EAEA;;EAEA;EACA,MAAM;;EAEN;EACA,WAAW;EACX,SAAS;EACT;IACE,YAAY;;IAEZ,MAAM;;IAEN;;;EAGF,WAAW;IAAiB;IAAqB,QAAQ;;;;YAI/C;EACV;EACA;EACA,QAAQ;;;YAIE;EACV;EACA;;EAEA;EACA;EACA;;;YAIU;EACV;EACA;EACA;;EAEA;EACA;;EAEA;EACA,SAAS;EACT,WAAW;;EAEX;EACA;EACA;EACA;EACA;;;YAIU;EACV;;EAEA,QAAQ;;EAER;;;YAIU;EACV;;EAEA;;EAEA;;;YAIU;EACV;EACA;IAAa;IAAc;;;;YAIjB;EACV;EACA;EACA;;EAEA;;EAEA;;EAEA;;EAEA;;;YAIU;EACV;EACA;EACA;EACA;IAAoB;IAAc;;EAClC;EACA;;;YAIU;EACV;EACA;EACA,WAAW;EACX;;;YAIU;EACV;EACA;;;YAIU;EACV,MAAM;EACN;;EAEA;;;YAIU;EACV,sBAAsB;EACtB;EACA;IACE;IACA;;IAEA;IACA;IACA;IACA;;;EAGF,UAAU;EACV,SAAS;EACT,SAAS;EACT,YAAY;EACZ,SAAS;EACT,SAAS;EACT,QAAQ;EACR,OAAO;EACP,YAAY;EACZ,WAAW;;EAEX;IAAc,SAAS,eAAe;;EACtC,UAAU"}
1
+ {"version":3,"file":"inspect-report.types.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/inspect-report.types.ts"],"mappings":";;;;;;;;;;;;;;;;;qBAkBa;;qBAGA;;YAcD,yBAAyB;;YAGzB,aAAa;;YAGb;;EAEV;;EAEA;IAAuB;;;EAEvB;;;YAIU;;EAEV;;EAEA;;EAEA;;;YAIU;;EAEV;;EAEA;;EAEA;;;YAIU;EACV;EACA;EACA;EACA,QAAQ;;;YAIE;;EAEV;EACA;EACA;;EAEA;;EAEA;EACA;;EAEA;;EAEA;EACA,MAAM;;EAEN;EACA,WAAW;EACX,SAAS;EACT;IACE,YAAY;;IAEZ,MAAM;;IAEN;;;EAGF,WAAW;IAAiB;IAAqB,QAAQ;;;;YAI/C;EACV;EACA;EACA,QAAQ;;;YAIE;EACV;EACA;;EAEA;EACA;EACA;;;YAIU;EACV;EACA;EACA;;EAEA;EACA;;EAEA;EACA,SAAS;EACT,WAAW;;EAEX;EACA;EACA;EACA;EACA;;;YAIU;EACV;;EAEA,QAAQ;;EAER;;;YAIU;EACV;;EAEA;;EAEA;;;YAIU;EACV;EACA;IAAa;IAAc;;;;YAIjB;EACV;EACA;EACA;;EAEA;;EAEA;;EAEA;;EAEA;;;YAIU;EACV;EACA;EACA;EACA;IAAoB;IAAc;;EAClC;EACA;;;YAIU;EACV;EACA;EACA,WAAW;EACX;;;YAIU;EACV;EACA;;;YAIU;EACV,MAAM;EACN;;EAEA;;;YAIU;EACV,sBAAsB;EACtB;EACA;IACE;IACA;;IAEA;IACA;IACA;IACA;;;EAGF,UAAU;EACV,SAAS;EACT,SAAS;EACT,YAAY;EACZ,SAAS;EACT,SAAS;EACT,QAAQ;EACR,OAAO;EACP,YAAY;EACZ,WAAW;EACX,QAAQ;;EAER;IAAc,SAAS,eAAe;;EACtC,UAAU;;;YAIA;EACV;;EAEA;EACA;;EAEA;;EAEA;IAAW;IAAmB;;EAC9B"}
@@ -25,7 +25,8 @@ const INSPECT_SECTIONS = [
25
25
  "pages",
26
26
  "jobs",
27
27
  "schedules",
28
- "packages"
28
+ "packages",
29
+ "files"
29
30
  ];
30
31
 
31
32
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"inspect-report.types.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/inspect-report.types.ts"],"sourcesContent":["import type { WarlockErrorCode } from \"../../errors/error-codes\";\n\n/**\n * @fileoverview The `warlock inspect` report, schema version 1.\n *\n * STABILITY: within `schemaVersion: 1` fields are only ever ADDED. No field is\n * removed, renamed or retyped, so a consumer written against this file keeps\n * working on every later 5.x release. Consumers must ignore keys they do not\n * know. A change that breaks that promise ships as `schemaVersion: 2` and is\n * listed under BREAKING in the changelog. Free text (warning messages,\n * descriptions) is not part of the contract.\n *\n * The same shape is published as JSON Schema (draft 2020-12) in\n * `@warlock.js/core/schemas/inspect-report.schema.json` and as the\n * `INSPECT_REPORT_JSON_SCHEMA` constant.\n */\n\n/** The version of the report shape. Bumped only for a breaking change. */\nexport const INSPECT_SCHEMA_VERSION = 1;\n\n/** Every section the report can contain, in output order. */\nexport const INSPECT_SECTIONS = [\n \"routes\",\n \"models\",\n \"resources\",\n \"config\",\n \"events\",\n \"pages\",\n \"jobs\",\n \"schedules\",\n \"packages\",\n] as const;\n\n/** One section name. */\nexport type InspectSection = (typeof INSPECT_SECTIONS)[number];\n\n/** A JSON Schema (draft 2020-12) fragment. */\nexport type JsonSchema = Record<string, unknown>;\n\n/** Who guards a route, from the descriptor `authMiddleware()` attaches. */\nexport type InspectRouteAuth = {\n /** Whether an auth guard runs on the route. */\n required: boolean;\n /** Where the token is read: `\"header\"` (bearer) or `{ cookie }`. */\n sources: (\"header\" | { cookie: string })[];\n /** User types the guard accepts; empty means any. */\n userTypes: string[];\n};\n\n/** The rate limit a route runs under. */\nexport type InspectRouteRateLimit = {\n /** `route` = the route's own option, `global` = `http.rateLimit`, `none` = no limiter. */\n source: \"route\" | \"global\" | \"none\";\n /** Max requests per window; `\"dynamic\"` when configured as a function. */\n max: number | \"dynamic\" | null;\n /** Window in milliseconds, or the configured string (`\"1 minute\"`); `\"dynamic\"` for a function. */\n timeWindow: number | string | null;\n};\n\n/** What the route's request log entries keep. */\nexport type InspectRouteLogging = {\n /** Whether the request body is logged. */\n body: boolean;\n /** Whether the query string is logged. */\n query: boolean;\n /** Whether `http.logging.private` rules exist that may remove more for some URLs. */\n privateRules: boolean;\n};\n\n/** One request parameter (path, query or header). */\nexport type InspectParameter = {\n name: string;\n in: \"path\" | \"query\" | \"header\" | \"cookie\";\n required: boolean;\n schema: JsonSchema;\n};\n\n/** One registered HTTP route. */\nexport type InspectRoute = {\n /** Uppercase method, `ALL` for `router.all`. */\n method: string;\n path: string;\n name: string | null;\n /** Project-relative file that registered the route. */\n sourceFile: string | null;\n /** Handler function name, `\"anonymous\"` when it has none. */\n handler: string;\n description: string | null;\n /** Whether a page (SSR) route registered it. */\n isPage: boolean;\n /** Middleware function names in run order. */\n middleware: string[];\n auth: InspectRouteAuth;\n /** `false` when the route opted out of the CSRF origin guard (`csrf: false`). */\n csrf: boolean;\n rateLimit: InspectRouteRateLimit;\n logging: InspectRouteLogging;\n request: {\n parameters: InspectParameter[];\n /** JSON Schema of the request body, or `null`. */\n body: JsonSchema | null;\n /** Whether `validation.validate` (custom middleware, not described) is set. */\n customValidation: boolean;\n };\n /** Declared responses keyed by status code. */\n responses: Record<string, { description: string; schema: JsonSchema | null }>;\n};\n\n/** One model column, from the model's Seal `schema`. */\nexport type InspectModelColumn = {\n name: string;\n required: boolean;\n schema: JsonSchema;\n};\n\n/** One model relation. */\nexport type InspectModelRelation = {\n name: string;\n type: string;\n /** Target model name, or `null` when it could not be resolved. */\n model: string | null;\n foreignKey: string | null;\n localKey: string | null;\n};\n\n/** One model class. */\nexport type InspectModel = {\n name: string;\n table: string | null;\n primaryKey: string | null;\n /** Data source name, when configured by name. */\n dataSource: string | null;\n sourceFile: string | null;\n /** Whether `@RegisterModel()` put it in the registry. */\n registered: boolean;\n columns: InspectModelColumn[];\n relations: InspectModelRelation[];\n /** Name of the model's `static resource`, a key of `components.schemas`. */\n resource: string | null;\n deleteStrategy: string | null;\n createdAtColumn: string | null;\n updatedAtColumn: string | null;\n deletedAtColumn: string | null;\n};\n\n/** One resource class reached from a route or a model. */\nexport type InspectResource = {\n name: string;\n /** Its output shape (JSON Schema; nested resources are `$ref`s into `components.schemas`). */\n schema: JsonSchema;\n /** Models whose `static resource` is this resource. */\n models: string[];\n};\n\n/** One config key: its path and value type. Values are never printed. */\nexport type InspectConfigKey = {\n key: string;\n /** `string`, `number`, `boolean`, `null`, `array`, `object`, `function`, `regexp`, `date`, or a class name. */\n type: string;\n /** The `src/config/*` file the top-level key comes from, when it exists. */\n file: string | null;\n};\n\n/** One event and the listeners app modules registered for it. */\nexport type InspectEvent = {\n event: string;\n listeners: { name: string; sourceFile: string }[];\n};\n\n/** One page installed by `@warlock.js/web`. */\nexport type InspectPage = {\n path: string;\n name: string | null;\n file: string;\n /** Layout files from the outermost to the page's own directory. */\n layouts: string[];\n /** Files on the chain (layouts, then the page) that export a `loader`. */\n loaders: string[];\n /** Action names the page exports (`\"default\"` for `action`). */\n actions: string[];\n /** `\"user\"` when the page or a layout statically requires a user. */\n guard: string | null;\n};\n\n/** One queue job defined with `defineJob()`. */\nexport type InspectJob = {\n name: string;\n queue: string;\n attempts: number | null;\n backoff: number | { type: string; delay: number } | null;\n removeOnComplete: boolean | number | null;\n removeOnFail: boolean | number | null;\n};\n\n/** One scheduled task on the `@warlock.js/scheduler` scheduler. */\nexport type InspectSchedule = {\n name: string;\n cron: string | null;\n intervals: Record<string, unknown>;\n nextRun: string | null;\n};\n\n/** One installed `@warlock.js/*` package. */\nexport type InspectPackage = {\n name: string;\n version: string;\n};\n\n/** Something inspect could not read, with its code when one applies. */\nexport type InspectWarning = {\n code: WarlockErrorCode | null;\n message: string;\n /** The section or file it concerns. */\n source: string | null;\n};\n\n/** The whole report. Sections not requested are absent. */\nexport type InspectReport = {\n schemaVersion: typeof INSPECT_SCHEMA_VERSION;\n generatedAt: string;\n app: {\n name: string | null;\n version: string | null;\n /** Absolute project root. */\n root: string;\n node: string;\n environment: string;\n runtimeStrategy: string;\n };\n /** The sections this report contains. */\n sections: InspectSection[];\n routes?: InspectRoute[];\n models?: InspectModel[];\n resources?: InspectResource[];\n config?: InspectConfigKey[];\n events?: InspectEvent[];\n pages?: InspectPage[];\n jobs?: InspectJob[];\n schedules?: InspectSchedule[];\n packages?: InspectPackage[];\n /** Shared schemas that `$ref`s point at (`#/components/schemas/<name>`). */\n components: { schemas: Record<string, JsonSchema> };\n warnings: InspectWarning[];\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAkBA,MAAa,yBAAyB;;AAGtC,MAAa,mBAAmB;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
1
+ {"version":3,"file":"inspect-report.types.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/inspect-report.types.ts"],"sourcesContent":["import type { WarlockErrorCode } from \"../../errors/error-codes\";\n\n/**\n * @fileoverview The `warlock inspect` report, schema version 1.\n *\n * STABILITY: within `schemaVersion: 1` fields are only ever ADDED. No field is\n * removed, renamed or retyped, so a consumer written against this file keeps\n * working on every later 5.x release. Consumers must ignore keys they do not\n * know. A change that breaks that promise ships as `schemaVersion: 2` and is\n * listed under BREAKING in the changelog. Free text (warning messages,\n * descriptions) is not part of the contract.\n *\n * The same shape is published as JSON Schema (draft 2020-12) in\n * `@warlock.js/core/schemas/inspect-report.schema.json` and as the\n * `INSPECT_REPORT_JSON_SCHEMA` constant.\n */\n\n/** The version of the report shape. Bumped only for a breaking change. */\nexport const INSPECT_SCHEMA_VERSION = 1;\n\n/** Every section the report can contain, in output order. */\nexport const INSPECT_SECTIONS = [\n \"routes\",\n \"models\",\n \"resources\",\n \"config\",\n \"events\",\n \"pages\",\n \"jobs\",\n \"schedules\",\n \"packages\",\n \"files\",\n] as const;\n\n/** One section name. */\nexport type InspectSection = (typeof INSPECT_SECTIONS)[number];\n\n/** A JSON Schema (draft 2020-12) fragment. */\nexport type JsonSchema = Record<string, unknown>;\n\n/** Who guards a route, from the descriptor `authMiddleware()` attaches. */\nexport type InspectRouteAuth = {\n /** Whether an auth guard runs on the route. */\n required: boolean;\n /** Where the token is read: `\"header\"` (bearer) or `{ cookie }`. */\n sources: (\"header\" | { cookie: string })[];\n /** User types the guard accepts; empty means any. */\n userTypes: string[];\n};\n\n/** The rate limit a route runs under. */\nexport type InspectRouteRateLimit = {\n /** `route` = the route's own option, `global` = `http.rateLimit`, `none` = no limiter. */\n source: \"route\" | \"global\" | \"none\";\n /** Max requests per window; `\"dynamic\"` when configured as a function. */\n max: number | \"dynamic\" | null;\n /** Window in milliseconds, or the configured string (`\"1 minute\"`); `\"dynamic\"` for a function. */\n timeWindow: number | string | null;\n};\n\n/** What the route's request log entries keep. */\nexport type InspectRouteLogging = {\n /** Whether the request body is logged. */\n body: boolean;\n /** Whether the query string is logged. */\n query: boolean;\n /** Whether `http.logging.private` rules exist that may remove more for some URLs. */\n privateRules: boolean;\n};\n\n/** One request parameter (path, query or header). */\nexport type InspectParameter = {\n name: string;\n in: \"path\" | \"query\" | \"header\" | \"cookie\";\n required: boolean;\n schema: JsonSchema;\n};\n\n/** One registered HTTP route. */\nexport type InspectRoute = {\n /** Uppercase method, `ALL` for `router.all`. */\n method: string;\n path: string;\n name: string | null;\n /** Project-relative file that registered the route. */\n sourceFile: string | null;\n /** Handler function name, `\"anonymous\"` when it has none. */\n handler: string;\n description: string | null;\n /** Whether a page (SSR) route registered it. */\n isPage: boolean;\n /** Middleware function names in run order. */\n middleware: string[];\n auth: InspectRouteAuth;\n /** `false` when the route opted out of the CSRF origin guard (`csrf: false`). */\n csrf: boolean;\n rateLimit: InspectRouteRateLimit;\n logging: InspectRouteLogging;\n request: {\n parameters: InspectParameter[];\n /** JSON Schema of the request body, or `null`. */\n body: JsonSchema | null;\n /** Whether `validation.validate` (custom middleware, not described) is set. */\n customValidation: boolean;\n };\n /** Declared responses keyed by status code. */\n responses: Record<string, { description: string; schema: JsonSchema | null }>;\n};\n\n/** One model column, from the model's Seal `schema`. */\nexport type InspectModelColumn = {\n name: string;\n required: boolean;\n schema: JsonSchema;\n};\n\n/** One model relation. */\nexport type InspectModelRelation = {\n name: string;\n type: string;\n /** Target model name, or `null` when it could not be resolved. */\n model: string | null;\n foreignKey: string | null;\n localKey: string | null;\n};\n\n/** One model class. */\nexport type InspectModel = {\n name: string;\n table: string | null;\n primaryKey: string | null;\n /** Data source name, when configured by name. */\n dataSource: string | null;\n sourceFile: string | null;\n /** Whether `@RegisterModel()` put it in the registry. */\n registered: boolean;\n columns: InspectModelColumn[];\n relations: InspectModelRelation[];\n /** Name of the model's `static resource`, a key of `components.schemas`. */\n resource: string | null;\n deleteStrategy: string | null;\n createdAtColumn: string | null;\n updatedAtColumn: string | null;\n deletedAtColumn: string | null;\n};\n\n/** One resource class reached from a route or a model. */\nexport type InspectResource = {\n name: string;\n /** Its output shape (JSON Schema; nested resources are `$ref`s into `components.schemas`). */\n schema: JsonSchema;\n /** Models whose `static resource` is this resource. */\n models: string[];\n};\n\n/** One config key: its path and value type. Values are never printed. */\nexport type InspectConfigKey = {\n key: string;\n /** `string`, `number`, `boolean`, `null`, `array`, `object`, `function`, `regexp`, `date`, or a class name. */\n type: string;\n /** The `src/config/*` file the top-level key comes from, when it exists. */\n file: string | null;\n};\n\n/** One event and the listeners app modules registered for it. */\nexport type InspectEvent = {\n event: string;\n listeners: { name: string; sourceFile: string }[];\n};\n\n/** One page installed by `@warlock.js/web`. */\nexport type InspectPage = {\n path: string;\n name: string | null;\n file: string;\n /** Layout files from the outermost to the page's own directory. */\n layouts: string[];\n /** Files on the chain (layouts, then the page) that export a `loader`. */\n loaders: string[];\n /** Action names the page exports (`\"default\"` for `action`). */\n actions: string[];\n /** `\"user\"` when the page or a layout statically requires a user. */\n guard: string | null;\n};\n\n/** One queue job defined with `defineJob()`. */\nexport type InspectJob = {\n name: string;\n queue: string;\n attempts: number | null;\n backoff: number | { type: string; delay: number } | null;\n removeOnComplete: boolean | number | null;\n removeOnFail: boolean | number | null;\n};\n\n/** One scheduled task on the `@warlock.js/scheduler` scheduler. */\nexport type InspectSchedule = {\n name: string;\n cron: string | null;\n intervals: Record<string, unknown>;\n nextRun: string | null;\n};\n\n/** One installed `@warlock.js/*` package. */\nexport type InspectPackage = {\n name: string;\n version: string;\n};\n\n/** Something inspect could not read, with its code when one applies. */\nexport type InspectWarning = {\n code: WarlockErrorCode | null;\n message: string;\n /** The section or file it concerns. */\n source: string | null;\n};\n\n/** The whole report. Sections not requested are absent. */\nexport type InspectReport = {\n schemaVersion: typeof INSPECT_SCHEMA_VERSION;\n generatedAt: string;\n app: {\n name: string | null;\n version: string | null;\n /** Absolute project root. */\n root: string;\n node: string;\n environment: string;\n runtimeStrategy: string;\n };\n /** The sections this report contains. */\n sections: InspectSection[];\n routes?: InspectRoute[];\n models?: InspectModel[];\n resources?: InspectResource[];\n config?: InspectConfigKey[];\n events?: InspectEvent[];\n pages?: InspectPage[];\n jobs?: InspectJob[];\n schedules?: InspectSchedule[];\n packages?: InspectPackage[];\n files?: InspectFile[];\n /** Shared schemas that `$ref`s point at (`#/components/schemas/<name>`). */\n components: { schemas: Record<string, JsonSchema> };\n warnings: InspectWarning[];\n};\n\n/** A source file and its static module graph, with project-relative paths. */\nexport type InspectFile = {\n file: string;\n /** src/app/<module>, or the containing top-level src directory. */\n module: string;\n role: string;\n /** Public export names; default and * represent default and star exports. */\n exports: string[];\n /** Literal imports and re-exports; null means external or unresolved. */\n imports: { specifier: string; file: string | null }[];\n importedBy: string[];\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAkBA,MAAa,yBAAyB;;AAGtC,MAAa,mBAAmB;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-tools.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/mcp/mcp-tools.ts"],"mappings":";;;;;;;;;;;;;YA8BY;;EAEV;;EAEA;;EAEA,QAAQ,mBAAmB,mBAAmB,QAAQ;;EAEtD,MAAM;IACJ;IACA;IACA,gBAAgB;MACd,QAAQ;;EAEZ,MAAM;IACJ;IACA;IACA;MACE,QAAQ;;EAEZ,YAAY,QAAQ;;EAEpB;IACE,KAAK,MAAM,gBAAgB;IAC3B,MAAM,MAAM,gBAAgB;;;EAG9B,QAAQ,QAAQ;;EAEhB;;;YAIU;;EAEV;EACA;EACA,OAAO;;EAEP;;EAEA,YAAY,OAAO;EACnB,IAAI,OAAO,0BAA0B;;;qBAI1B;;wBAiPG,kBAAkB,OAAO,0BAA0B;;;;;;wBAgCnD,sBAAsB,SAAS,oBAAoB;;wBAiTnD,kBAAkB"}
1
+ {"version":3,"file":"mcp-tools.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/mcp/mcp-tools.ts"],"mappings":";;;;;;;;;;;;;YA8BY;;EAEV;;EAEA;;EAEA,QAAQ,mBAAmB,mBAAmB,QAAQ;;EAEtD,MAAM;IACJ;IACA;IACA,gBAAgB;MACd,QAAQ;;EAEZ,MAAM;IACJ;IACA;IACA;MACE,QAAQ;;EAEZ,YAAY,QAAQ;;EAEpB;IACE,KAAK,MAAM,gBAAgB;IAC3B,MAAM,MAAM,gBAAgB;;;EAG9B,QAAQ,QAAQ;;EAEhB;;;YAIU;;EAEV;EACA;EACA,OAAO;;EAEP;;EAEA,YAAY,OAAO;EACnB,IAAI,OAAO,0BAA0B;;;qBAI1B;;wBAoPG,kBAAkB,OAAO,0BAA0B;;;;;;wBAgCnD,sBAAsB,SAAS,oBAAoB;;wBAiTnD,kBAAkB"}
@@ -72,7 +72,12 @@ function sectionEntryMatches(section, entry, filter) {
72
72
  ],
73
73
  jobs: ["name", "queue"],
74
74
  schedules: ["name"],
75
- packages: ["name"]
75
+ packages: ["name"],
76
+ files: [
77
+ "file",
78
+ "module",
79
+ "role"
80
+ ]
76
81
  }[section].map((field) => {
77
82
  const value = Reflect.get(entry, field);
78
83
  return typeof value === "string" ? value : null;
@@ -87,6 +92,7 @@ const SECTION_DESCRIPTIONS = {
87
92
  pages: "Pages @warlock.js/web installed: path, name, file, layout chain, loaders, actions and guard.",
88
93
  jobs: "Queue jobs defined with defineJob() from @warlock.js/queue: name, queue, attempts, backoff, retention.",
89
94
  schedules: "Scheduled tasks from @warlock.js/scheduler: name, cron expression, intervals, next run.",
95
+ files: "Source files, convention roles, exports and resolved imports/importedBy (static analysis, no execution).",
90
96
  packages: "Installed @warlock.js/* packages and their versions."
91
97
  };
92
98
  function inspectSectionTool(context, section) {
@@ -106,7 +112,7 @@ function inspectSectionTool(context, section) {
106
112
  }
107
113
  return {
108
114
  name: `inspect_${section}`,
109
- description: `${SECTION_DESCRIPTIONS[section]} Read from the app's registries (the same data as \`warlock inspect --json --section ${section}\`), not from source text. Read-only.`,
115
+ description: `${SECTION_DESCRIPTIONS[section]} The same data as \`warlock inspect --json --section ${section}\`. Read-only.`,
110
116
  input: inputSchema(properties),
111
117
  writes: false,
112
118
  async run(input) {