filtercn 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { ProjectInfo } from "./detect-project.js";
2
+ export declare function checkPeerDependencies(cwd: string): string[];
3
+ export declare function installDependencies(deps: string[], projectInfo: ProjectInfo, cwd: string): void;
4
+ export declare function getShadcnInstallHint(pm: ProjectInfo["packageManager"]): string;
5
+ //# sourceMappingURL=dependencies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../../src/utils/dependencies.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAcvD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAW3D;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EAAE,EACd,WAAW,EAAE,WAAW,EACxB,GAAG,EAAE,MAAM,GACV,IAAI,CAaN;AAgBD,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,WAAW,CAAC,gBAAgB,CAAC,GAAG,MAAM,CAG9E"}
@@ -0,0 +1,57 @@
1
+ import fs from "fs-extra";
2
+ import path from "node:path";
3
+ import { execSync } from "node:child_process";
4
+ import { logger } from "./logger.js";
5
+ const PEER_DEPENDENCIES = ["lucide-react", "date-fns"];
6
+ const SHADCN_COMPONENTS = [
7
+ "button",
8
+ "input",
9
+ "select",
10
+ "popover",
11
+ "calendar",
12
+ "command",
13
+ "badge",
14
+ ];
15
+ export function checkPeerDependencies(cwd) {
16
+ const pkgPath = path.join(cwd, "package.json");
17
+ if (!fs.existsSync(pkgPath))
18
+ return PEER_DEPENDENCIES;
19
+ const pkg = fs.readJsonSync(pkgPath);
20
+ const allDeps = {
21
+ ...pkg.dependencies,
22
+ ...pkg.devDependencies,
23
+ };
24
+ return PEER_DEPENDENCIES.filter((dep) => !allDeps[dep]);
25
+ }
26
+ export function installDependencies(deps, projectInfo, cwd) {
27
+ if (deps.length === 0)
28
+ return;
29
+ const installCmd = getInstallCommand(projectInfo.packageManager, deps);
30
+ logger.info(`Installing: ${deps.join(", ")}...`);
31
+ try {
32
+ execSync(installCmd, { cwd, stdio: "pipe" });
33
+ logger.success("Dependencies installed.");
34
+ }
35
+ catch (error) {
36
+ logger.error(`Failed to install dependencies. Run manually:`);
37
+ logger.info(` ${installCmd}`);
38
+ }
39
+ }
40
+ function getInstallCommand(pm, deps) {
41
+ const depStr = deps.join(" ");
42
+ switch (pm) {
43
+ case "pnpm":
44
+ return `pnpm add ${depStr}`;
45
+ case "yarn":
46
+ return `yarn add ${depStr}`;
47
+ case "bun":
48
+ return `bun add ${depStr}`;
49
+ default:
50
+ return `npm install ${depStr}`;
51
+ }
52
+ }
53
+ export function getShadcnInstallHint(pm) {
54
+ const runner = pm === "npm" ? "npx" : pm === "pnpm" ? "pnpm dlx" : pm === "yarn" ? "npx" : "bunx";
55
+ return `${runner} shadcn@latest add ${SHADCN_COMPONENTS.join(" ")}`;
56
+ }
57
+ //# sourceMappingURL=dependencies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencies.js","sourceRoot":"","sources":["../../src/utils/dependencies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,MAAM,iBAAiB,GAAG,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;AAEvD,MAAM,iBAAiB,GAAG;IACxB,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,SAAS;IACT,UAAU;IACV,SAAS;IACT,OAAO;CACR,CAAC;AAEF,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAC/C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,iBAAiB,CAAC;IAEtD,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG;QACd,GAAG,GAAG,CAAC,YAAY;QACnB,GAAG,GAAG,CAAC,eAAe;KACvB,CAAC;IAEF,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,IAAc,EACd,WAAwB,EACxB,GAAW;IAEX,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAE9B,MAAM,UAAU,GAAG,iBAAiB,CAAC,WAAW,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;IACvE,MAAM,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAEjD,IAAI,CAAC;QACH,QAAQ,CAAC,UAAU,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC7C,MAAM,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;QAC9D,MAAM,CAAC,IAAI,CAAC,KAAK,UAAU,EAAE,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,EAAiC,EAAE,IAAc;IAC1E,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,QAAQ,EAAE,EAAE,CAAC;QACX,KAAK,MAAM;YACT,OAAO,YAAY,MAAM,EAAE,CAAC;QAC9B,KAAK,MAAM;YACT,OAAO,YAAY,MAAM,EAAE,CAAC;QAC9B,KAAK,KAAK;YACR,OAAO,WAAW,MAAM,EAAE,CAAC;QAC7B;YACE,OAAO,eAAe,MAAM,EAAE,CAAC;IACnC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,EAAiC;IACpE,MAAM,MAAM,GAAG,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IAClG,OAAO,GAAG,MAAM,sBAAsB,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AACtE,CAAC"}
@@ -0,0 +1,12 @@
1
+ export interface ProjectInfo {
2
+ /** Whether the project has a src/ directory */
3
+ hasSrc: boolean;
4
+ /** The components directory path (e.g. "src/components" or "components") */
5
+ componentsDir: string;
6
+ /** The detected package manager */
7
+ packageManager: "npm" | "pnpm" | "yarn" | "bun";
8
+ /** The import alias (e.g. "@/") */
9
+ alias: string;
10
+ }
11
+ export declare function detectProject(cwd: string): ProjectInfo;
12
+ //# sourceMappingURL=detect-project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-project.d.ts","sourceRoot":"","sources":["../../src/utils/detect-project.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,MAAM,EAAE,OAAO,CAAC;IAChB,4EAA4E;IAC5E,aAAa,EAAE,MAAM,CAAC;IACtB,mCAAmC;IACnC,cAAc,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;IAChD,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAgBtD"}
@@ -0,0 +1,52 @@
1
+ import fs from "fs-extra";
2
+ import path from "node:path";
3
+ export function detectProject(cwd) {
4
+ const hasSrc = fs.existsSync(path.join(cwd, "src"));
5
+ // Detect components directory
6
+ let componentsDir = "components";
7
+ if (hasSrc) {
8
+ componentsDir = path.join("src", "components");
9
+ }
10
+ // Detect package manager from lockfiles
11
+ const packageManager = detectPackageManager(cwd);
12
+ // Detect alias from tsconfig
13
+ const alias = detectAlias(cwd);
14
+ return { hasSrc, componentsDir, packageManager, alias };
15
+ }
16
+ function detectPackageManager(cwd) {
17
+ if (fs.existsSync(path.join(cwd, "bun.lockb")) || fs.existsSync(path.join(cwd, "bun.lock"))) {
18
+ return "bun";
19
+ }
20
+ if (fs.existsSync(path.join(cwd, "pnpm-lock.yaml"))) {
21
+ return "pnpm";
22
+ }
23
+ if (fs.existsSync(path.join(cwd, "yarn.lock"))) {
24
+ return "yarn";
25
+ }
26
+ return "npm";
27
+ }
28
+ function detectAlias(cwd) {
29
+ const tsconfigPath = path.join(cwd, "tsconfig.json");
30
+ if (!fs.existsSync(tsconfigPath))
31
+ return "@/";
32
+ try {
33
+ const raw = fs.readFileSync(tsconfigPath, "utf-8");
34
+ // Strip comments (basic) then parse
35
+ const cleaned = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
36
+ const tsconfig = JSON.parse(cleaned);
37
+ const paths = tsconfig?.compilerOptions?.paths;
38
+ if (paths) {
39
+ // Look for alias patterns like "@/*"
40
+ for (const key of Object.keys(paths)) {
41
+ if (key.endsWith("/*")) {
42
+ return key.replace("/*", "/");
43
+ }
44
+ }
45
+ }
46
+ }
47
+ catch {
48
+ // Fallback
49
+ }
50
+ return "@/";
51
+ }
52
+ //# sourceMappingURL=detect-project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-project.js","sourceRoot":"","sources":["../../src/utils/detect-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAa7B,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,MAAM,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IAEpD,8BAA8B;IAC9B,IAAI,aAAa,GAAG,YAAY,CAAC;IACjC,IAAI,MAAM,EAAE,CAAC;QACX,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IACjD,CAAC;IAED,wCAAwC;IACxC,MAAM,cAAc,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAEjD,6BAA6B;IAC7B,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAE/B,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;AAC1D,CAAC;AAED,SAAS,oBAAoB,CAAC,GAAW;IACvC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC;QAC5F,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC;QACpD,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;QAC/C,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IACrD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC;QAAE,OAAO,IAAI,CAAC;IAE9C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACnD,oCAAoC;QACpC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;QAC9E,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,QAAQ,EAAE,eAAe,EAAE,KAAK,CAAC;QAC/C,IAAI,KAAK,EAAE,CAAC;YACV,qCAAqC;YACrC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACrC,IAAI,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;oBACvB,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,WAAW;IACb,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,9 @@
1
+ export interface WriteFileOptions {
2
+ /** Base directory (cwd) */
3
+ cwd: string;
4
+ /** Force overwrite existing files */
5
+ force: boolean;
6
+ }
7
+ export declare function writeTemplateFile(relativePath: string, content: string, options: WriteFileOptions): Promise<boolean>;
8
+ export declare function writeAllTemplates(files: Record<string, string>, options: WriteFileOptions): Promise<number>;
9
+ //# sourceMappingURL=file-writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-writer.d.ts","sourceRoot":"","sources":["../../src/utils/file-writer.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,gBAAgB;IAC/B,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,qCAAqC;IACrC,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,iBAAiB,CACrC,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,OAAO,CAAC,CAYlB;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC7B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,MAAM,CAAC,CAOjB"}
@@ -0,0 +1,24 @@
1
+ import fs from "fs-extra";
2
+ import path from "node:path";
3
+ import { logger } from "./logger.js";
4
+ export async function writeTemplateFile(relativePath, content, options) {
5
+ const fullPath = path.join(options.cwd, relativePath);
6
+ if (fs.existsSync(fullPath) && !options.force) {
7
+ logger.warn(`Skipped (already exists): ${relativePath}`);
8
+ return false;
9
+ }
10
+ await fs.ensureDir(path.dirname(fullPath));
11
+ await fs.writeFile(fullPath, content, "utf-8");
12
+ logger.success(`Created: ${relativePath}`);
13
+ return true;
14
+ }
15
+ export async function writeAllTemplates(files, options) {
16
+ let count = 0;
17
+ for (const [relativePath, content] of Object.entries(files)) {
18
+ const written = await writeTemplateFile(relativePath, content, options);
19
+ if (written)
20
+ count++;
21
+ }
22
+ return count;
23
+ }
24
+ //# sourceMappingURL=file-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-writer.js","sourceRoot":"","sources":["../../src/utils/file-writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AASrC,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,YAAoB,EACpB,OAAe,EACf,OAAyB;IAEzB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAEtD,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC,6BAA6B,YAAY,EAAE,CAAC,CAAC;QACzD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC3C,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,CAAC,OAAO,CAAC,YAAY,YAAY,EAAE,CAAC,CAAC;IAC3C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAA6B,EAC7B,OAAyB;IAEzB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5D,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACxE,IAAI,OAAO;YAAE,KAAK,EAAE,CAAC;IACvB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,9 @@
1
+ export declare const logger: {
2
+ info: (msg: string) => void;
3
+ success: (msg: string) => void;
4
+ warn: (msg: string) => void;
5
+ error: (msg: string) => void;
6
+ break: () => void;
7
+ title: (msg: string) => void;
8
+ };
9
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,MAAM;gBACL,MAAM;mBACH,MAAM;gBACT,MAAM;iBACL,MAAM;;iBAEN,MAAM;CAKpB,CAAC"}
@@ -0,0 +1,14 @@
1
+ import chalk from "chalk";
2
+ export const logger = {
3
+ info: (msg) => console.log(chalk.cyan("ℹ"), msg),
4
+ success: (msg) => console.log(chalk.green("✔"), msg),
5
+ warn: (msg) => console.log(chalk.yellow("⚠"), msg),
6
+ error: (msg) => console.log(chalk.red("✖"), msg),
7
+ break: () => console.log(""),
8
+ title: (msg) => {
9
+ console.log("");
10
+ console.log(chalk.bold.blue(` ${msg}`));
11
+ console.log("");
12
+ },
13
+ };
14
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IACxD,OAAO,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IAC5D,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IAC1D,KAAK,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IACxD,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;IAC5B,KAAK,EAAE,CAAC,GAAW,EAAE,EAAE;QACrB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;CACF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "filtercn",
3
+ "version": "0.1.0",
4
+ "description": "CLI to scaffold the FilterCN conditional filter component into your Next.js + shadcn/ui project",
5
+ "type": "module",
6
+ "bin": {
7
+ "filtercn": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "dev": "tsc --watch",
12
+ "start": "node dist/index.js"
13
+ },
14
+ "dependencies": {
15
+ "chalk": "^5.4.1",
16
+ "commander": "^13.1.0",
17
+ "fs-extra": "^11.3.0",
18
+ "ora": "^8.2.0",
19
+ "prompts": "^2.4.2"
20
+ },
21
+ "devDependencies": {
22
+ "@types/fs-extra": "^11.0.4",
23
+ "@types/node": "^20.17.50",
24
+ "@types/prompts": "^2.4.9",
25
+ "typescript": "^5.8.3"
26
+ },
27
+ "keywords": ["filter", "shadcn", "nextjs", "cli", "component"],
28
+ "license": "MIT"
29
+ }
@@ -0,0 +1,126 @@
1
+ import path from "node:path";
2
+ import chalk from "chalk";
3
+ import ora from "ora";
4
+ import prompts from "prompts";
5
+ import { detectProject } from "../utils/detect-project.js";
6
+ import { writeAllTemplates } from "../utils/file-writer.js";
7
+ import {
8
+ checkPeerDependencies,
9
+ installDependencies,
10
+ getShadcnInstallHint,
11
+ } from "../utils/dependencies.js";
12
+ import { getTemplateFiles } from "../templates/index.js";
13
+ import { logger } from "../utils/logger.js";
14
+
15
+ interface InitOptions {
16
+ force: boolean;
17
+ cwd: string;
18
+ }
19
+
20
+ export async function initCommand(options: InitOptions) {
21
+ const cwd = path.resolve(options.cwd);
22
+
23
+ logger.title("🎛️ FilterCN — Component Installer");
24
+
25
+ // Step 1: Detect project
26
+ const spinner = ora("Detecting project structure...").start();
27
+ const projectInfo = detectProject(cwd);
28
+ spinner.succeed("Project detected");
29
+
30
+ console.log("");
31
+ console.log(
32
+ chalk.dim(" Project root: ") + cwd
33
+ );
34
+ console.log(
35
+ chalk.dim(" Components dir: ") + projectInfo.componentsDir
36
+ );
37
+ console.log(
38
+ chalk.dim(" Package manager: ") + projectInfo.packageManager
39
+ );
40
+ console.log(
41
+ chalk.dim(" Import alias: ") + projectInfo.alias
42
+ );
43
+ console.log("");
44
+
45
+ // Step 2: Confirm
46
+ const targetDir = path.join(
47
+ projectInfo.componentsDir,
48
+ "conditional-filter"
49
+ );
50
+
51
+ const { proceed } = await prompts({
52
+ type: "confirm",
53
+ name: "proceed",
54
+ message: `This will create files in ${chalk.cyan(targetDir)}. Continue?`,
55
+ initial: true,
56
+ });
57
+
58
+ if (!proceed) {
59
+ logger.info("Cancelled.");
60
+ return;
61
+ }
62
+
63
+ // Step 3: Write template files
64
+ logger.break();
65
+ const writeSpinner = ora("Scaffolding component files...").start();
66
+ const templates = getTemplateFiles(projectInfo.alias);
67
+
68
+ // Prefix each template path with the target directory
69
+ const prefixedTemplates: Record<string, string> = {};
70
+ for (const [relativePath, content] of Object.entries(templates)) {
71
+ prefixedTemplates[path.join(targetDir, relativePath)] = content;
72
+ }
73
+
74
+ writeSpinner.stop();
75
+
76
+ const fileCount = await writeAllTemplates(prefixedTemplates, {
77
+ cwd,
78
+ force: options.force,
79
+ });
80
+
81
+ logger.break();
82
+ logger.success(`${fileCount} files created.`);
83
+
84
+ // Step 4: Install peer dependencies
85
+ logger.break();
86
+ const missingDeps = checkPeerDependencies(cwd);
87
+
88
+ if (missingDeps.length > 0) {
89
+ const { installDeps } = await prompts({
90
+ type: "confirm",
91
+ name: "installDeps",
92
+ message: `Install missing dependencies (${missingDeps.join(", ")})?`,
93
+ initial: true,
94
+ });
95
+
96
+ if (installDeps) {
97
+ installDependencies(missingDeps, projectInfo, cwd);
98
+ } else {
99
+ logger.warn("Skipped dependency installation. Install manually:");
100
+ logger.info(` ${missingDeps.join(" ")}`);
101
+ }
102
+ } else {
103
+ logger.success("All peer dependencies already installed.");
104
+ }
105
+
106
+ // Step 5: Remind about shadcn/ui components
107
+ logger.break();
108
+ logger.info(
109
+ chalk.yellow("Don't forget to install the required shadcn/ui components:")
110
+ );
111
+ console.log("");
112
+ console.log(chalk.dim(" ") + chalk.cyan(getShadcnInstallHint(projectInfo.packageManager)));
113
+ console.log("");
114
+
115
+ // Done!
116
+ logger.break();
117
+ console.log(chalk.bold.green(" ✨ FilterCN installed successfully!"));
118
+ console.log("");
119
+ console.log(chalk.dim(" Quick start:"));
120
+ console.log("");
121
+ console.log(
122
+ chalk.dim(" ") +
123
+ chalk.white(`import { FilterProvider, FilterRoot } from "${projectInfo.alias}components/conditional-filter";`)
124
+ );
125
+ console.log("");
126
+ }
package/src/index.ts ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from "commander";
4
+ import { initCommand } from "./commands/init.js";
5
+
6
+ const program = new Command();
7
+
8
+ program
9
+ .name("filtercn")
10
+ .description("CLI to scaffold the FilterCN conditional filter component into your project")
11
+ .version("0.1.0");
12
+
13
+ program
14
+ .command("init")
15
+ .description("Initialize the conditional-filter component in your project")
16
+ .option("-f, --force", "Overwrite existing files", false)
17
+ .option(
18
+ "-c, --cwd <path>",
19
+ "The working directory (defaults to current directory)",
20
+ process.cwd()
21
+ )
22
+ .action(async (opts) => {
23
+ await initCommand({
24
+ force: opts.force,
25
+ cwd: opts.cwd,
26
+ });
27
+ });
28
+
29
+ program.parse();