@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.
- package/CHANGELOG.md +69 -0
- package/esm/cli/cli-commands.manager.mjs +1 -1
- package/esm/cli/cli-commands.manager.mjs.map +1 -1
- package/esm/cli/commands/add.command.mjs +1 -0
- package/esm/cli/commands/add.command.mjs.map +1 -1
- package/esm/cli/commands/build.command.mjs +30 -3
- package/esm/cli/commands/build.command.mjs.map +1 -1
- package/esm/cli/commands/check/check-command.action.mjs +1 -0
- package/esm/cli/commands/check/check-command.action.mjs.map +1 -1
- package/esm/cli/commands/check.command.mjs +5 -0
- package/esm/cli/commands/check.command.mjs.map +1 -1
- package/esm/cli/commands/explain/explain-command.action.mjs +21 -0
- package/esm/cli/commands/explain/explain-command.action.mjs.map +1 -1
- package/esm/cli/commands/explain.command.mjs +14 -4
- package/esm/cli/commands/explain.command.mjs.map +1 -1
- package/esm/cli/commands/generate/generate.command.mjs +19 -1
- package/esm/cli/commands/generate/generate.command.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/endpoint.generator.mjs +1 -1
- package/esm/cli/commands/generate/generators/endpoint.generator.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/web.generator.mjs +169 -0
- package/esm/cli/commands/generate/generators/web.generator.mjs.map +1 -0
- package/esm/cli/commands/generate/templates/web-stubs.mjs +231 -0
- package/esm/cli/commands/generate/templates/web-stubs.mjs.map +1 -0
- package/esm/cli/commands/inspect/inspect-command.action.mjs +4 -3
- package/esm/cli/commands/inspect/inspect-command.action.mjs.map +1 -1
- package/esm/cli/commands/inspect.command.mjs +13 -8
- package/esm/cli/commands/inspect.command.mjs.map +1 -1
- package/esm/cli/commands/mcp/mcp-command.action.mjs +1 -1
- package/esm/cli/commands/mcp/mcp-command.action.mjs.map +1 -1
- package/esm/config/config-loader.d.mts.map +1 -1
- package/esm/config/config-loader.mjs +2 -0
- package/esm/config/config-loader.mjs.map +1 -1
- package/esm/config/load-config-files.mjs +4 -0
- package/esm/config/load-config-files.mjs.map +1 -1
- package/esm/dev-server/file-event-handler.mjs +11 -1
- package/esm/dev-server/file-event-handler.mjs.map +1 -1
- package/esm/dev-server/file-manager.d.mts +1 -1
- package/esm/dev-server/file-manager.d.mts.map +1 -1
- package/esm/dev-server/file-manager.mjs.map +1 -1
- package/esm/dev-server/files-orchestrator.mjs +16 -1
- package/esm/dev-server/files-orchestrator.mjs.map +1 -1
- package/esm/dev-server/files-watcher.mjs +13 -4
- package/esm/dev-server/files-watcher.mjs.map +1 -1
- package/esm/dev-server/loader/loader-port-acks.mjs +21 -9
- package/esm/dev-server/loader/loader-port-acks.mjs.map +1 -1
- package/esm/dev-server/loader/register-loader.mjs +31 -12
- package/esm/dev-server/loader/register-loader.mjs.map +1 -1
- package/esm/dev-server/module-loader.mjs +15 -1
- package/esm/dev-server/module-loader.mjs.map +1 -1
- package/esm/dev-server/parse-imports.mjs +1 -1
- package/esm/dev-server/special-file-patterns.mjs +4 -1
- package/esm/dev-server/special-file-patterns.mjs.map +1 -1
- package/esm/dev-server/type-generator.mjs +1 -1
- package/esm/e2e/cdp.d.mts.map +1 -1
- package/esm/e2e/cdp.mjs +9 -2
- package/esm/e2e/cdp.mjs.map +1 -1
- package/esm/e2e/index.d.mts +2 -2
- package/esm/e2e/page.d.mts +14 -1
- package/esm/e2e/page.d.mts.map +1 -1
- package/esm/e2e/page.mjs +81 -8
- package/esm/e2e/page.mjs.map +1 -1
- package/esm/e2e/types.d.mts +49 -0
- package/esm/e2e/types.d.mts.map +1 -1
- package/esm/e2e/types.mjs.map +1 -1
- package/esm/errors/error-codes.d.mts +72 -0
- package/esm/errors/error-codes.d.mts.map +1 -1
- package/esm/errors/error-codes.mjs +72 -0
- package/esm/errors/error-codes.mjs.map +1 -1
- package/esm/errors/index.d.mts +2 -2
- package/esm/errors/index.mjs +2 -2
- package/esm/generations/add-command.action.mjs +2 -0
- package/esm/generations/add-command.action.mjs.map +1 -1
- package/esm/generations/design-system-payload.mjs +53 -0
- package/esm/generations/design-system-payload.mjs.map +1 -0
- package/esm/generations/features/design-system.feature.mjs +38 -0
- package/esm/generations/features/design-system.feature.mjs.map +1 -0
- package/esm/generations/features/index.mjs +3 -1
- package/esm/generations/features/index.mjs.map +1 -1
- package/esm/generations/features/notifications.feature.mjs +13 -2
- package/esm/generations/features/notifications.feature.mjs.map +1 -1
- package/esm/generations/features/test.feature.mjs +48 -13
- package/esm/generations/features/test.feature.mjs.map +1 -1
- package/esm/generations/features/web.feature.mjs +3 -3
- package/esm/generations/features/web.feature.mjs.map +1 -1
- package/esm/generations/stubs.mjs +9 -5
- package/esm/generations/stubs.mjs.map +1 -1
- package/esm/http/error-mapper.d.mts +1 -1
- package/esm/http/error-mapper.mjs +3 -3
- package/esm/http/error-mapper.mjs.map +1 -1
- package/esm/http/error-response.d.mts +3 -0
- package/esm/http/error-response.d.mts.map +1 -1
- package/esm/http/error-response.mjs +8 -2
- package/esm/http/error-response.mjs.map +1 -1
- package/esm/http/errors/errors.d.mts +8 -0
- package/esm/http/errors/errors.d.mts.map +1 -1
- package/esm/http/errors/errors.mjs +13 -1
- package/esm/http/errors/errors.mjs.map +1 -1
- package/esm/http/index.d.mts +3 -2
- package/esm/http/index.mjs +3 -2
- package/esm/http/list-endpoint.d.mts +35 -0
- package/esm/http/list-endpoint.d.mts.map +1 -0
- package/esm/http/list-endpoint.mjs +28 -0
- package/esm/http/list-endpoint.mjs.map +1 -0
- package/esm/http/middleware/inject-request-context.d.mts.map +1 -1
- package/esm/http/middleware/inject-request-context.mjs +12 -2
- package/esm/http/middleware/inject-request-context.mjs.map +1 -1
- package/esm/http/server.mjs +1 -1
- package/esm/index.d.mts +10 -6
- package/esm/index.mjs +5 -2
- package/esm/localization/index.mjs +3 -1
- package/esm/localization/translation-usage-graph.d.mts +49 -0
- package/esm/localization/translation-usage-graph.d.mts.map +1 -0
- package/esm/localization/translation-usage-graph.mjs +128 -0
- package/esm/localization/translation-usage-graph.mjs.map +1 -0
- package/esm/localization/translation-usage.d.mts +85 -0
- package/esm/localization/translation-usage.d.mts.map +1 -0
- package/esm/localization/translation-usage.mjs +307 -0
- package/esm/localization/translation-usage.mjs.map +1 -0
- package/esm/openapi/security.mjs +12 -4
- package/esm/openapi/security.mjs.map +1 -1
- package/esm/openapi/types.d.mts +2 -0
- package/esm/openapi/types.d.mts.map +1 -1
- package/esm/production/build-budgets.d.mts +64 -0
- package/esm/production/build-budgets.d.mts.map +1 -0
- package/esm/production/build-budgets.mjs +109 -0
- package/esm/production/build-budgets.mjs.map +1 -0
- package/esm/production/production-builder.mjs +13 -1
- package/esm/production/production-builder.mjs.map +1 -1
- package/esm/production/resolve-build-config.d.mts +1 -1
- package/esm/production/resolve-build-config.d.mts.map +1 -1
- package/esm/production/resolve-build-config.mjs.map +1 -1
- package/esm/production/route-registration-snapshot.mjs +5 -3
- package/esm/production/route-registration-snapshot.mjs.map +1 -1
- package/esm/restful/restful.d.mts +1 -1
- package/esm/router/router.d.mts +2 -0
- package/esm/router/router.d.mts.map +1 -1
- package/esm/router/router.mjs +4 -1
- package/esm/router/router.mjs.map +1 -1
- package/esm/router/types.d.mts +19 -0
- package/esm/router/types.d.mts.map +1 -1
- package/esm/tests/fakes/storage-fake.d.mts +3 -1
- package/esm/tests/fakes/storage-fake.d.mts.map +1 -1
- package/esm/tests/fakes/storage-fake.mjs +3 -3
- package/esm/tests/fakes/storage-fake.mjs.map +1 -1
- package/esm/tests/fakes/test-fakes.d.mts +3 -1
- package/esm/tests/fakes/test-fakes.d.mts.map +1 -1
- package/esm/tests/fakes/test-fakes.mjs +3 -2
- package/esm/tests/fakes/test-fakes.mjs.map +1 -1
- package/esm/tests/index.d.mts +4 -2
- package/esm/tests/index.mjs +3 -1
- package/esm/tests/load-unit-config.mjs +24 -0
- package/esm/tests/load-unit-config.mjs.map +1 -0
- package/esm/tests/response-contract.d.mts +32 -0
- package/esm/tests/response-contract.d.mts.map +1 -0
- package/esm/tests/response-contract.mjs +116 -0
- package/esm/tests/response-contract.mjs.map +1 -0
- package/esm/tests/start-http-development-server.d.mts.map +1 -1
- package/esm/tests/start-http-development-server.mjs +10 -2
- package/esm/tests/start-http-development-server.mjs.map +1 -1
- package/esm/tests/test-lifecycle-state.mjs.map +1 -1
- package/esm/tests/test-locales.mjs +33 -0
- package/esm/tests/test-locales.mjs.map +1 -0
- package/esm/tests/test-runtime-scope.d.mts +15 -0
- package/esm/tests/test-runtime-scope.d.mts.map +1 -0
- package/esm/tests/test-runtime-scope.mjs +80 -0
- package/esm/tests/test-runtime-scope.mjs.map +1 -0
- package/esm/tests/vitest-setup.d.mts +13 -3
- package/esm/tests/vitest-setup.d.mts.map +1 -1
- package/esm/tests/vitest-setup.mjs +146 -18
- package/esm/tests/vitest-setup.mjs.map +1 -1
- package/esm/tooling/check/affected-files.d.mts +5 -0
- package/esm/tooling/check/affected-files.d.mts.map +1 -0
- package/esm/tooling/check/affected-files.mjs +56 -0
- package/esm/tooling/check/affected-files.mjs.map +1 -0
- package/esm/tooling/check/api-route-references.d.mts +16 -0
- package/esm/tooling/check/api-route-references.d.mts.map +1 -0
- package/esm/tooling/check/api-route-references.mjs +146 -0
- package/esm/tooling/check/api-route-references.mjs.map +1 -0
- package/esm/tooling/check/changed-files.d.mts +2 -0
- package/esm/tooling/check/changed-files.d.mts.map +1 -1
- package/esm/tooling/check/changed-files.mjs +2 -2
- package/esm/tooling/check/changed-files.mjs.map +1 -1
- package/esm/tooling/check/conventions-step.d.mts +7 -3
- package/esm/tooling/check/conventions-step.d.mts.map +1 -1
- package/esm/tooling/check/conventions-step.mjs +59 -8
- package/esm/tooling/check/conventions-step.mjs.map +1 -1
- package/esm/tooling/check/fixes.d.mts +8 -0
- package/esm/tooling/check/fixes.d.mts.map +1 -0
- package/esm/tooling/check/fixes.mjs +31 -0
- package/esm/tooling/check/fixes.mjs.map +1 -0
- package/esm/tooling/check/index.d.mts +12 -0
- package/esm/tooling/check/index.mjs +3 -2
- package/esm/tooling/check/run-check.d.mts +2 -0
- package/esm/tooling/check/run-check.d.mts.map +1 -1
- package/esm/tooling/check/run-check.mjs +23 -5
- package/esm/tooling/check/run-check.mjs.map +1 -1
- package/esm/tooling/check/run-tests.mjs +1 -1
- package/esm/tooling/check/source-ast.d.mts +1 -0
- package/esm/tooling/check/translation-conventions.mjs +32 -0
- package/esm/tooling/check/translation-conventions.mjs.map +1 -0
- package/esm/tooling/check/web-conventions.d.mts +10 -0
- package/esm/tooling/check/web-conventions.d.mts.map +1 -0
- package/esm/tooling/check/web-conventions.mjs +126 -0
- package/esm/tooling/check/web-conventions.mjs.map +1 -0
- package/esm/tooling/index.d.mts +7 -2
- package/esm/tooling/index.mjs +4 -2
- package/esm/tooling/inspect/collect-files.mjs +172 -0
- package/esm/tooling/inspect/collect-files.mjs.map +1 -0
- package/esm/tooling/inspect/collect-pages.mjs +3 -2
- package/esm/tooling/inspect/collect-pages.mjs.map +1 -1
- package/esm/tooling/inspect/collect-routes.mjs +1 -1
- package/esm/tooling/inspect/collect-routes.mjs.map +1 -1
- package/esm/tooling/inspect/explain-file.d.mts +12 -0
- package/esm/tooling/inspect/explain-file.d.mts.map +1 -0
- package/esm/tooling/inspect/explain-file.mjs +45 -0
- package/esm/tooling/inspect/explain-file.mjs.map +1 -0
- package/esm/tooling/inspect/index.d.mts +3 -2
- package/esm/tooling/inspect/index.mjs +2 -1
- package/esm/tooling/inspect/inspect-app.d.mts.map +1 -1
- package/esm/tooling/inspect/inspect-app.mjs +9 -3
- package/esm/tooling/inspect/inspect-app.mjs.map +1 -1
- package/esm/tooling/inspect/inspect-report.schema.mjs +34 -1
- package/esm/tooling/inspect/inspect-report.schema.mjs.map +1 -1
- package/esm/tooling/inspect/inspect-report.types.d.mts +17 -1
- package/esm/tooling/inspect/inspect-report.types.d.mts.map +1 -1
- package/esm/tooling/inspect/inspect-report.types.mjs +2 -1
- package/esm/tooling/inspect/inspect-report.types.mjs.map +1 -1
- package/esm/tooling/mcp/mcp-tools.d.mts.map +1 -1
- package/esm/tooling/mcp/mcp-tools.mjs +8 -2
- package/esm/tooling/mcp/mcp-tools.mjs.map +1 -1
- package/esm/tooling/problem.d.mts +4 -0
- package/esm/tooling/problem.d.mts.map +1 -1
- package/esm/tooling/problem.mjs +1 -0
- package/esm/tooling/problem.mjs.map +1 -1
- package/esm/tooling/syntax/ast.d.mts +2 -0
- package/esm/tooling/typecheck/run-typecheck.mjs +5 -1
- package/esm/tooling/typecheck/run-typecheck.mjs.map +1 -1
- package/esm/upgrade/codemods/index.mjs +2 -0
- package/esm/upgrade/codemods/index.mjs.map +1 -1
- package/esm/upgrade/codemods/vite-vitest.mjs +170 -0
- package/esm/upgrade/codemods/vite-vitest.mjs.map +1 -0
- package/esm/upgrade/notes.mjs +4 -0
- package/esm/upgrade/notes.mjs.map +1 -1
- package/esm/vite/index.d.mts +3 -1
- package/esm/vite/index.mjs +3 -1
- package/esm/vite/test-setup-reporter.d.mts +16 -0
- package/esm/vite/test-setup-reporter.d.mts.map +1 -0
- package/esm/vite/test-setup-reporter.mjs +55 -0
- package/esm/vite/test-setup-reporter.mjs.map +1 -0
- package/esm/vite/test-workers.d.mts +5 -0
- package/esm/vite/test-workers.d.mts.map +1 -0
- package/esm/vite/test-workers.mjs +38 -0
- package/esm/vite/test-workers.mjs.map +1 -0
- package/esm/warlock-config/index.d.mts +2 -1
- package/esm/warlock-config/types.d.mts +3 -0
- package/esm/warlock-config/types.d.mts.map +1 -1
- package/llms-full.txt +874 -9
- package/llms.txt +2 -0
- package/package.json +15 -14
- package/schemas/inspect-report.schema.json +47 -1
- package/skills/build-budgets/SKILL.md +51 -0
- package/skills/build-restful/SKILL.md +56 -0
- package/skills/configure-app/SKILL.md +7 -0
- package/skills/create-module/SKILL.md +9 -0
- package/skills/generate-web-ui/SKILL.md +71 -0
- package/skills/index.md +2 -2
- package/skills/register-route/SKILL.md +13 -0
- package/skills/run-app/SKILL.md +1 -1
- package/skills/send-mail/SKILL.md +25 -0
- package/skills/send-response/SKILL.md +50 -0
- package/skills/test-browser/SKILL.md +53 -0
- package/skills/test-http/SKILL.md +91 -0
- package/skills/test-service/SKILL.md +161 -3
- package/skills/upgrade-from-5-29/SKILL.md +109 -0
- package/skills/use-localization/SKILL.md +25 -0
- package/skills/warlock-check/SKILL.md +75 -1
- package/skills/warlock-inspect/SKILL.md +45 -2
- package/skills/warlock-mcp/SKILL.md +4 -0
- package/skills/write-cli-command/SKILL.md +18 -0
- package/esm/production/build-app-production.mjs +0 -14
- package/esm/production/build-app-production.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-check.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/check/run-check.ts"],"sourcesContent":["import path from \"node:path\";\nimport { createProblem, type ToolingProblem } from \"../problem\";\nimport {\n runTypecheck,\n type TypecheckOptions,\n type TypecheckResult,\n} from \"../typecheck/run-typecheck\";\nimport { type GitRunner, listChangedFiles } from \"./changed-files\";\nimport {\n CHECK_STEPS,\n type CheckReport,\n type CheckStep,\n type CheckStepName,\n type CheckStepStatus,\n checkExitCode,\n} from \"./check-report.types\";\nimport { runConventions } from \"./conventions-step\";\nimport { checkNodeVersion } from \"./environment-step\";\nimport { runLint } from \"./lint-step\";\nimport { listSourceFiles, listTestFiles } from \"./source-files\";\nimport {\n findVitest,\n parseVitestReport,\n runVitest,\n type VitestRunner,\n vitestArguments,\n vitestRunFailure,\n} from \"./tests-step\";\n\n/** Runs the typecheck step. The CLI swaps in a child process so a heap overflow cannot end `check`. */\nexport type TypecheckRunner = (\n options: TypecheckOptions,\n) => Promise<TypecheckResult> | TypecheckResult;\n\n/** Inputs of {@link runCheck}. */\nexport type CheckOptions = {\n /** Project root. Default: `process.cwd()`. */\n cwd?: string;\n /** Oxlint is the only supported linter. */\n lint?: \"oxlint\";\n /** Limit every step to the files changed against `base` (default HEAD) plus untracked files. */\n changed?: boolean;\n /** Compare with `git merge-base <base> HEAD` instead of HEAD. Implies `changed`. */\n base?: string;\n /** Steps not to run. */\n skip?: readonly CheckStepName[];\n /** tsconfig path, relative to `cwd`. Default: `tsconfig.json`. */\n project?: string;\n /** How git is run. */\n git?: GitRunner;\n /** How the typecheck runs. Default: in this process. */\n typecheck?: TypecheckRunner;\n /** How vitest runs. */\n vitest?: VitestRunner;\n /** Where the app's vitest CLI is. Default: resolved from the app root. */\n vitestBinary?: string | null;\n /** The Node.js version to check. Default: the running one. */\n nodeVersion?: string;\n};\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction statusOf(problems: readonly ToolingProblem[]): CheckStepStatus {\n const errors = problems.filter((problem) => problem.severity === \"error\");\n\n if (errors.some((problem) => problem.category === \"environment\")) return \"blocked\";\n\n return errors.length > 0 ? \"failed\" : \"passed\";\n}\n\n/** Bundles one step's timing, status and problems. */\ntype StepOutcome = { status?: CheckStepStatus; detail: string | null; problems: ToolingProblem[] };\n\n/**\n * The single verify command: typecheck, lint, the tests affected by the\n * change, and the framework's convention checks, as one report with one entry\n * per problem and an exit code that tells \"your code\" (1) from \"this machine\"\n * (2).\n *\n * Every step runs even when an earlier one failed, so one run lists every\n * problem. The only exception: with `changed`, a git failure leaves no file\n * list, and every step after `environment` is `blocked`.\n */\nexport async function runCheck(options: CheckOptions = {}): Promise<CheckReport> {\n const selection: unknown = options.lint;\n if (selection !== undefined && selection !== \"oxlint\")\n throw new Error(\n \"ESLint support was removed in 5.34.0. Oxlint/Oxfmt is the default; run npx warlock upgrade --from 5.33 --to 5.34.0.\",\n );\n const cwd = path.resolve(options.cwd ?? process.cwd());\n const changed = options.changed === true || options.base !== undefined;\n const skip = new Set(options.skip ?? []);\n const steps: CheckStep[] = [];\n const problems: ToolingProblem[] = [];\n let files: string[] | null = null;\n let filesBlocked = false;\n\n const run = async (name: CheckStepName, body: () => Promise<StepOutcome> | StepOutcome) => {\n const startedAt = Date.now();\n\n if (skip.has(name)) {\n steps.push({ name, status: \"skipped\", durationMs: 0, detail: \"skipped with --skip\" });\n return;\n }\n\n if (filesBlocked && name !== \"environment\") {\n steps.push({\n name,\n status: \"blocked\",\n durationMs: 0,\n detail: \"the changed files could not be listed\",\n });\n return;\n }\n\n let outcome: StepOutcome;\n\n try {\n outcome = await body();\n } catch (error) {\n outcome = {\n detail: null,\n problems: [\n createProblem({\n code: \"WL8007\",\n source: \"environment\",\n message: `The ${name} step crashed: ${errorMessage(error)}`,\n }),\n ],\n };\n }\n\n problems.push(...outcome.problems);\n steps.push({\n name,\n status: outcome.status ?? statusOf(outcome.problems),\n durationMs: Date.now() - startedAt,\n detail: outcome.detail,\n });\n };\n\n await run(\"environment\", async () => {\n const found = checkNodeVersion(cwd, options.nodeVersion);\n\n if (changed) {\n const listed = await listChangedFiles({ cwd, base: options.base, git: options.git });\n\n if (\"problem\" in listed) {\n filesBlocked = true;\n found.push(listed.problem);\n } else {\n files = listed.files;\n }\n }\n\n return {\n detail: `Node ${options.nodeVersion ?? process.versions.node}${files ? `, ${files.length} changed file(s)` : \"\"}`,\n problems: found,\n };\n });\n\n const targets = async (): Promise<string[]> => files ?? (await listSourceFiles(cwd));\n\n await run(\"typecheck\", async () => {\n if (files !== null && files.length === 0) {\n return { status: \"skipped\", detail: \"no changed files\", problems: [] };\n }\n\n const typecheck = options.typecheck ?? runTypecheck;\n const result = await typecheck({\n cwd,\n project: options.project,\n ...(files !== null ? { files } : {}),\n });\n\n return {\n detail: `${result.checkedFiles} file(s) checked in ${result.durationMs}ms`,\n problems: result.problems,\n };\n });\n\n await run(\"lint\", async () => {\n const lintFiles = await targets();\n\n if (lintFiles.length === 0) {\n return { status: \"skipped\", detail: \"no files to lint\", problems: [] };\n }\n\n const { linters, problems: found } = await runLint(cwd, lintFiles);\n\n if (linters.length === 0) {\n return {\n status: \"skipped\",\n detail: \"no Oxlint config\",\n problems: [],\n };\n }\n\n return { detail: `${linters.join(\" + \")} over ${lintFiles.length} file(s)`, problems: found };\n });\n\n await run(\"tests\", async () => {\n if (files !== null && files.length === 0) {\n return { status: \"skipped\", detail: \"no changed files\", problems: [] };\n }\n\n const binary = options.vitestBinary === undefined ? findVitest(cwd) : options.vitestBinary;\n\n if (!binary) {\n if ((await listTestFiles(cwd)).length === 0) {\n return { status: \"skipped\", detail: \"no test files\", problems: [] };\n }\n\n return {\n detail: null,\n problems: [\n createProblem({\n code: \"WL8002\",\n source: \"environment\",\n message: \"The project has test files but vitest is not installed in the app.\",\n }),\n ],\n };\n }\n\n const vitest = options.vitest ?? runVitest;\n const outcome = await vitest(binary, vitestArguments(files), cwd);\n const found =\n outcome.report === undefined\n ? vitestRunFailure(outcome)\n : parseVitestReport(outcome.report, cwd);\n const total =\n typeof outcome.report === \"object\" && outcome.report !== null\n ? Reflect.get(outcome.report, \"numTotalTests\")\n : undefined;\n\n return {\n detail: typeof total === \"number\" ? `${total} test(s) ran` : null,\n problems: found,\n };\n });\n\n await run(\"conventions\", async () => {\n const conventionFiles = await targets();\n\n return {\n detail: `${conventionFiles.length} file(s) checked`,\n problems: runConventions(cwd, conventionFiles, options.project),\n };\n });\n\n // Keep the declared order even if a future step is added out of sequence.\n steps.sort((first, second) => CHECK_STEPS.indexOf(first.name) - CHECK_STEPS.indexOf(second.name));\n\n const exitCode = checkExitCode(problems);\n const errors = problems.filter((problem) => problem.severity === \"error\");\n\n return {\n schemaVersion: 1,\n ok: exitCode === 0,\n exitCode,\n changed,\n files,\n steps,\n problems,\n summary: {\n errors: errors.length,\n warnings: problems.length - errors.length,\n code: errors.filter((problem) => problem.category === \"code\").length,\n environment: errors.filter((problem) => problem.category === \"environment\").length,\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"run-check.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/check/run-check.ts"],"sourcesContent":["import { affectedFiles } from \"./affected-files\";\nimport { applyConventionFixes } from \"./fixes\";\nimport path from \"node:path\";\nimport { createProblem, type ToolingProblem } from \"../problem\";\nimport {\n runTypecheck,\n type TypecheckOptions,\n type TypecheckResult,\n} from \"../typecheck/run-typecheck\";\nimport { type GitRunner, listChangedFiles } from \"./changed-files\";\nimport {\n CHECK_STEPS,\n type CheckReport,\n type CheckStep,\n type CheckStepName,\n type CheckStepStatus,\n checkExitCode,\n} from \"./check-report.types\";\nimport { runConventions } from \"./conventions-step\";\nimport { collectApiRouteFacts } from \"./api-route-references\";\nimport { checkNodeVersion } from \"./environment-step\";\nimport { runLint } from \"./lint-step\";\nimport { listSourceFiles, listTestFiles } from \"./source-files\";\nimport {\n findVitest,\n parseVitestReport,\n runVitest,\n type VitestRunner,\n vitestArguments,\n vitestRunFailure,\n} from \"./tests-step\";\n\n/** Runs the typecheck step. The CLI swaps in a child process so a heap overflow cannot end `check`. */\nexport type TypecheckRunner = (\n options: TypecheckOptions,\n) => Promise<TypecheckResult> | TypecheckResult;\n\n/** Inputs of {@link runCheck}. */\nexport type CheckOptions = {\n /** Project root. Default: `process.cwd()`. */\n cwd?: string;\n /** Oxlint is the only supported linter. */\n lint?: \"oxlint\";\n /** Limit every step to the files changed against `base` (default HEAD) plus untracked files. */\n changed?: boolean;\n /** Apply safe convention fixes before checking. */\n fix?: boolean;\n /** Compare with `git merge-base <base> HEAD` instead of HEAD. Implies `changed`. */\n base?: string;\n /** Steps not to run. */\n skip?: readonly CheckStepName[];\n /** tsconfig path, relative to `cwd`. Default: `tsconfig.json`. */\n project?: string;\n /** How git is run. */\n git?: GitRunner;\n /** How the typecheck runs. Default: in this process. */\n typecheck?: TypecheckRunner;\n /** How vitest runs. */\n vitest?: VitestRunner;\n /** Where the app's vitest CLI is. Default: resolved from the app root. */\n vitestBinary?: string | null;\n /** The Node.js version to check. Default: the running one. */\n nodeVersion?: string;\n};\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction statusOf(problems: readonly ToolingProblem[]): CheckStepStatus {\n const errors = problems.filter((problem) => problem.severity === \"error\");\n\n if (errors.some((problem) => problem.category === \"environment\")) return \"blocked\";\n\n return errors.length > 0 ? \"failed\" : \"passed\";\n}\n\n/** Bundles one step's timing, status and problems. */\ntype StepOutcome = { status?: CheckStepStatus; detail: string | null; problems: ToolingProblem[] };\n\n/**\n * The single verify command: typecheck, lint, the tests affected by the\n * change, and the framework's convention checks, as one report with one entry\n * per problem and an exit code that tells \"your code\" (1) from \"this machine\"\n * (2).\n *\n * Every step runs even when an earlier one failed, so one run lists every\n * problem. The only exception: with `changed`, a git failure leaves no file\n * list, and every step after `environment` is `blocked`.\n */\nexport async function runCheck(options: CheckOptions = {}): Promise<CheckReport> {\n const selection: unknown = options.lint;\n if (selection !== undefined && selection !== \"oxlint\")\n throw new Error(\n \"ESLint support was removed in 5.34.0. Oxlint/Oxfmt is the default; run npx warlock upgrade --from 5.33 --to 5.34.0.\",\n );\n const cwd = path.resolve(options.cwd ?? process.cwd());\n const changed = options.changed === true || options.base !== undefined;\n const skip = new Set(options.skip ?? []);\n const steps: CheckStep[] = [];\n const problems: ToolingProblem[] = [];\n let files: string[] | null = null;\n let filesBlocked = false;\n\n const run = async (name: CheckStepName, body: () => Promise<StepOutcome> | StepOutcome) => {\n const startedAt = Date.now();\n\n if (skip.has(name)) {\n steps.push({ name, status: \"skipped\", durationMs: 0, detail: \"skipped with --skip\" });\n return;\n }\n\n if (filesBlocked && name !== \"environment\") {\n steps.push({\n name,\n status: \"blocked\",\n durationMs: 0,\n detail: \"the changed files could not be listed\",\n });\n return;\n }\n\n let outcome: StepOutcome;\n\n try {\n outcome = await body();\n } catch (error) {\n outcome = {\n detail: null,\n problems: [\n createProblem({\n code: \"WL8007\",\n source: \"environment\",\n message: `The ${name} step crashed: ${errorMessage(error)}`,\n }),\n ],\n };\n }\n\n problems.push(...outcome.problems);\n steps.push({\n name,\n status: outcome.status ?? statusOf(outcome.problems),\n durationMs: Date.now() - startedAt,\n detail: outcome.detail,\n });\n };\n\n await run(\"environment\", async () => {\n const found = checkNodeVersion(cwd, options.nodeVersion);\n\n if (changed) {\n const listed = await listChangedFiles({\n cwd,\n base: options.base,\n git: options.git,\n includeDeleted: true,\n });\n\n if (\"problem\" in listed) {\n filesBlocked = true;\n found.push(listed.problem);\n } else {\n filesBlocked = true;\n files = await affectedFiles(cwd, listed.files, options.project);\n filesBlocked = false;\n }\n }\n\n return {\n detail: `Node ${options.nodeVersion ?? process.versions.node}${files ? `, ${files.length} changed file(s)` : \"\"}`,\n problems: found,\n };\n });\n\n const targets = async (): Promise<string[]> => files ?? (await listSourceFiles(cwd));\n\n if (options.fix && !filesBlocked && !skip.has(\"conventions\")) {\n try {\n const fixTargets = await targets();\n applyConventionFixes(\n cwd,\n runConventions(\n cwd,\n fixTargets,\n options.project,\n collectApiRouteFacts(cwd, await listSourceFiles(cwd)),\n ),\n );\n } catch (error) {\n problems.push(\n createProblem({\n code: \"WL8007\",\n source: \"environment\",\n message: `Could not apply fixes: ${errorMessage(error)}`,\n }),\n );\n }\n }\n\n await run(\"typecheck\", async () => {\n if (files !== null && files.length === 0) {\n return { status: \"skipped\", detail: \"no changed files\", problems: [] };\n }\n\n const typecheck = options.typecheck ?? runTypecheck;\n const result = await typecheck({\n cwd,\n project: options.project,\n ...(files !== null ? { files } : {}),\n });\n\n return {\n detail: `${result.checkedFiles} file(s) checked in ${result.durationMs}ms`,\n problems: result.problems,\n };\n });\n\n await run(\"lint\", async () => {\n const lintFiles = await targets();\n\n if (lintFiles.length === 0) {\n return { status: \"skipped\", detail: \"no files to lint\", problems: [] };\n }\n\n const { linters, problems: found } = await runLint(cwd, lintFiles);\n\n if (linters.length === 0) {\n return {\n status: \"skipped\",\n detail: \"no Oxlint config\",\n problems: [],\n };\n }\n\n return { detail: `${linters.join(\" + \")} over ${lintFiles.length} file(s)`, problems: found };\n });\n\n await run(\"tests\", async () => {\n if (files !== null && files.length === 0) {\n return { status: \"skipped\", detail: \"no changed files\", problems: [] };\n }\n\n const binary = options.vitestBinary === undefined ? findVitest(cwd) : options.vitestBinary;\n\n if (!binary) {\n if ((await listTestFiles(cwd)).length === 0) {\n return { status: \"skipped\", detail: \"no test files\", problems: [] };\n }\n\n return {\n detail: null,\n problems: [\n createProblem({\n code: \"WL8002\",\n source: \"environment\",\n message: \"The project has test files but vitest is not installed in the app.\",\n }),\n ],\n };\n }\n\n const vitest = options.vitest ?? runVitest;\n const outcome = await vitest(binary, vitestArguments(files), cwd);\n const found =\n outcome.report === undefined\n ? vitestRunFailure(outcome)\n : parseVitestReport(outcome.report, cwd);\n const total =\n typeof outcome.report === \"object\" && outcome.report !== null\n ? Reflect.get(outcome.report, \"numTotalTests\")\n : undefined;\n\n return {\n detail: typeof total === \"number\" ? `${total} test(s) ran` : null,\n problems: found,\n };\n });\n\n await run(\"conventions\", async () => {\n const conventionFiles = await targets();\n\n return {\n detail: `${conventionFiles.length} file(s) checked`,\n // Facts come from the whole project even when only changed files are checked:\n // a route registered in one file may be referenced from another.\n problems: runConventions(\n cwd,\n conventionFiles,\n options.project,\n collectApiRouteFacts(cwd, await listSourceFiles(cwd)),\n ),\n };\n });\n\n // Keep the declared order even if a future step is added out of sequence.\n steps.sort((first, second) => CHECK_STEPS.indexOf(first.name) - CHECK_STEPS.indexOf(second.name));\n\n const exitCode = checkExitCode(problems);\n const errors = problems.filter((problem) => problem.severity === \"error\");\n\n return {\n schemaVersion: 1,\n ok: exitCode === 0,\n exitCode,\n changed,\n files,\n steps,\n problems,\n summary: {\n errors: errors.length,\n warnings: problems.length - errors.length,\n code: errors.filter((problem) => problem.category === \"code\").length,\n environment: errors.filter((problem) => problem.category === \"environment\").length,\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { checkExitCode } from "./check-report.types.mjs";
|
|
2
2
|
import { createProblem } from "../problem.mjs";
|
|
3
|
-
import { listChangedFiles } from "./changed-files.mjs";
|
|
4
3
|
import { listTestFiles } from "./source-files.mjs";
|
|
4
|
+
import { listChangedFiles } from "./changed-files.mjs";
|
|
5
5
|
import { findVitest, parseVitestReport, runVitest, vitestArguments, vitestRunFailure } from "./tests-step.mjs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "../syntax/ast.mjs";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { scanTranslationSource } from "../../localization/translation-usage.mjs";
|
|
2
|
+
import { createProblem } from "../problem.mjs";
|
|
3
|
+
|
|
4
|
+
//#region ../../packages/core/src/tooling/check/translation-conventions.ts
|
|
5
|
+
/** Application code that renders on the client: everything under `src/web` except setup and test files. */
|
|
6
|
+
const WEB_CLIENT_FILE = /^src\/web\/.+\.[cm]?[jt]sx?$/;
|
|
7
|
+
const SETUP_OR_TEST_FILE = /\.(?:setup|test|spec)\.[cm]?[jt]sx?$/i;
|
|
8
|
+
/**
|
|
9
|
+
* `WL9104`: a translation lookup whose key is only known at runtime.
|
|
10
|
+
*
|
|
11
|
+
* A page ships the translation keys its client code can reach, found by
|
|
12
|
+
* reading the code. A key computed at runtime (`trans(key)`, a translator
|
|
13
|
+
* passed on as a value) defeats that reading, so the page falls back to every
|
|
14
|
+
* group. The fix is a `config.translations` declaration in the page's setup
|
|
15
|
+
* file, which this rule points at.
|
|
16
|
+
*/
|
|
17
|
+
function translationProblems(relativePath, source) {
|
|
18
|
+
if (!WEB_CLIENT_FILE.test(relativePath) || SETUP_OR_TEST_FILE.test(relativePath)) return [];
|
|
19
|
+
return scanTranslationSource(relativePath, source).usage.dynamicSites.map((site) => createProblem({
|
|
20
|
+
code: "WL9104",
|
|
21
|
+
source: "convention",
|
|
22
|
+
severity: "warning",
|
|
23
|
+
message: `Translation key \`${site.text}\` is computed at runtime, so a page that renders it ships every translation group. Declare the keys it uses with \`config.translations\` in the page's setup file.`,
|
|
24
|
+
file: relativePath,
|
|
25
|
+
line: site.line,
|
|
26
|
+
column: site.column
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
//#endregion
|
|
31
|
+
export { translationProblems };
|
|
32
|
+
//# sourceMappingURL=translation-conventions.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translation-conventions.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/check/translation-conventions.ts"],"sourcesContent":["import { scanTranslationSource } from \"../../localization/translation-usage\";\nimport { createProblem, type ToolingProblem } from \"../problem\";\n\n/** Application code that renders on the client: everything under `src/web` except setup and test files. */\nconst WEB_CLIENT_FILE = /^src\\/web\\/.+\\.[cm]?[jt]sx?$/;\nconst SETUP_OR_TEST_FILE = /\\.(?:setup|test|spec)\\.[cm]?[jt]sx?$/i;\n\n/**\n * `WL9104`: a translation lookup whose key is only known at runtime.\n *\n * A page ships the translation keys its client code can reach, found by\n * reading the code. A key computed at runtime (`trans(key)`, a translator\n * passed on as a value) defeats that reading, so the page falls back to every\n * group. The fix is a `config.translations` declaration in the page's setup\n * file, which this rule points at.\n */\nexport function translationProblems(relativePath: string, source: string): ToolingProblem[] {\n if (!WEB_CLIENT_FILE.test(relativePath) || SETUP_OR_TEST_FILE.test(relativePath)) return [];\n\n return scanTranslationSource(relativePath, source).usage.dynamicSites.map((site) =>\n createProblem({\n code: \"WL9104\",\n source: \"convention\",\n severity: \"warning\",\n message:\n `Translation key \\`${site.text}\\` is computed at runtime, so a page that renders it ships every ` +\n \"translation group. Declare the keys it uses with `config.translations` in the page's setup file.\",\n file: relativePath,\n line: site.line,\n column: site.column,\n }),\n );\n}\n"],"mappings":";;;;;AAIA,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;;;;;;;;;;AAW3B,SAAgB,oBAAoB,cAAsB,QAAkC;CAC1F,IAAI,CAAC,gBAAgB,KAAK,YAAY,KAAK,mBAAmB,KAAK,YAAY,GAAG,OAAO,CAAC;CAE1F,OAAO,sBAAsB,cAAc,MAAM,CAAC,CAAC,MAAM,aAAa,KAAK,SACzE,cAAc;EACZ,MAAM;EACN,QAAQ;EACR,UAAU;EACV,SACE,qBAAqB,KAAK,KAAK;EAEjC,MAAM;EACN,MAAM,KAAK;EACX,QAAQ,KAAK;CACf,CAAC,CACH;AACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { WarlockErrorCode } from "../../errors/error-codes.mjs";
|
|
2
|
+
import "../syntax/ast.mjs";
|
|
3
|
+
import "./source-ast.mjs";
|
|
4
|
+
//#region ../../packages/core/src/tooling/check/web-conventions.d.ts
|
|
5
|
+
export type ConventionOptions = {
|
|
6
|
+
componentLineLimit?: number;
|
|
7
|
+
rules?: Partial<Record<WarlockErrorCode, "off" | "warning" | "error">>;
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
//# sourceMappingURL=web-conventions.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-conventions.d.mts","names":["_$______errors_error_codes0.WarlockErrorCode"],"sources":["../../../../../../../../../packages/core/src/tooling/check/web-conventions.ts"],"mappings":";;;;YAaY;EACV;EACA,QAAQ,QACN,OAHQA"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { parentOf, textOf } from "../syntax/ast.mjs";
|
|
2
|
+
import { ancestors, calleeName, isFunctionLike, keyName, literalString, memberName, unwrap, walk } from "./source-ast.mjs";
|
|
3
|
+
|
|
4
|
+
//#region ../../packages/core/src/tooling/check/web-conventions.ts
|
|
5
|
+
/** JSX-returning functions are components; helpers and hook files are not. */
|
|
6
|
+
function webFindings(source, options = {}) {
|
|
7
|
+
if (!/^src\/web\/.*\.tsx$/.test(source.fileName)) return [];
|
|
8
|
+
const findings = [];
|
|
9
|
+
const hooks = /* @__PURE__ */ new Set([
|
|
10
|
+
"useState",
|
|
11
|
+
"useReducer",
|
|
12
|
+
"useEffect",
|
|
13
|
+
"useLayoutEffect"
|
|
14
|
+
]);
|
|
15
|
+
for (const statement of source.body) if (statement.type === "ImportDeclaration" && statement.source.value === "react") {
|
|
16
|
+
for (const specifier of statement.specifiers) if (specifier.type === "ImportSpecifier" && hooks.has(keyName(specifier.imported) ?? "")) hooks.add(specifier.local.name);
|
|
17
|
+
}
|
|
18
|
+
const components = [];
|
|
19
|
+
walk(source, (node) => {
|
|
20
|
+
if (!isFunctionLike(node) || !node.body || ancestors(node).some(isFunctionLike)) return;
|
|
21
|
+
const parent = parentOf(node);
|
|
22
|
+
const name = node.id?.name ?? (parent?.type === "VariableDeclarator" ? keyName(parent.id) : void 0);
|
|
23
|
+
if (name && !/^[A-Z]/.test(name)) return;
|
|
24
|
+
let jsx = false;
|
|
25
|
+
walk(node.body, (child) => {
|
|
26
|
+
if (child.type === "JSXElement" || child.type === "JSXFragment") jsx = true;
|
|
27
|
+
});
|
|
28
|
+
if (jsx) components.push(node);
|
|
29
|
+
}, true);
|
|
30
|
+
const add = (code, node, message) => findings.push({
|
|
31
|
+
code,
|
|
32
|
+
node,
|
|
33
|
+
message,
|
|
34
|
+
severity: "warning"
|
|
35
|
+
});
|
|
36
|
+
const limit = options.componentLineLimit ?? 150;
|
|
37
|
+
if (components.length && source.text.replace(/\r?\n$/, "").split(/\r?\n/).length > limit) add("WL9013", components[0] ?? source, `Component file exceeds ${limit} lines. Split it into smaller components and use-*.ts hooks.`);
|
|
38
|
+
for (const component of components.slice(1)) add("WL9014", component, "More than one component in this file. Move each component to its own file.");
|
|
39
|
+
for (const component of components) {
|
|
40
|
+
if (!isFunctionLike(component) || !component.body) continue;
|
|
41
|
+
const eventNames = /* @__PURE__ */ new Set();
|
|
42
|
+
walk(component.body, (node) => {
|
|
43
|
+
if (node.type === "JSXAttribute" && /^on[A-Z]/.test(keyName(node.name) ?? "") && node.value?.type === "JSXExpressionContainer" && node.value.expression.type === "Identifier") eventNames.add(node.value.expression.name);
|
|
44
|
+
});
|
|
45
|
+
walk(component.body, (node) => {
|
|
46
|
+
if (node.type === "CallExpression" && hooks.has(calleeName(node) ?? "")) add("WL9015", node, "Move component state and effects to a use-*.ts hook file.");
|
|
47
|
+
if (isFunctionLike(node)) {
|
|
48
|
+
const parent = parentOf(node);
|
|
49
|
+
const name = node.id?.name ?? (parent?.type === "VariableDeclarator" ? keyName(parent.id) : void 0);
|
|
50
|
+
const attribute = parent?.type === "JSXExpressionContainer" ? parentOf(parent) : void 0;
|
|
51
|
+
if (/^(?:handle|on)[A-Z]/.test(name ?? "") || eventNames.has(name ?? "") || attribute?.type === "JSXAttribute" && /^on[A-Z]/.test(keyName(attribute.name) ?? "")) add("WL9015", node, "Move this event-handler function to a use-*.ts hook file.");
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
walk(source, (node) => {
|
|
56
|
+
if (node.type !== "JSXOpeningElement" || node.name.type !== "JSXIdentifier") return;
|
|
57
|
+
const tag = node.name.name;
|
|
58
|
+
if (![
|
|
59
|
+
"input",
|
|
60
|
+
"textarea",
|
|
61
|
+
"select"
|
|
62
|
+
].includes(tag)) return;
|
|
63
|
+
const attributes = node.attributes.filter((attribute) => attribute.type === "JSXAttribute");
|
|
64
|
+
const value = (attribute) => attribute.value?.type === "JSXExpressionContainer" ? literalString(attribute.value.expression) : literalString(attribute.value);
|
|
65
|
+
const inputType = attributes.find((attribute) => keyName(attribute.name) === "type");
|
|
66
|
+
const type = inputType ? value(inputType) : void 0;
|
|
67
|
+
if (!source.fileName.startsWith("src/web/design-system/") && (tag === "select" || tag === "input" && [
|
|
68
|
+
"checkbox",
|
|
69
|
+
"radio",
|
|
70
|
+
"date",
|
|
71
|
+
"time",
|
|
72
|
+
"datetime-local"
|
|
73
|
+
].includes(type ?? ""))) add("WL9016", node, "Use a design-system control instead of this native form control.");
|
|
74
|
+
for (const attribute of attributes) {
|
|
75
|
+
const name = keyName(attribute.name);
|
|
76
|
+
if ([
|
|
77
|
+
"required",
|
|
78
|
+
"pattern",
|
|
79
|
+
"min",
|
|
80
|
+
"max",
|
|
81
|
+
"minLength",
|
|
82
|
+
"maxLength"
|
|
83
|
+
].includes(name ?? "") || tag === "input" && name === "type" && type === "email") add("WL9017", attribute, "Move native validation to the shared validation schema and display field errors through the design-system control.");
|
|
84
|
+
}
|
|
85
|
+
}, true);
|
|
86
|
+
return findings;
|
|
87
|
+
}
|
|
88
|
+
/** RequestHandler exports declare their contract through a static responseSchema. */
|
|
89
|
+
function responseSchemaFindings(source) {
|
|
90
|
+
if (!/^src\/app\/.+\/controllers\/.+\.[cm]?tsx?$/.test(source.fileName)) return [];
|
|
91
|
+
const handlerTypes = /* @__PURE__ */ new Set(["RequestHandler"]);
|
|
92
|
+
for (const statement of source.body) if (statement.type === "ImportDeclaration") {
|
|
93
|
+
for (const specifier of statement.specifiers) if (specifier.type === "ImportSpecifier" && keyName(specifier.imported) === "RequestHandler") handlerTypes.add(specifier.local.name);
|
|
94
|
+
}
|
|
95
|
+
const exports = /* @__PURE__ */ new Set();
|
|
96
|
+
const schemas = /* @__PURE__ */ new Set();
|
|
97
|
+
const handlers = [];
|
|
98
|
+
walk(source, (node) => {
|
|
99
|
+
if (node.type === "ExportNamedDeclaration") for (const specifier of node.specifiers) exports.add(keyName(specifier.local) ?? "");
|
|
100
|
+
if (node.type === "ExportDefaultDeclaration" && node.declaration.type === "Identifier") exports.add(node.declaration.name);
|
|
101
|
+
if (ancestors(node).some(isFunctionLike)) return;
|
|
102
|
+
if (node.type === "AssignmentExpression" && node.operator === "=") {
|
|
103
|
+
const left = unwrap(node.left);
|
|
104
|
+
if (left.type === "MemberExpression" && memberName(left) === "responseSchema" && left.object.type === "Identifier" && !["undefined", "null"].includes(textOf(node.right))) schemas.add(left.object.name);
|
|
105
|
+
}
|
|
106
|
+
if (node.type !== "VariableDeclarator" || node.id.type !== "Identifier") return;
|
|
107
|
+
const annotation = node.id.typeAnnotation?.typeAnnotation;
|
|
108
|
+
const initializer = node.init;
|
|
109
|
+
const satisfied = initializer?.type === "TSSatisfiesExpression" ? initializer.typeAnnotation : void 0;
|
|
110
|
+
const type = annotation ?? satisfied;
|
|
111
|
+
if (type?.type !== "TSTypeReference" || !handlerTypes.has(keyName(type.typeName) ?? "")) return;
|
|
112
|
+
handlers.push(node);
|
|
113
|
+
if (initializer?.type === "CallExpression" && initializer.callee.type === "MemberExpression" && initializer.callee.object.type === "Identifier" && initializer.callee.object.name === "Object" && keyName(initializer.callee.property) === "assign" && initializer.arguments.slice(1).some((argument) => argument.type === "ObjectExpression" && argument.properties.some((property) => property.type === "Property" && keyName(property.key) === "responseSchema"))) schemas.add(node.id.name);
|
|
114
|
+
if (ancestors(node).some((parent) => parent.type === "ExportNamedDeclaration")) exports.add(node.id.name);
|
|
115
|
+
}, true);
|
|
116
|
+
return handlers.filter((node) => node.id.type === "Identifier" && exports.has(node.id.name) && !schemas.has(node.id.name)).map((node) => ({
|
|
117
|
+
code: "WL9018",
|
|
118
|
+
node: node.id,
|
|
119
|
+
severity: "warning",
|
|
120
|
+
message: "Exported RequestHandler has no responseSchema. Declare the response body contract for each returned status code."
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
//#endregion
|
|
125
|
+
export { responseSchemaFindings, webFindings };
|
|
126
|
+
//# sourceMappingURL=web-conventions.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-conventions.mjs","names":["ast.parentOf","ast.textOf"],"sources":["../../../../../../../../../packages/core/src/tooling/check/web-conventions.ts"],"sourcesContent":["import * as ast from \"../syntax/ast\";\nimport {\n ancestors,\n calleeName,\n isFunctionLike,\n keyName,\n literalString,\n memberName,\n unwrap,\n walk,\n type SourceFinding,\n} from \"./source-ast\";\n\nexport type ConventionOptions = {\n componentLineLimit?: number;\n rules?: Partial<\n Record<import(\"../../errors/error-codes\").WarlockErrorCode, \"off\" | \"warning\" | \"error\">\n >;\n};\n\n/** JSX-returning functions are components; helpers and hook files are not. */\nexport function webFindings(\n source: ast.SourceFile,\n options: ConventionOptions = {},\n): SourceFinding[] {\n if (!/^src\\/web\\/.*\\.tsx$/.test(source.fileName)) return [];\n const findings: SourceFinding[] = [];\n const hooks = new Set([\"useState\", \"useReducer\", \"useEffect\", \"useLayoutEffect\"]);\n for (const statement of source.body)\n if (statement.type === \"ImportDeclaration\" && statement.source.value === \"react\") {\n for (const specifier of statement.specifiers)\n if (specifier.type === \"ImportSpecifier\" && hooks.has(keyName(specifier.imported) ?? \"\"))\n hooks.add(specifier.local.name);\n }\n const components: ast.Node[] = [];\n walk(\n source,\n (node) => {\n if (!isFunctionLike(node) || !node.body || ancestors(node).some(isFunctionLike)) return;\n const parent = ast.parentOf(node);\n const name =\n node.id?.name ?? (parent?.type === \"VariableDeclarator\" ? keyName(parent.id) : undefined);\n if (name && !/^[A-Z]/.test(name)) return;\n let jsx = false;\n walk(node.body, (child) => {\n if (child.type === \"JSXElement\" || child.type === \"JSXFragment\") jsx = true;\n });\n if (jsx) components.push(node);\n },\n true,\n );\n const add = (code: SourceFinding[\"code\"], node: ast.Node, message: string) =>\n findings.push({ code, node, message, severity: \"warning\" });\n const limit = options.componentLineLimit ?? 150;\n if (components.length && source.text.replace(/\\r?\\n$/, \"\").split(/\\r?\\n/).length > limit)\n add(\n \"WL9013\",\n components[0] ?? source,\n `Component file exceeds ${limit} lines. Split it into smaller components and use-*.ts hooks.`,\n );\n for (const component of components.slice(1))\n add(\n \"WL9014\",\n component,\n \"More than one component in this file. Move each component to its own file.\",\n );\n for (const component of components) {\n if (!isFunctionLike(component) || !component.body) continue;\n const eventNames = new Set<string>();\n walk(component.body, (node) => {\n if (\n node.type === \"JSXAttribute\" &&\n /^on[A-Z]/.test(keyName(node.name) ?? \"\") &&\n node.value?.type === \"JSXExpressionContainer\" &&\n node.value.expression.type === \"Identifier\"\n )\n eventNames.add(node.value.expression.name);\n });\n walk(component.body, (node) => {\n if (node.type === \"CallExpression\" && hooks.has(calleeName(node) ?? \"\"))\n add(\"WL9015\", node, \"Move component state and effects to a use-*.ts hook file.\");\n if (isFunctionLike(node)) {\n const parent = ast.parentOf(node);\n const name =\n node.id?.name ?? (parent?.type === \"VariableDeclarator\" ? keyName(parent.id) : undefined);\n const attribute =\n parent?.type === \"JSXExpressionContainer\" ? ast.parentOf(parent) : undefined;\n if (\n /^(?:handle|on)[A-Z]/.test(name ?? \"\") ||\n eventNames.has(name ?? \"\") ||\n (attribute?.type === \"JSXAttribute\" && /^on[A-Z]/.test(keyName(attribute.name) ?? \"\"))\n )\n add(\"WL9015\", node, \"Move this event-handler function to a use-*.ts hook file.\");\n }\n });\n }\n walk(\n source,\n (node) => {\n if (node.type !== \"JSXOpeningElement\" || node.name.type !== \"JSXIdentifier\") return;\n const tag = node.name.name;\n if (![\"input\", \"textarea\", \"select\"].includes(tag)) return;\n const attributes = node.attributes.filter((attribute) => attribute.type === \"JSXAttribute\");\n const value = (attribute: ast.JSXAttribute) =>\n attribute.value?.type === \"JSXExpressionContainer\"\n ? literalString(attribute.value.expression)\n : literalString(attribute.value);\n const inputType = attributes.find((attribute) => keyName(attribute.name) === \"type\");\n const type = inputType ? value(inputType) : undefined;\n if (\n !source.fileName.startsWith(\"src/web/design-system/\") &&\n (tag === \"select\" ||\n (tag === \"input\" &&\n [\"checkbox\", \"radio\", \"date\", \"time\", \"datetime-local\"].includes(type ?? \"\")))\n )\n add(\"WL9016\", node, \"Use a design-system control instead of this native form control.\");\n for (const attribute of attributes) {\n const name = keyName(attribute.name);\n if (\n [\"required\", \"pattern\", \"min\", \"max\", \"minLength\", \"maxLength\"].includes(name ?? \"\") ||\n (tag === \"input\" && name === \"type\" && type === \"email\")\n )\n add(\n \"WL9017\",\n attribute,\n \"Move native validation to the shared validation schema and display field errors through the design-system control.\",\n );\n }\n },\n true,\n );\n return findings;\n}\n\n/** RequestHandler exports declare their contract through a static responseSchema. */\nexport function responseSchemaFindings(source: ast.SourceFile): SourceFinding[] {\n if (!/^src\\/app\\/.+\\/controllers\\/.+\\.[cm]?tsx?$/.test(source.fileName)) return [];\n const handlerTypes = new Set([\"RequestHandler\"]);\n for (const statement of source.body)\n if (statement.type === \"ImportDeclaration\")\n for (const specifier of statement.specifiers)\n if (\n specifier.type === \"ImportSpecifier\" &&\n keyName(specifier.imported) === \"RequestHandler\"\n )\n handlerTypes.add(specifier.local.name);\n const exports = new Set<string>();\n const schemas = new Set<string>();\n const handlers: ast.VariableDeclarator[] = [];\n walk(\n source,\n (node) => {\n if (node.type === \"ExportNamedDeclaration\")\n for (const specifier of node.specifiers) exports.add(keyName(specifier.local) ?? \"\");\n if (node.type === \"ExportDefaultDeclaration\" && node.declaration.type === \"Identifier\")\n exports.add(node.declaration.name);\n if (ancestors(node).some(isFunctionLike)) return;\n if (node.type === \"AssignmentExpression\" && node.operator === \"=\") {\n const left = unwrap(node.left);\n if (\n left.type === \"MemberExpression\" &&\n memberName(left) === \"responseSchema\" &&\n left.object.type === \"Identifier\" &&\n ![\"undefined\", \"null\"].includes(ast.textOf(node.right))\n )\n schemas.add(left.object.name);\n }\n if (node.type !== \"VariableDeclarator\" || node.id.type !== \"Identifier\") return;\n const annotation = node.id.typeAnnotation?.typeAnnotation;\n const initializer = node.init;\n const satisfied =\n initializer?.type === \"TSSatisfiesExpression\" ? initializer.typeAnnotation : undefined;\n const type = annotation ?? satisfied;\n if (type?.type !== \"TSTypeReference\" || !handlerTypes.has(keyName(type.typeName) ?? \"\"))\n return;\n handlers.push(node);\n if (\n initializer?.type === \"CallExpression\" &&\n initializer.callee.type === \"MemberExpression\" &&\n initializer.callee.object.type === \"Identifier\" &&\n initializer.callee.object.name === \"Object\" &&\n keyName(initializer.callee.property) === \"assign\" &&\n initializer.arguments\n .slice(1)\n .some(\n (argument) =>\n argument.type === \"ObjectExpression\" &&\n argument.properties.some(\n (property) =>\n property.type === \"Property\" && keyName(property.key) === \"responseSchema\",\n ),\n )\n )\n schemas.add(node.id.name);\n if (ancestors(node).some((parent) => parent.type === \"ExportNamedDeclaration\"))\n exports.add(node.id.name);\n },\n true,\n );\n return handlers\n .filter(\n (node) =>\n node.id.type === \"Identifier\" && exports.has(node.id.name) && !schemas.has(node.id.name),\n )\n .map<SourceFinding>((node) => ({\n code: \"WL9018\",\n node: node.id,\n severity: \"warning\",\n message:\n \"Exported RequestHandler has no responseSchema. Declare the response body contract for each returned status code.\",\n }));\n}\n"],"mappings":"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"}
|
package/esm/tooling/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AGENTS_MD_END, AGENTS_MD_FILE, AGENTS_MD_START, upsertGeneratedSection } from "./agents-md/agents-md-markers.mjs";
|
|
2
|
-
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/inspect-report.types.mjs";
|
|
2
|
+
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/inspect-report.types.mjs";
|
|
3
3
|
import { InstalledSkill, listInstalledSkills, parseSkillFrontMatter, shortSkillLine } from "./agents-md/installed-skills.mjs";
|
|
4
4
|
import { AgentsMdWriteStatus, WriteAgentsMdOptions, WriteAgentsMdResult, writeAgentsMd } from "./agents-md/write-agents-md.mjs";
|
|
5
5
|
import { AgentsMdRefresher, AgentsMdRefresherOptions, createAgentsMdRefresher } from "./agents-md/agents-md-refresher.mjs";
|
|
@@ -7,9 +7,11 @@ import { RenderAgentsMdOptions, listAppModules, renderAgentsMdSection } from "./
|
|
|
7
7
|
import { BOARD_DIRECTORY, BOARD_STATES, BOARD_TRANSITIONS, BOARD_VERDICT_LINES, BoardHistoryEntry, BoardInbox, BoardItem, BoardMessage, BoardState, BoardStatus, BoardVerdict, isBoardState, isBoardVerdict } from "./board/board.types.mjs";
|
|
8
8
|
import { AddBoardItemInput, InitBoardResult, MoveBoardItemOptions, SendBoardMessageInput, SendBoardMessageResult, WatchBoardOptions, WatchBoardResult, addBoardItem, assertAgentName, assertBoardTransition, boardSlug, gitignoreCoversBoard, initBoard, listBoardItems, listBoardMessages, moveBoardItem, nextBoardStates, readBoardCursor, readBoardItem, readBoardStatus, sendBoardMessage, watchBoard, writeBoardCursor } from "./board/board.mjs";
|
|
9
9
|
import { BoardMessageFields, ParsedBoardMessage, formatBoardMessage, parseBoardMessage } from "./board/board-message.mjs";
|
|
10
|
+
import { ProblemFix } from "./check/fixes.mjs";
|
|
10
11
|
import { ProblemInput, ProblemSource, ToolingProblem, createProblem } from "./problem.mjs";
|
|
11
12
|
import { GitResult, GitRunner, listChangedFiles, runGit } from "./check/changed-files.mjs";
|
|
12
13
|
import { CHECK_EXIT_CODES, CHECK_STEPS, CheckExitCode, CheckReport, CheckStep, CheckStepName, CheckStepStatus, checkExitCode } from "./check/check-report.types.mjs";
|
|
14
|
+
import { ConventionOptions } from "./check/web-conventions.mjs";
|
|
13
15
|
import { checkFileConventions, checkTsconfigConventions, isAutoLoadedFile, runConventions } from "./check/conventions-step.mjs";
|
|
14
16
|
import { MIN_NODE_VERSION, checkNodeVersion } from "./check/environment-step.mjs";
|
|
15
17
|
import { LintOutcome, runLint } from "./check/lint-step.mjs";
|
|
@@ -17,6 +19,8 @@ import { DEFAULT_TYPECHECK_BUILD_INFO, TypecheckOptions, TypecheckResult, diagno
|
|
|
17
19
|
import { VitestRun, VitestRunner, findVitest, parseVitestReport, runVitest } from "./check/tests-step.mjs";
|
|
18
20
|
import { CheckOptions, TypecheckRunner, runCheck } from "./check/run-check.mjs";
|
|
19
21
|
import { RunTestsOptions, TestRunReport, runTests, testRunArguments } from "./check/run-tests.mjs";
|
|
22
|
+
import { affectedFiles } from "./check/affected-files.mjs";
|
|
23
|
+
import "./check/index.mjs";
|
|
20
24
|
import { DEV_SERVER_STATE_FILE, DevServerState, parseDevServerState, readDevServerState, removeDevServerState, updateDevServerState, writeDevServerState } from "./dev-state/dev-server-state.mjs";
|
|
21
25
|
import { ConnectDevtoolsOptions, DEFAULT_DEVTOOLS_PATH, DevtoolsClient, DevtoolsEndpoint, DevtoolsFetch, DevtoolsPhaseRecord, DevtoolsRequestRecord, DevtoolsRequestSummaryRecord, connectDevtools, parseRequestRecord, parseRequestSummary, resolveDevServerEndpoint } from "./devtools/devtools-client.mjs";
|
|
22
26
|
import { GeneratorArgsOptions, GeneratorSpec, MAKE_GENERATORS, MAKE_GENERATOR_FLAGS, MakeGenerator, buildGeneratorArgs, isMakeGenerator } from "./generate/generator-spec.mjs";
|
|
@@ -29,6 +33,7 @@ import { AppModuleImporter } from "./inspect/collect-packages.mjs";
|
|
|
29
33
|
import { InspectOptions, inspectApp, isInspectSection, parseInspectSections } from "./inspect/inspect-app.mjs";
|
|
30
34
|
import { InspectBootResult, bootForInspect, inspectOptionsFromBoot } from "./inspect/boot-for-inspect.mjs";
|
|
31
35
|
import { INSPECT_REPORT_JSON_SCHEMA } from "./inspect/inspect-report.schema.mjs";
|
|
36
|
+
import { ExplainedFile, explainFile } from "./inspect/explain-file.mjs";
|
|
32
37
|
import "./inspect/index.mjs";
|
|
33
38
|
import { DbSchema, DbSchemaColumn, DbSchemaTable, buildDbSchema } from "./mcp/db-schema.mjs";
|
|
34
39
|
import { DOCS_CORPUS_GLOBS, DocsCorpus, DocsSearchHit, DocsSection, loadDocsCorpus, readDocsFile, searchDocs, searchTerms, splitSections } from "./mcp/docs-search.mjs";
|
|
@@ -39,4 +44,4 @@ import { AiToolsServeModule, MCP_INSTALL_HINT, ServeToolContract, isAiToolsServe
|
|
|
39
44
|
import { StartWarlockMcpServerOptions, WarlockMcpServerHandle, WarlockMcpTransport, isLoopbackHost, resolveMcpTransport, startWarlockMcpServer, toServeContract } from "./mcp/start-mcp-server.mjs";
|
|
40
45
|
import { TRACE_SCHEMA_VERSION, TraceMiddleware, TraceQuery, TraceReport, TraceValidation } from "./trace/trace-report.types.mjs";
|
|
41
46
|
import { BuildTraceReportInput, TRACE_BODY_LIMIT, TRACE_REQUEST_ID_HEADER, TraceRequestOptions, TracedResponse, buildTraceReport, readResponseBody, redactHeaders, resolveTraceUrl, traceRequest } from "./trace/trace-request.mjs";
|
|
42
|
-
export { AGENTS_MD_END, AGENTS_MD_FILE, AGENTS_MD_START, type AddBoardItemInput, type AgentsMdRefresher, type AgentsMdRefresherOptions, type AgentsMdWriteStatus, type AiToolsServeModule, type AppModuleImporter, type ApplyGenerationOptions, BOARD_DIRECTORY, BOARD_STATES, BOARD_TRANSITIONS, BOARD_VERDICT_LINES, type BoardHistoryEntry, type BoardInbox, type BoardItem, type BoardMessage, type BoardMessageFields, type BoardState, type BoardStatus, type BoardVerdict, type BuildTraceReportInput, CHECK_EXIT_CODES, CHECK_STEPS, type CheckExitCode, type CheckOptions, type CheckReport, type CheckStep, type CheckStepName, type CheckStepStatus, type CliInvocation, type CliRun, type CliRunner, ConnectDevtoolsOptions, type CreateMcpContextOptions, DEFAULT_DEVTOOLS_PATH, DEFAULT_GENERATION_TIMEOUT_MS, DEFAULT_TYPECHECK_BUILD_INFO, DEV_SERVER_STATE_FILE, DIFF_CONTEXT_LINES, DOCS_CORPUS_GLOBS, type DbSchema, type DbSchemaColumn, type DbSchemaTable, DevServerState, DevtoolsClient, DevtoolsEndpoint, DevtoolsFetch, DevtoolsPhaseRecord, DevtoolsRequestRecord, DevtoolsRequestSummaryRecord, type DocsCorpus, type DocsSearchHit, type DocsSection, EventRecorder, type GeneratedFile, type GenerationBackend, type GenerationPlan, type GenerationPlanOptions, type GeneratorArgsOptions, type GeneratorSpec, type GitResult, type GitRunner, INSPECT_REPORT_JSON_SCHEMA, INSPECT_SCHEMA_VERSION, INSPECT_SECTIONS, type InitBoardResult, type InspectBootResult, InspectConfigKey, InspectEvent, InspectJob, InspectModel, InspectModelColumn, type InspectModelModule, InspectModelRelation, type InspectOptions, InspectPackage, InspectPage, InspectParameter, InspectReport, InspectResource, InspectRoute, InspectRouteAuth, InspectRouteLogging, InspectRouteRateLimit, InspectSchedule, InspectSection, InspectWarning, type InstalledSkill, JsonSchema, type LintOutcome, MAKE_GENERATORS, MAKE_GENERATOR_FLAGS, MAX_FILE_DIFF_BYTES, MCP_INSTALL_HINT, MCP_MAKE_GENERATORS, MIN_NODE_VERSION, type MakeGenerator, type McpInputProperty, type McpInputSchema, type MoveBoardItemOptions, type ParsedBoardMessage, type ProblemInput, type ProblemSource, type RecordedListener, type RenderAgentsMdOptions, type RunTestsOptions, type SandboxBackendOptions, type SendBoardMessageInput, type SendBoardMessageResult, type ServeToolContract, type StartWarlockMcpServerOptions, TRACE_BODY_LIMIT, TRACE_REQUEST_ID_HEADER, TRACE_SCHEMA_VERSION, type TestRunReport, type ToolingProblem, TraceMiddleware, TraceQuery, TraceReport, type TraceRequestOptions, TraceValidation, type TracedResponse, type TypecheckOptions, type TypecheckResult, type TypecheckRunner, type UnifiedDiffInput, type VitestRun, type VitestRunner, type WarlockMcpContext, type WarlockMcpServerHandle, type WarlockMcpTool, type WarlockMcpTransport, type WatchBoardOptions, type WatchBoardResult, type WriteAgentsMdOptions, type WriteAgentsMdResult, addBoardItem, applyGeneration, assertAgentName, assertBoardTransition, boardSlug, bootForInspect, buildDbSchema, buildGeneratorArgs, buildTraceReport, checkExitCode, checkFileConventions, checkNodeVersion, checkTsconfigConventions, connectDevtools, createAgentsMdRefresher, createMcpContext, createProblem, createWarlockMcpTools, describeRun, describeToolError, diagnosticToProblem, directImporters, findVitest, formatBoardMessage, gitignoreCoversBoard, groupListeners, initBoard, inputSchema, inspectApp, inspectOptionsFromBoot, isAiToolsServeModule, isAutoLoadedFile, isBoardState, isBoardVerdict, isInspectSection, isLoopbackHost, isMakeGenerator, listAppModules, listBoardItems, listBoardMessages, listChangedFiles, listInstalledSkills, loadAiToolsServe, loadDocsCorpus, makeSpecFromInput, moveBoardItem, nextBoardStates, parseBoardMessage, parseDevServerState, parseInspectSections, parseRequestRecord, parseRequestSummary, parseSkillFrontMatter, parseVitestReport, readBoardCursor, readBoardItem, readBoardStatus, readDevServerState, readDocsFile, readResponseBody, redactHeaders, removeDevServerState, renderAgentsMdSection, resolveCliEntry, resolveDevServerEndpoint, resolveMcpTransport, resolveTraceUrl, runCheck, runConventions, runGit, runLint, runTests, runTypecheck, runVitest, sandboxBackend, searchDocs, searchTerms, sendBoardMessage, shortSkillLine, spawnCli, splitSections, startWarlockMcpServer, testRunArguments, toServeContract, toStandardSchema, traceRequest, unifiedDiff, updateDevServerState, upsertGeneratedSection, validateToolInput, watchBoard, writeAgentsMd, writeBoardCursor, writeDevServerState };
|
|
47
|
+
export { AGENTS_MD_END, AGENTS_MD_FILE, AGENTS_MD_START, type AddBoardItemInput, type AgentsMdRefresher, type AgentsMdRefresherOptions, type AgentsMdWriteStatus, type AiToolsServeModule, type AppModuleImporter, type ApplyGenerationOptions, BOARD_DIRECTORY, BOARD_STATES, BOARD_TRANSITIONS, BOARD_VERDICT_LINES, type BoardHistoryEntry, type BoardInbox, type BoardItem, type BoardMessage, type BoardMessageFields, type BoardState, type BoardStatus, type BoardVerdict, type BuildTraceReportInput, CHECK_EXIT_CODES, CHECK_STEPS, type CheckExitCode, type CheckOptions, type CheckReport, type CheckStep, type CheckStepName, type CheckStepStatus, type CliInvocation, type CliRun, type CliRunner, ConnectDevtoolsOptions, type ConventionOptions, type CreateMcpContextOptions, DEFAULT_DEVTOOLS_PATH, DEFAULT_GENERATION_TIMEOUT_MS, DEFAULT_TYPECHECK_BUILD_INFO, DEV_SERVER_STATE_FILE, DIFF_CONTEXT_LINES, DOCS_CORPUS_GLOBS, type DbSchema, type DbSchemaColumn, type DbSchemaTable, DevServerState, DevtoolsClient, DevtoolsEndpoint, DevtoolsFetch, DevtoolsPhaseRecord, DevtoolsRequestRecord, DevtoolsRequestSummaryRecord, type DocsCorpus, type DocsSearchHit, type DocsSection, EventRecorder, type ExplainedFile, type GeneratedFile, type GenerationBackend, type GenerationPlan, type GenerationPlanOptions, type GeneratorArgsOptions, type GeneratorSpec, type GitResult, type GitRunner, INSPECT_REPORT_JSON_SCHEMA, INSPECT_SCHEMA_VERSION, INSPECT_SECTIONS, type InitBoardResult, 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, type InstalledSkill, JsonSchema, type LintOutcome, MAKE_GENERATORS, MAKE_GENERATOR_FLAGS, MAX_FILE_DIFF_BYTES, MCP_INSTALL_HINT, MCP_MAKE_GENERATORS, MIN_NODE_VERSION, type MakeGenerator, type McpInputProperty, type McpInputSchema, type MoveBoardItemOptions, type ParsedBoardMessage, type ProblemFix, type ProblemInput, type ProblemSource, type RecordedListener, type RenderAgentsMdOptions, type RunTestsOptions, type SandboxBackendOptions, type SendBoardMessageInput, type SendBoardMessageResult, type ServeToolContract, type StartWarlockMcpServerOptions, TRACE_BODY_LIMIT, TRACE_REQUEST_ID_HEADER, TRACE_SCHEMA_VERSION, type TestRunReport, type ToolingProblem, TraceMiddleware, TraceQuery, TraceReport, type TraceRequestOptions, TraceValidation, type TracedResponse, type TypecheckOptions, type TypecheckResult, type TypecheckRunner, type UnifiedDiffInput, type VitestRun, type VitestRunner, type WarlockMcpContext, type WarlockMcpServerHandle, type WarlockMcpTool, type WarlockMcpTransport, type WatchBoardOptions, type WatchBoardResult, type WriteAgentsMdOptions, type WriteAgentsMdResult, addBoardItem, affectedFiles, applyGeneration, assertAgentName, assertBoardTransition, boardSlug, bootForInspect, buildDbSchema, buildGeneratorArgs, buildTraceReport, checkExitCode, checkFileConventions, checkNodeVersion, checkTsconfigConventions, connectDevtools, createAgentsMdRefresher, createMcpContext, createProblem, createWarlockMcpTools, describeRun, describeToolError, diagnosticToProblem, directImporters, explainFile, findVitest, formatBoardMessage, gitignoreCoversBoard, groupListeners, initBoard, inputSchema, inspectApp, inspectOptionsFromBoot, isAiToolsServeModule, isAutoLoadedFile, isBoardState, isBoardVerdict, isInspectSection, isLoopbackHost, isMakeGenerator, listAppModules, listBoardItems, listBoardMessages, listChangedFiles, listInstalledSkills, loadAiToolsServe, loadDocsCorpus, makeSpecFromInput, moveBoardItem, nextBoardStates, parseBoardMessage, parseDevServerState, parseInspectSections, parseRequestRecord, parseRequestSummary, parseSkillFrontMatter, parseVitestReport, readBoardCursor, readBoardItem, readBoardStatus, readDevServerState, readDocsFile, readResponseBody, redactHeaders, removeDevServerState, renderAgentsMdSection, resolveCliEntry, resolveDevServerEndpoint, resolveMcpTransport, resolveTraceUrl, runCheck, runConventions, runGit, runLint, runTests, runTypecheck, runVitest, sandboxBackend, searchDocs, searchTerms, sendBoardMessage, shortSkillLine, spawnCli, splitSections, startWarlockMcpServer, testRunArguments, toServeContract, toStandardSchema, traceRequest, unifiedDiff, updateDevServerState, upsertGeneratedSection, validateToolInput, watchBoard, writeAgentsMd, writeBoardCursor, writeDevServerState };
|
package/esm/tooling/index.mjs
CHANGED
|
@@ -11,15 +11,17 @@ import { formatBoardMessage, parseBoardMessage } from "./board/board-message.mjs
|
|
|
11
11
|
import { addBoardItem, assertAgentName, assertBoardTransition, boardSlug, gitignoreCoversBoard, initBoard, listBoardItems, listBoardMessages, moveBoardItem, nextBoardStates, readBoardCursor, readBoardItem, readBoardStatus, sendBoardMessage, watchBoard, writeBoardCursor } from "./board/board.mjs";
|
|
12
12
|
import { CHECK_EXIT_CODES, CHECK_STEPS, checkExitCode } from "./check/check-report.types.mjs";
|
|
13
13
|
import { createProblem } from "./problem.mjs";
|
|
14
|
+
import { checkFileConventions, checkTsconfigConventions, isAutoLoadedFile, runConventions } from "./check/conventions-step.mjs";
|
|
15
|
+
import { affectedFiles } from "./check/affected-files.mjs";
|
|
14
16
|
import { DEFAULT_TYPECHECK_BUILD_INFO, diagnosticToProblem, directImporters, runTypecheck } from "./typecheck/run-typecheck.mjs";
|
|
15
17
|
import { listChangedFiles, runGit } from "./check/changed-files.mjs";
|
|
16
|
-
import { checkFileConventions, checkTsconfigConventions, isAutoLoadedFile, runConventions } from "./check/conventions-step.mjs";
|
|
17
18
|
import { MIN_NODE_VERSION, checkNodeVersion } from "./check/environment-step.mjs";
|
|
18
19
|
import { runLint } from "./check/lint-step.mjs";
|
|
19
20
|
import { findVitest, parseVitestReport, runVitest } from "./check/tests-step.mjs";
|
|
20
21
|
import { runCheck } from "./check/run-check.mjs";
|
|
21
22
|
import { DEV_SERVER_STATE_FILE, parseDevServerState, readDevServerState, removeDevServerState, updateDevServerState, writeDevServerState } from "./dev-state/dev-server-state.mjs";
|
|
22
23
|
import { DEFAULT_DEVTOOLS_PATH, connectDevtools, parseRequestRecord, parseRequestSummary, resolveDevServerEndpoint } from "./devtools/devtools-client.mjs";
|
|
24
|
+
import { explainFile } from "./inspect/explain-file.mjs";
|
|
23
25
|
import { runTests, testRunArguments } from "./check/run-tests.mjs";
|
|
24
26
|
import { MAKE_GENERATORS, MAKE_GENERATOR_FLAGS, buildGeneratorArgs, isMakeGenerator } from "./generate/generator-spec.mjs";
|
|
25
27
|
import { DEFAULT_GENERATION_TIMEOUT_MS, describeRun, resolveCliEntry, spawnCli } from "./generate/run-cli.mjs";
|
|
@@ -42,4 +44,4 @@ import "./inspect/index.mjs";
|
|
|
42
44
|
import "./mcp/index.mjs";
|
|
43
45
|
import "./typecheck/index.mjs";
|
|
44
46
|
|
|
45
|
-
export { AGENTS_MD_END, AGENTS_MD_FILE, AGENTS_MD_START, BOARD_DIRECTORY, BOARD_STATES, BOARD_TRANSITIONS, BOARD_VERDICT_LINES, CHECK_EXIT_CODES, CHECK_STEPS, DEFAULT_DEVTOOLS_PATH, DEFAULT_GENERATION_TIMEOUT_MS, DEFAULT_TYPECHECK_BUILD_INFO, DEV_SERVER_STATE_FILE, DIFF_CONTEXT_LINES, DOCS_CORPUS_GLOBS, EventRecorder, INSPECT_REPORT_JSON_SCHEMA, INSPECT_SCHEMA_VERSION, INSPECT_SECTIONS, MAKE_GENERATORS, MAKE_GENERATOR_FLAGS, MAX_FILE_DIFF_BYTES, MCP_INSTALL_HINT, MCP_MAKE_GENERATORS, MIN_NODE_VERSION, TRACE_BODY_LIMIT, TRACE_REQUEST_ID_HEADER, TRACE_SCHEMA_VERSION, addBoardItem, applyGeneration, assertAgentName, assertBoardTransition, boardSlug, bootForInspect, buildDbSchema, buildGeneratorArgs, buildTraceReport, checkExitCode, checkFileConventions, checkNodeVersion, checkTsconfigConventions, connectDevtools, createAgentsMdRefresher, createMcpContext, createProblem, createWarlockMcpTools, describeRun, describeToolError, diagnosticToProblem, directImporters, findVitest, formatBoardMessage, gitignoreCoversBoard, groupListeners, initBoard, inputSchema, inspectApp, inspectOptionsFromBoot, isAiToolsServeModule, isAutoLoadedFile, isBoardState, isBoardVerdict, isInspectSection, isLoopbackHost, isMakeGenerator, listAppModules, listBoardItems, listBoardMessages, listChangedFiles, listInstalledSkills, loadAiToolsServe, loadDocsCorpus, makeSpecFromInput, moveBoardItem, nextBoardStates, parseBoardMessage, parseDevServerState, parseInspectSections, parseRequestRecord, parseRequestSummary, parseSkillFrontMatter, parseVitestReport, readBoardCursor, readBoardItem, readBoardStatus, readDevServerState, readDocsFile, readResponseBody, redactHeaders, removeDevServerState, renderAgentsMdSection, resolveCliEntry, resolveDevServerEndpoint, resolveMcpTransport, resolveTraceUrl, runCheck, runConventions, runGit, runLint, runTests, runTypecheck, runVitest, sandboxBackend, searchDocs, searchTerms, sendBoardMessage, shortSkillLine, spawnCli, splitSections, startWarlockMcpServer, testRunArguments, toServeContract, toStandardSchema, traceRequest, unifiedDiff, updateDevServerState, upsertGeneratedSection, validateToolInput, watchBoard, writeAgentsMd, writeBoardCursor, writeDevServerState };
|
|
47
|
+
export { AGENTS_MD_END, AGENTS_MD_FILE, AGENTS_MD_START, BOARD_DIRECTORY, BOARD_STATES, BOARD_TRANSITIONS, BOARD_VERDICT_LINES, CHECK_EXIT_CODES, CHECK_STEPS, DEFAULT_DEVTOOLS_PATH, DEFAULT_GENERATION_TIMEOUT_MS, DEFAULT_TYPECHECK_BUILD_INFO, DEV_SERVER_STATE_FILE, DIFF_CONTEXT_LINES, DOCS_CORPUS_GLOBS, EventRecorder, INSPECT_REPORT_JSON_SCHEMA, INSPECT_SCHEMA_VERSION, INSPECT_SECTIONS, MAKE_GENERATORS, MAKE_GENERATOR_FLAGS, MAX_FILE_DIFF_BYTES, MCP_INSTALL_HINT, MCP_MAKE_GENERATORS, MIN_NODE_VERSION, TRACE_BODY_LIMIT, TRACE_REQUEST_ID_HEADER, TRACE_SCHEMA_VERSION, addBoardItem, affectedFiles, applyGeneration, assertAgentName, assertBoardTransition, boardSlug, bootForInspect, buildDbSchema, buildGeneratorArgs, buildTraceReport, checkExitCode, checkFileConventions, checkNodeVersion, checkTsconfigConventions, connectDevtools, createAgentsMdRefresher, createMcpContext, createProblem, createWarlockMcpTools, describeRun, describeToolError, diagnosticToProblem, directImporters, explainFile, findVitest, formatBoardMessage, gitignoreCoversBoard, groupListeners, initBoard, inputSchema, inspectApp, inspectOptionsFromBoot, isAiToolsServeModule, isAutoLoadedFile, isBoardState, isBoardVerdict, isInspectSection, isLoopbackHost, isMakeGenerator, listAppModules, listBoardItems, listBoardMessages, listChangedFiles, listInstalledSkills, loadAiToolsServe, loadDocsCorpus, makeSpecFromInput, moveBoardItem, nextBoardStates, parseBoardMessage, parseDevServerState, parseInspectSections, parseRequestRecord, parseRequestSummary, parseSkillFrontMatter, parseVitestReport, readBoardCursor, readBoardItem, readBoardStatus, readDevServerState, readDocsFile, readResponseBody, redactHeaders, removeDevServerState, renderAgentsMdSection, resolveCliEntry, resolveDevServerEndpoint, resolveMcpTransport, resolveTraceUrl, runCheck, runConventions, runGit, runLint, runTests, runTypecheck, runVitest, sandboxBackend, searchDocs, searchTerms, sendBoardMessage, shortSkillLine, spawnCli, splitSections, startWarlockMcpServer, testRunArguments, toServeContract, toStandardSchema, traceRequest, unifiedDiff, updateDevServerState, upsertGeneratedSection, validateToolInput, watchBoard, writeAgentsMd, writeBoardCursor, writeDevServerState };
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { forEachChild } from "../syntax/ast.mjs";
|
|
2
|
+
import { isConfigFile, isEventFile, isLocaleFile, isMainFile, isRouteFile, isWorkerFile } from "../../dev-server/special-file-patterns.mjs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
5
|
+
import { readTsconfig, resolvePathAlias } from "get-tsconfig";
|
|
6
|
+
import { parseSync } from "oxc-parser";
|
|
7
|
+
|
|
8
|
+
//#region ../../packages/core/src/tooling/inspect/collect-files.ts
|
|
9
|
+
const CODE = /\.(?:[cm]?[jt]s|[jt]sx)$/;
|
|
10
|
+
const EXTENSIONS = [
|
|
11
|
+
".ts",
|
|
12
|
+
".tsx",
|
|
13
|
+
".mts",
|
|
14
|
+
".cts",
|
|
15
|
+
".js",
|
|
16
|
+
".jsx",
|
|
17
|
+
".mjs",
|
|
18
|
+
".cjs",
|
|
19
|
+
".d.ts"
|
|
20
|
+
];
|
|
21
|
+
function projectFile(cwd, file) {
|
|
22
|
+
return path.relative(cwd, path.resolve(cwd, file)).split(path.sep).join("/");
|
|
23
|
+
}
|
|
24
|
+
/** Infer a role from file names and the framework's directory conventions. */
|
|
25
|
+
function fileRole(file) {
|
|
26
|
+
const stem = path.posix.basename(file).replace(CODE, "");
|
|
27
|
+
if (/(?:^|\.)(?:spec|test)$/.test(stem)) return "spec";
|
|
28
|
+
if (file.endsWith(".d.ts")) return "type";
|
|
29
|
+
if (isConfigFile(file)) return "config";
|
|
30
|
+
if (isRouteFile(file)) return "routes";
|
|
31
|
+
if (isMainFile(file)) return "main";
|
|
32
|
+
if (isWorkerFile(file)) return "worker";
|
|
33
|
+
if (isEventFile(file)) return "event";
|
|
34
|
+
if (isLocaleFile(file)) return "locale";
|
|
35
|
+
for (const role of [
|
|
36
|
+
"routes",
|
|
37
|
+
"page",
|
|
38
|
+
"setup",
|
|
39
|
+
"layout",
|
|
40
|
+
"root"
|
|
41
|
+
]) if (stem === role || stem.endsWith(`.${role}`)) return role;
|
|
42
|
+
for (const role of [
|
|
43
|
+
"controller",
|
|
44
|
+
"service",
|
|
45
|
+
"repository",
|
|
46
|
+
"model",
|
|
47
|
+
"migration",
|
|
48
|
+
"schema",
|
|
49
|
+
"resource",
|
|
50
|
+
"hook",
|
|
51
|
+
"component",
|
|
52
|
+
"util",
|
|
53
|
+
"type",
|
|
54
|
+
"config"
|
|
55
|
+
]) if (stem.endsWith(`.${role}`) || file.split("/").includes(role === "repository" ? "repositories" : `${role}s`)) return role;
|
|
56
|
+
if (file.startsWith("src/config/")) return "config";
|
|
57
|
+
if (file.split("/").includes("utils")) return "util";
|
|
58
|
+
if (/^use[A-Z]/.test(stem)) return "hook";
|
|
59
|
+
if (/\.tsx$|\.jsx$/.test(file)) return "component";
|
|
60
|
+
return "source";
|
|
61
|
+
}
|
|
62
|
+
function bindingNames(node) {
|
|
63
|
+
if (node.type === "Identifier") return [node.name];
|
|
64
|
+
if (node.type === "ObjectPattern") return node.properties.flatMap((property) => bindingNames(property.type === "RestElement" ? property.argument : property.value));
|
|
65
|
+
if (node.type === "ArrayPattern") return node.elements.flatMap((element) => element ? bindingNames(element) : []);
|
|
66
|
+
if (node.type === "AssignmentPattern") return bindingNames(node.left);
|
|
67
|
+
if (node.type === "RestElement") return bindingNames(node.argument);
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
/** Read each source module once; never import or execute application code. */
|
|
71
|
+
function collectFiles(cwd, warnings = []) {
|
|
72
|
+
cwd = path.resolve(cwd);
|
|
73
|
+
const paths = [];
|
|
74
|
+
const scan = (directory) => {
|
|
75
|
+
if (!existsSync(directory)) return;
|
|
76
|
+
try {
|
|
77
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
78
|
+
const file = path.join(directory, entry.name);
|
|
79
|
+
if (entry.isDirectory()) scan(file);
|
|
80
|
+
else if (entry.isFile()) paths.push(file);
|
|
81
|
+
}
|
|
82
|
+
} catch (error) {
|
|
83
|
+
warnings.push({
|
|
84
|
+
code: null,
|
|
85
|
+
source: projectFile(cwd, directory),
|
|
86
|
+
message: String(error)
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
scan(path.join(cwd, "src"));
|
|
91
|
+
paths.sort();
|
|
92
|
+
const known = new Set(paths);
|
|
93
|
+
let tsconfig;
|
|
94
|
+
try {
|
|
95
|
+
if (existsSync(path.join(cwd, "tsconfig.json"))) tsconfig = readTsconfig(path.join(cwd, "tsconfig.json"), { typescriptVersion: false });
|
|
96
|
+
} catch (error) {
|
|
97
|
+
warnings.push({
|
|
98
|
+
code: null,
|
|
99
|
+
source: "tsconfig.json",
|
|
100
|
+
message: String(error)
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
const probe = (base) => {
|
|
104
|
+
const extension = path.extname(base);
|
|
105
|
+
const stem = /\.[cm]?jsx?$/.test(extension) ? base.slice(0, -extension.length) : base;
|
|
106
|
+
const candidates = stem !== base ? EXTENSIONS.map((ext) => stem + ext) : [];
|
|
107
|
+
candidates.push(base, ...EXTENSIONS.map((ext) => base + ext), ...EXTENSIONS.map((ext) => path.join(base, `index${ext}`)));
|
|
108
|
+
return candidates.find((candidate) => known.has(candidate));
|
|
109
|
+
};
|
|
110
|
+
const files = paths.map((absolute) => {
|
|
111
|
+
const file = projectFile(cwd, absolute);
|
|
112
|
+
const parts = file.split("/");
|
|
113
|
+
const record = {
|
|
114
|
+
file,
|
|
115
|
+
module: parts[1] === "app" && parts.length > 3 ? parts.slice(0, 3).join("/") : path.posix.dirname(file).split("/").slice(0, 2).join("/"),
|
|
116
|
+
role: fileRole(file),
|
|
117
|
+
exports: [],
|
|
118
|
+
imports: [],
|
|
119
|
+
importedBy: []
|
|
120
|
+
};
|
|
121
|
+
if (!CODE.test(file)) return record;
|
|
122
|
+
try {
|
|
123
|
+
const parsed = parseSync(absolute, readFileSync(absolute, "utf8"));
|
|
124
|
+
for (const error of parsed.errors) warnings.push({
|
|
125
|
+
code: null,
|
|
126
|
+
source: file,
|
|
127
|
+
message: error.message
|
|
128
|
+
});
|
|
129
|
+
const exports = /* @__PURE__ */ new Set();
|
|
130
|
+
const imports = /* @__PURE__ */ new Set();
|
|
131
|
+
for (const statement of parsed.program.body) {
|
|
132
|
+
if (statement.type === "ExportDefaultDeclaration") exports.add("default");
|
|
133
|
+
if (statement.type === "ExportAllDeclaration") exports.add(statement.exported ? statement.exported.type === "Identifier" ? statement.exported.name : String(statement.exported.value) : "*");
|
|
134
|
+
if (statement.type !== "ExportNamedDeclaration") continue;
|
|
135
|
+
for (const specifier of statement.specifiers) exports.add(specifier.exported.type === "Identifier" ? specifier.exported.name : String(specifier.exported.value));
|
|
136
|
+
const declaration = statement.declaration;
|
|
137
|
+
if (declaration?.type === "VariableDeclaration") for (const item of declaration.declarations) for (const name of bindingNames(item.id)) exports.add(name);
|
|
138
|
+
else if (declaration && "id" in declaration && declaration.id?.type === "Identifier") exports.add(declaration.id.name);
|
|
139
|
+
}
|
|
140
|
+
const visit = (node) => {
|
|
141
|
+
if ((node.type === "ImportDeclaration" || node.type === "ExportNamedDeclaration" || node.type === "ExportAllDeclaration" || node.type === "TSImportType") && node.source) imports.add(String(node.source.value));
|
|
142
|
+
if (node.type === "ImportExpression" && node.source.type === "Literal" && typeof node.source.value === "string") imports.add(node.source.value);
|
|
143
|
+
if (node.type === "TSImportEqualsDeclaration" && node.moduleReference.type === "TSExternalModuleReference" && typeof node.moduleReference.expression.value === "string") imports.add(node.moduleReference.expression.value);
|
|
144
|
+
forEachChild(node, visit);
|
|
145
|
+
};
|
|
146
|
+
visit(parsed.program);
|
|
147
|
+
record.exports = [...exports].sort();
|
|
148
|
+
record.imports = [...imports].sort().map((specifier) => {
|
|
149
|
+
const resolved = (specifier.startsWith(".") ? [path.resolve(path.dirname(absolute), specifier)] : tsconfig ? resolvePathAlias(tsconfig, specifier) : []).map(probe).find((candidate) => candidate !== void 0);
|
|
150
|
+
return {
|
|
151
|
+
specifier,
|
|
152
|
+
file: resolved ? projectFile(cwd, resolved) : null
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
} catch (error) {
|
|
156
|
+
warnings.push({
|
|
157
|
+
code: null,
|
|
158
|
+
source: file,
|
|
159
|
+
message: String(error)
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
return record;
|
|
163
|
+
});
|
|
164
|
+
const byFile = new Map(files.map((file) => [file.file, file]));
|
|
165
|
+
for (const file of files) for (const imported of file.imports) if (imported.file) byFile.get(imported.file)?.importedBy.push(file.file);
|
|
166
|
+
for (const file of files) file.importedBy = [...new Set(file.importedBy)].sort();
|
|
167
|
+
return files;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
//#endregion
|
|
171
|
+
export { collectFiles, fileRole, projectFile };
|
|
172
|
+
//# sourceMappingURL=collect-files.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect-files.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/tooling/inspect/collect-files.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { readTsconfig, resolvePathAlias } from \"get-tsconfig\";\nimport { parseSync, type Node } from \"oxc-parser\";\nimport {\n isConfigFile,\n isEventFile,\n isLocaleFile,\n isMainFile,\n isRouteFile,\n isWorkerFile,\n} from \"../../dev-server/special-file-patterns\";\nimport { forEachChild } from \"../syntax/ast\";\nimport type { InspectFile, InspectWarning } from \"./inspect-report.types\";\n\nconst CODE = /\\.(?:[cm]?[jt]s|[jt]sx)$/;\nconst EXTENSIONS = [\".ts\", \".tsx\", \".mts\", \".cts\", \".js\", \".jsx\", \".mjs\", \".cjs\", \".d.ts\"];\n\nexport function projectFile(cwd: string, file: string): string {\n return path.relative(cwd, path.resolve(cwd, file)).split(path.sep).join(\"/\");\n}\n\n/** Infer a role from file names and the framework's directory conventions. */\nexport function fileRole(file: string): string {\n const stem = path.posix.basename(file).replace(CODE, \"\");\n if (/(?:^|\\.)(?:spec|test)$/.test(stem)) return \"spec\";\n if (file.endsWith(\".d.ts\")) return \"type\";\n if (isConfigFile(file)) return \"config\";\n if (isRouteFile(file)) return \"routes\";\n if (isMainFile(file)) return \"main\";\n if (isWorkerFile(file)) return \"worker\";\n if (isEventFile(file)) return \"event\";\n if (isLocaleFile(file)) return \"locale\";\n for (const role of [\"routes\", \"page\", \"setup\", \"layout\", \"root\"]) {\n if (stem === role || stem.endsWith(`.${role}`)) return role;\n }\n for (const role of [\n \"controller\",\n \"service\",\n \"repository\",\n \"model\",\n \"migration\",\n \"schema\",\n \"resource\",\n \"hook\",\n \"component\",\n \"util\",\n \"type\",\n \"config\",\n ]) {\n if (\n stem.endsWith(`.${role}`) ||\n file.split(\"/\").includes(role === \"repository\" ? \"repositories\" : `${role}s`)\n )\n return role;\n }\n if (file.startsWith(\"src/config/\")) return \"config\";\n if (file.split(\"/\").includes(\"utils\")) return \"util\";\n if (/^use[A-Z]/.test(stem)) return \"hook\";\n if (/\\.tsx$|\\.jsx$/.test(file)) return \"component\";\n return \"source\";\n}\n\nfunction bindingNames(node: Node): string[] {\n if (node.type === \"Identifier\") return [node.name];\n if (node.type === \"ObjectPattern\")\n return node.properties.flatMap((property) =>\n bindingNames(property.type === \"RestElement\" ? property.argument : property.value),\n );\n if (node.type === \"ArrayPattern\")\n return node.elements.flatMap((element) => (element ? bindingNames(element) : []));\n if (node.type === \"AssignmentPattern\") return bindingNames(node.left);\n if (node.type === \"RestElement\") return bindingNames(node.argument);\n return [];\n}\n\n/** Read each source module once; never import or execute application code. */\nexport function collectFiles(cwd: string, warnings: InspectWarning[] = []): InspectFile[] {\n cwd = path.resolve(cwd);\n const paths: string[] = [];\n const scan = (directory: string): void => {\n if (!existsSync(directory)) return;\n try {\n for (const entry of readdirSync(directory, { withFileTypes: true })) {\n const file = path.join(directory, entry.name);\n if (entry.isDirectory()) scan(file);\n else if (entry.isFile()) paths.push(file);\n }\n } catch (error) {\n warnings.push({ code: null, source: projectFile(cwd, directory), message: String(error) });\n }\n };\n scan(path.join(cwd, \"src\"));\n paths.sort();\n const known = new Set(paths);\n let tsconfig: ReturnType<typeof readTsconfig> | undefined;\n try {\n if (existsSync(path.join(cwd, \"tsconfig.json\")))\n tsconfig = readTsconfig(path.join(cwd, \"tsconfig.json\"), { typescriptVersion: false });\n } catch (error) {\n warnings.push({ code: null, source: \"tsconfig.json\", message: String(error) });\n }\n const probe = (base: string): string | undefined => {\n const extension = path.extname(base);\n const stem = /\\.[cm]?jsx?$/.test(extension) ? base.slice(0, -extension.length) : base;\n const candidates = stem !== base ? EXTENSIONS.map((ext) => stem + ext) : [];\n candidates.push(\n base,\n ...EXTENSIONS.map((ext) => base + ext),\n ...EXTENSIONS.map((ext) => path.join(base, `index${ext}`)),\n );\n return candidates.find((candidate) => known.has(candidate));\n };\n const files = paths.map((absolute): InspectFile => {\n const file = projectFile(cwd, absolute);\n const parts = file.split(\"/\");\n const record: InspectFile = {\n file,\n module:\n parts[1] === \"app\" && parts.length > 3\n ? parts.slice(0, 3).join(\"/\")\n : path.posix.dirname(file).split(\"/\").slice(0, 2).join(\"/\"),\n role: fileRole(file),\n exports: [],\n imports: [],\n importedBy: [],\n };\n if (!CODE.test(file)) return record;\n try {\n const parsed = parseSync(absolute, readFileSync(absolute, \"utf8\"));\n for (const error of parsed.errors)\n warnings.push({ code: null, source: file, message: error.message });\n const exports = new Set<string>();\n const imports = new Set<string>();\n for (const statement of parsed.program.body) {\n if (statement.type === \"ExportDefaultDeclaration\") exports.add(\"default\");\n if (statement.type === \"ExportAllDeclaration\")\n exports.add(\n statement.exported\n ? statement.exported.type === \"Identifier\"\n ? statement.exported.name\n : String(statement.exported.value)\n : \"*\",\n );\n if (statement.type !== \"ExportNamedDeclaration\") continue;\n for (const specifier of statement.specifiers)\n exports.add(\n specifier.exported.type === \"Identifier\"\n ? specifier.exported.name\n : String(specifier.exported.value),\n );\n const declaration = statement.declaration;\n if (declaration?.type === \"VariableDeclaration\") {\n for (const item of declaration.declarations)\n for (const name of bindingNames(item.id)) exports.add(name);\n } else if (declaration && \"id\" in declaration && declaration.id?.type === \"Identifier\")\n exports.add(declaration.id.name);\n }\n const visit = (node: Node): void => {\n if (\n (node.type === \"ImportDeclaration\" ||\n node.type === \"ExportNamedDeclaration\" ||\n node.type === \"ExportAllDeclaration\" ||\n node.type === \"TSImportType\") &&\n node.source\n )\n imports.add(String(node.source.value));\n if (\n node.type === \"ImportExpression\" &&\n node.source.type === \"Literal\" &&\n typeof node.source.value === \"string\"\n )\n imports.add(node.source.value);\n if (\n node.type === \"TSImportEqualsDeclaration\" &&\n node.moduleReference.type === \"TSExternalModuleReference\" &&\n typeof node.moduleReference.expression.value === \"string\"\n )\n imports.add(node.moduleReference.expression.value);\n forEachChild(node, visit);\n };\n visit(parsed.program);\n record.exports = [...exports].sort();\n record.imports = [...imports].sort().map((specifier) => {\n const bases = specifier.startsWith(\".\")\n ? [path.resolve(path.dirname(absolute), specifier)]\n : tsconfig\n ? resolvePathAlias(tsconfig, specifier)\n : [];\n const resolved = bases.map(probe).find((candidate) => candidate !== undefined);\n return { specifier, file: resolved ? projectFile(cwd, resolved) : null };\n });\n } catch (error) {\n warnings.push({ code: null, source: file, message: String(error) });\n }\n return record;\n });\n const byFile = new Map(files.map((file) => [file.file, file]));\n for (const file of files)\n for (const imported of file.imports) {\n if (imported.file) byFile.get(imported.file)?.importedBy.push(file.file);\n }\n for (const file of files) file.importedBy = [...new Set(file.importedBy)].sort();\n return files;\n}\n"],"mappings":"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"}
|