diff --git a/.changeset/wrong-cwd-build-error.md b/.changeset/wrong-cwd-build-error.md new file mode 100644 index 00000000..00b0c073 --- /dev/null +++ b/.changeset/wrong-cwd-build-error.md @@ -0,0 +1,5 @@ +--- +"playground-cli": patch +--- + +Distinguish a wrong working directory from a genuinely unrecognised project in `dot build` / `dot deploy`. When no `package.json` is found, the error now points at the current directory ("Are you in your project directory? cd into it first, or point the command at it with --dir .") instead of the misleading "No build strategy detected" message that suggested editing a package.json that isn't there. diff --git a/src/utils/build/detect.test.ts b/src/utils/build/detect.test.ts index 3ebfb46e..437a80de 100644 --- a/src/utils/build/detect.test.ts +++ b/src/utils/build/detect.test.ts @@ -141,6 +141,45 @@ describe("detectBuildConfig", () => { ), ).toThrow(BuildDetectError); }); + + it("throws a wrong-directory error when package.json is missing entirely", () => { + // A missing package.json almost always means the user is one level + // above their project (e.g. ran `dot mod` then `dot build` from the + // parent). Point them at the cwd, not at editing a package.json that + // isn't there. + expect(() => detectBuildConfig(input({ packageJson: null }))).toThrow(BuildDetectError); + expect(() => detectBuildConfig(input({ packageJson: null }))).toThrow( + /No package\.json found/, + ); + }); + + it("names the project directory in the missing-package.json error", () => { + expect(() => + detectBuildConfig(input({ packageJson: null, projectDir: "/home/me" })), + ).toThrow(/\/home\/me/); + }); + + it("renders the missing-package.json error cleanly when no projectDir is known", () => { + // The dir name is optional, so the fallback must not leak `undefined` + // or a dangling space before the sentence-ending period. + let message = ""; + try { + detectBuildConfig(input({ packageJson: null })); + } catch (err) { + message = (err as Error).message; + } + expect(message).toContain("No package.json found."); + expect(message).not.toMatch(/undefined/); + expect(message).not.toMatch(/ {2}/); + }); + + it("keeps the generic build-strategy error when package.json exists but is unrecognised", () => { + // package.json IS present — the user is in the right place, we just + // can't infer a build. Keep the original guidance. + expect(() => detectBuildConfig(input({ packageJson: { scripts: {} } }))).toThrow( + /No build strategy detected/, + ); + }); }); describe("detectInstallConfig", () => { diff --git a/src/utils/build/detect.ts b/src/utils/build/detect.ts index bf1622b6..316ccc91 100644 --- a/src/utils/build/detect.ts +++ b/src/utils/build/detect.ts @@ -61,6 +61,12 @@ export interface DetectInput { lockfiles: Set; /** Set of additional config-file basenames (e.g. vite.config.ts). */ configFiles: Set; + /** + * Absolute project root the snapshot was taken from, used only to name the + * directory in the missing-package.json error. Optional so unit tests can + * build inputs without a real path. + */ + projectDir?: string; } export class BuildDetectError extends Error { @@ -197,6 +203,19 @@ export function detectBuildConfig(input: DetectInput): BuildConfig { } } + // No package.json at all almost always means the user is a level above + // their project (e.g. ran `dot mod`, then `dot build` from the parent dir). + // Point them at the directory rather than at editing a package.json that + // isn't there — the generic "add a build script" message sends them to the + // wrong fix. + if (!input.packageJson) { + const where = input.projectDir ? ` in ${input.projectDir}` : ""; + throw new BuildDetectError( + `No package.json found${where}. Are you in your project directory? ` + + "cd into it first, or point the command at it with --dir .", + ); + } + throw new BuildDetectError( 'No build strategy detected. Add a "build" script to package.json, or install vite/next/typescript.', ); diff --git a/src/utils/build/runner.ts b/src/utils/build/runner.ts index e84e926b..828a6131 100644 --- a/src/utils/build/runner.ts +++ b/src/utils/build/runner.ts @@ -68,6 +68,7 @@ export function loadDetectInput(projectDir: string): DetectInput { packageJson, lockfiles, configFiles, + projectDir: root, }; }