Skip to content

Commit ca788c9

Browse files
committed
Update pnpm-lock.yaml and package.json to include fast-glob; refactor CLI commands for improved error handling and project info retrieval
1 parent b0a6e74 commit ca788c9

File tree

14 files changed

+165
-63
lines changed

14 files changed

+165
-63
lines changed

packages/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"dotenv": "^16.5.0",
7070
"es-toolkit": "^1.15.1",
7171
"execa": "^9.5.1",
72+
"fast-glob": "^3.3.3",
7273
"fs-extra": "^11.3.0",
7374
"glob": "^11.0.1",
7475
"gradient-string": "^2.0.2",

packages/cli/src/cli/add/index.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,22 @@ import {
1717
} from "./data-source/index.js";
1818
import { makeAddSchemaCommand, runAddSchemaAction } from "./fmschema.js";
1919
import { makeAddPageCommand, runAddPageAction } from "./page/index.js";
20-
import { getMetaFromRegistry } from "./registry/getOptions.js";
2120
import { installFromRegistry } from "./registry/install.js";
2221

2322
export const runAdd = async (
2423
name: string | undefined,
2524
options?: { noInstall?: boolean }
2625
) => {
27-
const settings = getSettings();
28-
26+
2927
if (name === "tanstack-query") {
3028
return await runAddTanstackQueryCommand();
3129
} else if (name !== undefined) {
3230
// an arbitrary name was provided, so we'll try to install from the registry
3331
return await installFromRegistry(name);
3432
}
33+
34+
ensureProofKitProject({ commandName: "add" });
35+
const settings = getSettings();
3536

3637
const addType = abortIfCancel(
3738
await p.select({
@@ -99,13 +100,11 @@ export const makeAddCommand = () => {
99100
// console.log("preAction", _actionCommand.opts());
100101
initProgramState(_actionCommand.opts());
101102
state.baseCommand = "add";
102-
ensureProofKitProject({ commandName: "add" });
103103
});
104104
addCommand.hook("preSubcommand", (_thisCommand, _subCommand) => {
105105
// console.log("preSubcommand", _subCommand.opts());
106106
initProgramState(_subCommand.opts());
107107
state.baseCommand = "add";
108-
ensureProofKitProject({ commandName: "add" });
109108
});
110109

111110
addCommand.addCommand(makeAddAuthCommand());

packages/cli/src/cli/add/registry/getOptions.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
12
import { registryFetch } from "./http.js";
3+
import fs from "fs-extra";
4+
import fg from "fast-glob"
5+
import path from "path";
6+
import { state } from "~/state.js";
27

38
export async function getMetaFromRegistry(name: string) {
49
const result = await registryFetch("@get/meta/:name", {
@@ -10,3 +15,39 @@ export async function getMetaFromRegistry(name: string) {
1015
}
1116
return result.data;
1217
}
18+
19+
const PROJECT_SHARED_IGNORE = [
20+
"**/node_modules/**",
21+
".next",
22+
"public",
23+
"dist",
24+
"build",
25+
]
26+
27+
export async function getProjectInfo() {
28+
const cwd = state.projectDir || process.cwd();
29+
const [configFiles, isSrcDir] = await Promise.all([
30+
fg.glob(
31+
"**/{next,vite,astro,app}.config.*|gatsby-config.*|composer.json|react-router.config.*",
32+
{
33+
cwd,
34+
deep: 3,
35+
ignore: PROJECT_SHARED_IGNORE,
36+
}
37+
),
38+
fs.pathExists(path.resolve(cwd, "src"))
39+
])
40+
41+
42+
const isUsingAppDir = await fs.pathExists(
43+
path.resolve(cwd, `${isSrcDir ? "src/" : ""}app`)
44+
)
45+
46+
47+
// Next.js.
48+
if (configFiles.find((file) => file.startsWith("next.config."))?.length) {
49+
return isUsingAppDir ? "next-app" : "next-pages"
50+
}
51+
52+
return "manual"
53+
}

packages/cli/src/cli/add/registry/install.ts

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,40 @@
11
import { getOtherProofKitDependencies } from "@proofkit/registry";
22
import semver from "semver";
3+
import ora from "ora";
34

45
import { getRegistryUrl, shadcnInstall } from "~/helpers/shadcn-cli.js";
56
import { getVersion } from "~/utils/getProofKitVersion.js";
67
import { logger } from "~/utils/logger.js";
78
import { getSettings, mergeSettings } from "~/utils/parseSettings.js";
89
import { getMetaFromRegistry } from "./getOptions.js";
910
import { processPostInstallStep } from "./postInstall/index.js";
11+
import { preflightAddCommand } from "./preflight.js";
12+
import { uniq } from "es-toolkit";
1013

1114
export async function installFromRegistry(name: string) {
12-
const meta = await getMetaFromRegistry(name);
13-
if (!meta) {
14-
logger.error(`Template ${name} not found in the ProofKit registry`);
15-
return;
16-
}
17-
18-
if (
19-
meta.minimumProofKitVersion &&
20-
semver.gt(meta.minimumProofKitVersion, getVersion())
21-
) {
22-
logger.error(
23-
`Template ${name} requires ProofKit version ${meta.minimumProofKitVersion}, but you are using version ${getVersion()}`
24-
);
25-
return;
26-
}
15+
16+
const spinner = ora("Validating template").start();
17+
await preflightAddCommand();
18+
19+
try {
20+
const meta = await getMetaFromRegistry(name);
21+
if (!meta) {
22+
spinner.fail(`Template ${name} not found in the ProofKit registry`);
23+
return;
24+
}
25+
26+
27+
if (
28+
meta.minimumProofKitVersion &&
29+
semver.gt(meta.minimumProofKitVersion, getVersion())
30+
) {
31+
logger.error(
32+
`Template ${name} requires ProofKit version ${meta.minimumProofKitVersion}, but you are using version ${getVersion()}`
33+
);
34+
spinner.fail("Template is not compatible with your ProofKit version");
35+
return;
36+
}
37+
spinner.succeed();
2738

2839
const otherProofKitDependencies = getOtherProofKitDependencies(meta);
2940

@@ -55,10 +66,14 @@ export async function installFromRegistry(name: string) {
5566

5667
// update the settings
5768
mergeSettings({
58-
registryTemplates: [
69+
registryTemplates: uniq([
5970
...previouslyInstalledTemplates,
6071
name,
6172
...otherProofKitDependencies,
62-
],
73+
]),
6374
});
75+
} catch (error) {
76+
spinner.fail("Failed to fetch template metadata.");
77+
logger.error(error);
78+
}
6479
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { stealthInit } from "~/helpers/stealth-init.js";
2+
3+
export async function preflightAddCommand() {
4+
// make sure shadcn is installed, throw if not
5+
6+
// if proofkit is not inited, try to stealth init
7+
await stealthInit();
8+
}

packages/cli/src/cli/init.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ export const runInit = async (name?: string, opts?: CliFlags) => {
309309

310310
if (state.ui === "shadcn") {
311311
await shadcnInstall([
312-
`${getRegistryUrl()}/r/mode-toggle`,
312+
`${getRegistryUrl()}/r/components/mode-toggle`,
313313
"sonner",
314314
"button",
315315
]);

packages/cli/src/helpers/shadcn-cli.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,25 @@ import { state } from "~/state.js";
66
import { logger } from "~/utils/logger.js";
77
import { getSettings } from "~/utils/parseSettings.js";
88
import { runExecCommand } from "./installDependencies.js";
9+
import { execa } from "execa";
910

1011
export async function shadcnInstall(
1112
components: string | string[],
1213
friendlyComponentName?: string
1314
) {
1415
const componentsArray = Array.isArray(components) ? components : [components];
15-
const command = ["shadcn@latest", "add", "--overwrite", ...componentsArray];
16-
await runExecCommand({
17-
command,
18-
loadingMessage: `Installing ${friendlyComponentName ?? "components"}...`,
19-
successMessage: `${friendlyComponentName ?? "Components"} installed successfully!`,
20-
errorMessage: `Failed to install ${friendlyComponentName ?? "components"}`,
21-
});
16+
const command = ["shadcn@latest", "add", ...componentsArray, "--overwrite"];
17+
// Use execa to run the shadcn add command directly
18+
19+
try {
20+
await execa("pnpm", ["dlx", ...command], {
21+
stdio: "inherit",
22+
cwd: process.cwd(),
23+
});
24+
} catch (error) {
25+
logger.error(`Failed to run shadcn add: ${error}`);
26+
throw error;
27+
}
2228
}
2329

2430
export function getRegistryUrl(): string {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
3+
4+
5+
6+
7+
import fs from "fs-extra";
8+
import { defaultSettings } from "~/utils/parseSettings.js";
9+
10+
11+
/**
12+
* Used to add a proofkit.json file to an existing project
13+
*/
14+
export async function stealthInit() {
15+
// check if proofkit.json exists
16+
const proofkitJson = await fs.pathExists("proofkit.json");
17+
if (proofkitJson) {
18+
return;
19+
}
20+
21+
// create proofkit.json
22+
await fs.writeJson("proofkit.json", defaultSettings
23+
24+
);
25+
}

packages/registry/lib/types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export const templateFileSchema = z.discriminatedUnion("type", [
2929
// The name of the file within this template directory
3030
sourceFileName: z.string(),
3131
// The destination path in a consumer project, relative to project root
32-
destinationPath: z.string(),
32+
destinationPath: z.string().optional(),
3333
type: registryTypeSchema.extract(["registry:file", "registry:page"]),
3434
}),
3535
z.object({
@@ -103,6 +103,8 @@ const categorySchema = z.enum([
103103
"email",
104104
]);
105105

106+
export const frameworkSchema = z.enum(["next-pages", "next-app", "manual"]);
107+
106108
const sharedMetadataSchema = registryItemSchema
107109
.omit({ name: true, type: true, files: true })
108110
.extend({
@@ -121,6 +123,7 @@ const sharedMetadataSchema = registryItemSchema
121123
.string()
122124
.describe("The minimum version of ProofKit required to use this template")
123125
.optional(),
126+
allowedFrameworks: z.array(frameworkSchema).optional(),
124127
});
125128

126129
// Defines the metadata for a single template (_meta.ts)

packages/registry/lib/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,13 @@ export async function getStaticComponent(
185185
path: file.sourceFileName,
186186
type: file.type,
187187
content,
188-
target: file.destinationPath,
188+
target: file.destinationPath ?? file.sourceFileName,
189189
}
190190
: {
191191
path: file.sourceFileName,
192192
type: file.type,
193193
content,
194-
target: file.destinationPath ?? "",
194+
target: file.destinationPath ?? file.sourceFileName,
195195
};
196196

197197
return shadcnFile;

0 commit comments

Comments
 (0)