nx-factory-cli 2.0.1 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/commands/add-app.d.ts +15 -0
  2. package/dist/commands/add-app.d.ts.map +1 -0
  3. package/dist/commands/add-app.js +365 -0
  4. package/dist/commands/add-app.js.map +1 -0
  5. package/dist/commands/add-component.d.ts +2 -0
  6. package/dist/commands/add-component.d.ts.map +1 -0
  7. package/dist/commands/add-component.js +110 -0
  8. package/dist/commands/add-component.js.map +1 -0
  9. package/dist/commands/add-lib.d.ts +9 -0
  10. package/dist/commands/add-lib.d.ts.map +1 -0
  11. package/dist/commands/add-lib.js +190 -0
  12. package/dist/commands/add-lib.js.map +1 -0
  13. package/dist/commands/add-storybook.d.ts +6 -0
  14. package/dist/commands/add-storybook.d.ts.map +1 -0
  15. package/dist/commands/add-storybook.js +181 -0
  16. package/dist/commands/add-storybook.js.map +1 -0
  17. package/dist/commands/doctor.d.ts +2 -0
  18. package/dist/commands/doctor.d.ts.map +1 -0
  19. package/dist/commands/doctor.js +230 -0
  20. package/dist/commands/doctor.js.map +1 -0
  21. package/dist/commands/init.d.ts +9 -0
  22. package/dist/commands/init.d.ts.map +1 -0
  23. package/dist/commands/init.js +505 -0
  24. package/dist/commands/init.js.map +1 -0
  25. package/dist/commands/list.d.ts +2 -0
  26. package/dist/commands/list.d.ts.map +1 -0
  27. package/dist/commands/list.js +130 -0
  28. package/dist/commands/list.js.map +1 -0
  29. package/dist/commands/publish.d.ts +8 -0
  30. package/dist/commands/publish.d.ts.map +1 -0
  31. package/dist/commands/publish.js +179 -0
  32. package/dist/commands/publish.js.map +1 -0
  33. package/dist/commands/remove-component.d.ts +5 -0
  34. package/dist/commands/remove-component.d.ts.map +1 -0
  35. package/dist/commands/remove-component.js +172 -0
  36. package/dist/commands/remove-component.js.map +1 -0
  37. package/dist/commands/update.d.ts +5 -0
  38. package/dist/commands/update.d.ts.map +1 -0
  39. package/dist/commands/update.js +126 -0
  40. package/dist/commands/update.js.map +1 -0
  41. package/dist/config.d.ts +14 -0
  42. package/dist/config.d.ts.map +1 -0
  43. package/dist/config.js +35 -0
  44. package/dist/config.js.map +1 -0
  45. package/dist/exec.d.ts +25 -0
  46. package/dist/exec.d.ts.map +1 -0
  47. package/dist/exec.js +80 -0
  48. package/dist/exec.js.map +1 -0
  49. package/dist/files.d.ts +7 -0
  50. package/dist/files.d.ts.map +1 -0
  51. package/dist/files.js +23 -0
  52. package/dist/files.js.map +1 -0
  53. package/dist/index.d.ts +3 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +85 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/ui.d.ts +44 -0
  58. package/dist/ui.d.ts.map +1 -0
  59. package/dist/ui.js +149 -0
  60. package/dist/ui.js.map +1 -0
  61. package/package.json +1 -1
@@ -0,0 +1,190 @@
1
+ import inquirer from "inquirer";
2
+ import path from "path";
3
+ import { pathExists, writeJson, writeFile, ensureDir } from "../files.js";
4
+ import { loadConfig } from "../config.js";
5
+ import { detectPackageManager } from "../exec.js";
6
+ import { c, q, detected, createStepRunner, printSection, printSuccess, printError } from "../ui.js";
7
+ const LIB_TYPES = ["utils", "hooks", "config", "types", "api"];
8
+ export async function addLibCommand(options) {
9
+ // Verify monorepo root
10
+ if (!(await pathExists(path.join(process.cwd(), "package.json")))) {
11
+ printError({
12
+ title: "No package.json found",
13
+ detail: "Run this command from the monorepo root.",
14
+ recovery: [{ label: "", cmd: "cd <monorepo-root> && nx-factory add-lib" }],
15
+ });
16
+ process.exit(1);
17
+ return;
18
+ }
19
+ const cfg = await loadConfig();
20
+ const detectedPm = await detectPackageManager();
21
+ const defaults = {
22
+ libName: options.name ?? "shared",
23
+ libType: (options.type ?? "utils"),
24
+ pm: detectedPm ?? cfg?.pkgManager ?? "pnpm",
25
+ };
26
+ const answers = options.yes
27
+ ? defaults
28
+ : await inquirer.prompt([
29
+ {
30
+ type: "input",
31
+ name: "libName",
32
+ message: q("Library name", "lives at packages/<n>"),
33
+ default: defaults.libName,
34
+ validate: (v) => /^[a-z0-9-]+$/.test(v) || c.red("Only lowercase letters, numbers, and dashes"),
35
+ },
36
+ {
37
+ type: "list",
38
+ name: "libType",
39
+ message: q("Library type", "determines the initial file structure"),
40
+ choices: [
41
+ { name: "utils — shared helper functions", value: "utils" },
42
+ { name: "hooks — shared React hooks", value: "hooks" },
43
+ { name: "config — shared config / constants", value: "config" },
44
+ { name: "types — shared TypeScript types", value: "types" },
45
+ { name: "api — shared API client / fetchers", value: "api" },
46
+ ],
47
+ default: defaults.libType,
48
+ },
49
+ {
50
+ type: "list",
51
+ name: "pm",
52
+ message: q("Package manager"),
53
+ choices: ["pnpm", "npm", "yarn", "bun"],
54
+ default: detectedPm ? detected(detectedPm) : defaults.pm,
55
+ when: !detectedPm,
56
+ },
57
+ ]);
58
+ const libName = (answers.libName ?? defaults.libName);
59
+ const libType = (answers.libType ?? defaults.libType);
60
+ const pm = (answers.pm ?? detectedPm ?? cfg?.pkgManager ?? "pnpm");
61
+ const libDir = path.join(process.cwd(), "packages", libName);
62
+ if (await pathExists(libDir)) {
63
+ printError({
64
+ title: `packages/${libName} already exists`,
65
+ recovery: [{ label: "Choose a different name:", cmd: `nx-factory add-lib --name ${libName}-2` }],
66
+ });
67
+ process.exit(1);
68
+ return;
69
+ }
70
+ printSection(`${options.dryRun ? "[dry run] " : ""}Creating packages/${libName}`);
71
+ const step = createStepRunner(3, options.dryRun);
72
+ await step("Scaffold package structure", async () => {
73
+ await ensureDir(path.join(libDir, "src"));
74
+ await writeJson(path.join(libDir, "package.json"), {
75
+ name: `@workspace/${libName}`,
76
+ version: "0.0.1",
77
+ private: true,
78
+ type: "module",
79
+ exports: {
80
+ ".": {
81
+ import: "./dist/index.js",
82
+ types: "./dist/index.d.ts",
83
+ },
84
+ },
85
+ main: "./dist/index.js",
86
+ types: "./dist/index.d.ts",
87
+ scripts: {
88
+ build: "tsup",
89
+ "build:watch": "tsup --watch",
90
+ },
91
+ devDependencies: {
92
+ tsup: "^8.3.0",
93
+ typescript: "^5.6.0",
94
+ },
95
+ });
96
+ await writeJson(path.join(libDir, "tsconfig.json"), {
97
+ compilerOptions: {
98
+ target: "ES2022",
99
+ module: "ESNext",
100
+ moduleResolution: "bundler",
101
+ strict: true,
102
+ declaration: true,
103
+ declarationMap: true,
104
+ sourceMap: true,
105
+ esModuleInterop: true,
106
+ skipLibCheck: true,
107
+ outDir: "dist",
108
+ rootDir: "src",
109
+ },
110
+ include: ["src"],
111
+ exclude: ["node_modules", "dist"],
112
+ });
113
+ await writeFile(path.join(libDir, "tsup.config.ts"), `import { defineConfig } from "tsup";
114
+
115
+ export default defineConfig({
116
+ entry: ["src/index.ts"],
117
+ format: ["esm"],
118
+ dts: true,
119
+ sourcemap: true,
120
+ clean: true,
121
+ treeshake: true,
122
+ });
123
+ `);
124
+ // Seed index.ts based on lib type
125
+ await writeFile(path.join(libDir, "src/index.ts"), getIndexContent(libName, libType));
126
+ });
127
+ await step(`Add @workspace/${libName} to workspace`, async () => {
128
+ // For pnpm: pnpm-workspace.yaml is already written by init.
129
+ // For npm: the workspaces field in root package.json covers packages/*.
130
+ // Nothing extra to do — the new directory is picked up automatically.
131
+ void pm; // referenced to avoid unused-var warning
132
+ });
133
+ await step("Done", async () => { });
134
+ printSuccess({
135
+ title: `packages/${libName} created`,
136
+ commands: [
137
+ { cmd: `import { ... } from "@workspace/${libName}";`, comment: "use in any app" },
138
+ { cmd: `pnpm nx build @workspace/${libName}`, comment: "build the package" },
139
+ ],
140
+ tips: [
141
+ { label: "Add to an app's dependencies:", cmd: `"@workspace/${libName}": "${pm === "npm" ? "*" : "workspace:*"}"` },
142
+ ],
143
+ });
144
+ }
145
+ function getIndexContent(name, type) {
146
+ switch (type) {
147
+ case "utils":
148
+ return `// @workspace/${name} — shared utility functions
149
+
150
+ export function noop(): void {}
151
+
152
+ export function sleep(ms: number): Promise<void> {
153
+ return new Promise((resolve) => setTimeout(resolve, ms));
154
+ }
155
+ `;
156
+ case "hooks":
157
+ return `// @workspace/${name} — shared React hooks
158
+ // Note: add react as a peerDependency if you use hooks
159
+
160
+ export function useNoop(): void {}
161
+ `;
162
+ case "config":
163
+ return `// @workspace/${name} — shared configuration
164
+
165
+ export const config = {
166
+ env: process.env.NODE_ENV ?? "development",
167
+ } as const;
168
+ `;
169
+ case "types":
170
+ return `// @workspace/${name} — shared TypeScript types
171
+
172
+ export type ID = string;
173
+
174
+ export interface Timestamps {
175
+ createdAt: Date;
176
+ updatedAt: Date;
177
+ }
178
+ `;
179
+ case "api":
180
+ return `// @workspace/${name} — shared API client
181
+
182
+ export async function apiFetch<T>(url: string, init?: RequestInit): Promise<T> {
183
+ const res = await fetch(url, init);
184
+ if (!res.ok) throw new Error(\`HTTP \${res.status}: \${url}\`);
185
+ return res.json() as Promise<T>;
186
+ }
187
+ `;
188
+ }
189
+ }
190
+ //# sourceMappingURL=add-lib.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-lib.js","sourceRoot":"","sources":["../../src/commands/add-lib.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ interface AddStorybookOptions {
2
+ dryRun?: boolean;
3
+ }
4
+ export declare function addStorybookCommand(options: AddStorybookOptions): Promise<void>;
5
+ export {};
6
+ //# sourceMappingURL=add-storybook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-storybook.d.ts","sourceRoot":"","sources":["../../src/commands/add-storybook.ts"],"names":[],"mappings":"AAMA,UAAU,mBAAmB;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAsJrF"}
@@ -0,0 +1,181 @@
1
+ import path from "path";
2
+ import { pathExists, writeFile, ensureDir } from "../files.js";
3
+ import { loadConfig } from "../config.js";
4
+ import { run, pmAdd, detectPackageManager } from "../exec.js";
5
+ import { createStepRunner, printSection, printSuccess, printError, printWarn } from "../ui.js";
6
+ export async function addStorybookCommand(options) {
7
+ const cfg = await loadConfig();
8
+ const uiPkgDir = await detectUiPackageDir(cfg?.uiPackage);
9
+ if (!uiPkgDir) {
10
+ printError({
11
+ title: "UI package not found",
12
+ detail: "Run from the monorepo root.",
13
+ recovery: [{ label: "", cmd: "cd <monorepo-root> && nx-factory add-storybook" }],
14
+ });
15
+ process.exit(1);
16
+ return;
17
+ }
18
+ // Check Storybook isn't already present
19
+ const storybookDir = path.join(uiPkgDir, ".storybook");
20
+ if (await pathExists(storybookDir)) {
21
+ printWarn("Storybook already configured", `Found .storybook/ in packages/${cfg?.uiPackage ?? "ui"}`);
22
+ return;
23
+ }
24
+ const pm = (await detectPackageManager()) ?? cfg?.pkgManager ?? "pnpm";
25
+ const pkgName = cfg?.uiPackage ?? path.basename(uiPkgDir);
26
+ const installed = await getInstalledComponents(uiPkgDir);
27
+ printSection(`${options.dryRun ? "[dry run] " : ""}Adding Storybook to packages/${pkgName}`);
28
+ const step = createStepRunner(4, options.dryRun);
29
+ await step("Install Storybook deps", async () => {
30
+ await run(pm, [
31
+ pmAdd(pm), "--save-dev",
32
+ "@storybook/react-vite",
33
+ "@storybook/react",
34
+ "@storybook/addon-essentials",
35
+ "@storybook/addon-a11y",
36
+ "storybook",
37
+ ], { cwd: uiPkgDir });
38
+ });
39
+ await step("Write .storybook config", async () => {
40
+ await ensureDir(storybookDir);
41
+ await writeFile(path.join(storybookDir, "main.ts"), `import type { StorybookConfig } from "@storybook/react-vite";
42
+
43
+ const config: StorybookConfig = {
44
+ stories: ["../src/**/*.stories.@(ts|tsx)"],
45
+ addons: [
46
+ "@storybook/addon-essentials",
47
+ "@storybook/addon-a11y",
48
+ ],
49
+ framework: {
50
+ name: "@storybook/react-vite",
51
+ options: {},
52
+ },
53
+ };
54
+
55
+ export default config;
56
+ `);
57
+ await writeFile(path.join(storybookDir, "preview.ts"), `import type { Preview } from "@storybook/react";
58
+ import "../src/styles/globals.css";
59
+
60
+ const preview: Preview = {
61
+ parameters: {
62
+ controls: {
63
+ matchers: {
64
+ color: /(background|color)$/i,
65
+ date: /Date$/i,
66
+ },
67
+ },
68
+ },
69
+ };
70
+
71
+ export default preview;
72
+ `);
73
+ });
74
+ await step("Add storybook scripts to package.json", async () => {
75
+ const { default: fs } = await import("fs-extra");
76
+ const pkgJsonPath = path.join(uiPkgDir, "package.json");
77
+ const pkgJson = await fs.readJson(pkgJsonPath);
78
+ pkgJson.scripts = {
79
+ ...pkgJson.scripts,
80
+ storybook: "storybook dev --port 6006",
81
+ "build-storybook": "storybook build",
82
+ };
83
+ await fs.writeJson(pkgJsonPath, pkgJson, { spaces: 2 });
84
+ });
85
+ await step(`Generate ${installed.length} component stories`, async () => {
86
+ const storiesDir = path.join(uiPkgDir, "src/stories");
87
+ await ensureDir(storiesDir);
88
+ for (const comp of installed) {
89
+ const compName = toComponentName(comp);
90
+ const storyPath = path.join(storiesDir, `${compName}.stories.tsx`);
91
+ // Don't overwrite existing stories
92
+ if (await pathExists(storyPath))
93
+ continue;
94
+ await writeFile(storyPath, buildStory(compName, comp, pkgName));
95
+ }
96
+ // Write an index story if no components installed yet
97
+ if (installed.length === 0) {
98
+ await writeFile(path.join(storiesDir, "Welcome.stories.tsx"), `import type { Meta, StoryObj } from "@storybook/react";
99
+
100
+ const Welcome = () => (
101
+ <div style={{ padding: "2rem", fontFamily: "sans-serif" }}>
102
+ <h1>Welcome to @workspace/${pkgName}</h1>
103
+ <p>Add components with: <code>nx-factory add-component button</code></p>
104
+ </div>
105
+ );
106
+
107
+ const meta: Meta<typeof Welcome> = {
108
+ title: "Welcome",
109
+ component: Welcome,
110
+ };
111
+ export default meta;
112
+ type Story = StoryObj<typeof Welcome>;
113
+
114
+ export const Default: Story = {};
115
+ `);
116
+ }
117
+ });
118
+ printSuccess({
119
+ title: `Storybook added to packages/${pkgName}`,
120
+ commands: [
121
+ { cmd: `${pm} nx run ${pkgName}:storybook`, comment: "start Storybook on :6006" },
122
+ { cmd: `${pm} nx run ${pkgName}:build-storybook`, comment: "build static output" },
123
+ ],
124
+ tips: [
125
+ { label: "Stories live at:", cmd: `packages/${pkgName}/src/stories/` },
126
+ ],
127
+ });
128
+ }
129
+ // ─── Story template ──────────────────────────────────────────────────────────
130
+ function buildStory(compName, compSlug, pkgName) {
131
+ // Simple stories work for all components; complex ones (e.g. Dialog) would
132
+ // need customisation — we generate a useful default that compiles cleanly.
133
+ return `import type { Meta, StoryObj } from "@storybook/react";
134
+ import { ${compName} } from "@workspace/${pkgName}";
135
+
136
+ const meta: Meta<typeof ${compName}> = {
137
+ title: "ui/${compName}",
138
+ component: ${compName},
139
+ tags: ["autodocs"],
140
+ };
141
+ export default meta;
142
+ type Story = StoryObj<typeof ${compName}>;
143
+
144
+ export const Default: Story = {};
145
+ `;
146
+ }
147
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
148
+ async function getInstalledComponents(uiPkgDir) {
149
+ const dir = path.join(uiPkgDir, "src/components/ui");
150
+ if (!(await pathExists(dir)))
151
+ return [];
152
+ const { default: fs } = await import("fs-extra");
153
+ const files = await fs.readdir(dir);
154
+ return files
155
+ .filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"))
156
+ .map((f) => f.replace(/\.tsx?$/, ""))
157
+ .sort();
158
+ }
159
+ async function detectUiPackageDir(uiPackage) {
160
+ const base = uiPackage ?? "ui";
161
+ const configured = path.join(process.cwd(), "packages", base);
162
+ if (await pathExists(path.join(configured, "components.json")))
163
+ return configured;
164
+ if (await pathExists(path.join(process.cwd(), "components.json")))
165
+ return process.cwd();
166
+ const packagesDir = path.join(process.cwd(), "packages");
167
+ if (await pathExists(packagesDir)) {
168
+ const { default: fs } = await import("fs-extra");
169
+ const dirs = await fs.readdir(packagesDir);
170
+ for (const d of dirs) {
171
+ const candidate = path.join(packagesDir, d);
172
+ if (await pathExists(path.join(candidate, "components.json")))
173
+ return candidate;
174
+ }
175
+ }
176
+ return null;
177
+ }
178
+ function toComponentName(kebab) {
179
+ return kebab.split("-").map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("");
180
+ }
181
+ //# sourceMappingURL=add-storybook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-storybook.js","sourceRoot":"","sources":["../../src/commands/add-storybook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function doctorCommand(): Promise<void>;
2
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAWA,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAgOnD"}
@@ -0,0 +1,230 @@
1
+ import path from "path";
2
+ import { pathExists, writeFile } from "../files.js";
3
+ import { loadConfig } from "../config.js";
4
+ import { c, printSuccess, printError, printWarn } from "../ui.js";
5
+ export async function doctorCommand() {
6
+ const cfg = await loadConfig();
7
+ console.log(`\n ${c.dim("─".repeat(44))}`);
8
+ console.log(` ${c.whiteBold("nx-factory doctor")} ${c.dim("workspace health check")}`);
9
+ console.log(` ${c.dim("─".repeat(44))}\n`);
10
+ const checks = [];
11
+ const { default: fs } = await import("fs-extra");
12
+ // ─── 1. Config file present ────────────────────────────────────────────────
13
+ if (cfg) {
14
+ checks.push({ name: "Config file", status: "pass", detail: "nx-factory.config.json found" });
15
+ checks.push({ name: "Package manager", status: "pass", detail: cfg.pkgManager });
16
+ checks.push({ name: "UI package", status: "pass", detail: `packages/${cfg.uiPackage}` });
17
+ }
18
+ else {
19
+ checks.push({
20
+ name: "Config file",
21
+ status: "warn",
22
+ detail: "nx-factory.config.json not found — run `nx-factory init` or create manually",
23
+ });
24
+ }
25
+ // ─── 2. Resolve UI package dir ────────────────────────────────────────────
26
+ const uiPkgName = cfg?.uiPackage ?? "ui";
27
+ const uiPkgDir = path.join(process.cwd(), "packages", uiPkgName);
28
+ const hasUiPkg = await pathExists(uiPkgDir);
29
+ if (!hasUiPkg) {
30
+ checks.push({ name: "UI package dir", status: "fail", detail: `packages/${uiPkgName} not found` });
31
+ renderChecks(checks);
32
+ printError({
33
+ title: "Critical: UI package directory missing",
34
+ recovery: [{ label: "Re-initialise:", cmd: "nx-factory init" }],
35
+ });
36
+ return;
37
+ }
38
+ checks.push({ name: "UI package dir", status: "pass", detail: `packages/${uiPkgName} exists` });
39
+ // ─── 3. components.json ───────────────────────────────────────────────────
40
+ const compJsonPath = path.join(uiPkgDir, "components.json");
41
+ if (await pathExists(compJsonPath)) {
42
+ try {
43
+ const compJson = await fs.readJson(compJsonPath);
44
+ const style = compJson?.style ?? "unknown";
45
+ const aliases = compJson?.aliases ?? {};
46
+ // Auto-fix: if aliases use relative paths (./src/...) swap them to @/ style
47
+ const hasRelativePaths = Object.values(aliases).some((v) => typeof v === "string" && v.startsWith("./"));
48
+ if (hasRelativePaths) {
49
+ const fixed = {
50
+ ...compJson,
51
+ aliases: {
52
+ components: "@/components",
53
+ utils: "@/lib/utils",
54
+ ui: "@/components/ui",
55
+ lib: "@/lib",
56
+ hooks: "@/hooks",
57
+ },
58
+ };
59
+ await fs.writeJson(compJsonPath, fixed, { spaces: 2 });
60
+ checks.push({
61
+ name: "components.json",
62
+ status: "fix",
63
+ detail: `aliases rewritten from ./src/... to @/... (shadcn requires path aliases)`,
64
+ });
65
+ }
66
+ else {
67
+ checks.push({ name: "components.json", status: "pass", detail: `style: ${style}` });
68
+ }
69
+ }
70
+ catch {
71
+ checks.push({ name: "components.json", status: "fail", detail: "invalid JSON" });
72
+ }
73
+ }
74
+ else {
75
+ checks.push({ name: "components.json", status: "fail", detail: "missing — shadcn commands will not work" });
76
+ }
77
+ // ─── 4. tsup entry point ──────────────────────────────────────────────────
78
+ const tsupCfgPath = path.join(uiPkgDir, "tsup.config.ts");
79
+ const barrelPath = path.join(uiPkgDir, "src/index.ts");
80
+ if (await pathExists(tsupCfgPath)) {
81
+ checks.push({ name: "tsup.config.ts", status: "pass", detail: "build config present" });
82
+ }
83
+ else {
84
+ checks.push({ name: "tsup.config.ts", status: "warn", detail: "missing — `pnpm build` will not work" });
85
+ }
86
+ // ─── 4b. tsconfig paths (@/* alias required by shadcn) ────────────────────
87
+ const tsconfigPath = path.join(uiPkgDir, "tsconfig.json");
88
+ if (await pathExists(tsconfigPath)) {
89
+ try {
90
+ const tsconfig = await fs.readJson(tsconfigPath);
91
+ const paths = tsconfig?.compilerOptions?.paths ?? {};
92
+ const hasAlias = "@/*" in paths || "@/components" in paths;
93
+ if (!hasAlias) {
94
+ // Auto-fix: inject baseUrl + paths
95
+ tsconfig.compilerOptions = {
96
+ ...tsconfig.compilerOptions,
97
+ baseUrl: ".",
98
+ paths: { "@/*": ["./src/*"] },
99
+ };
100
+ await fs.writeJson(tsconfigPath, tsconfig, { spaces: 2 });
101
+ checks.push({
102
+ name: "tsconfig paths",
103
+ status: "fix",
104
+ detail: `added baseUrl + paths: { "@/*": ["./src/*"] }`,
105
+ });
106
+ }
107
+ else {
108
+ checks.push({ name: "tsconfig paths", status: "pass", detail: `@/* alias present` });
109
+ }
110
+ }
111
+ catch {
112
+ checks.push({ name: "tsconfig paths", status: "warn", detail: "could not parse tsconfig.json" });
113
+ }
114
+ }
115
+ else {
116
+ checks.push({ name: "tsconfig paths", status: "warn", detail: "tsconfig.json missing in UI package" });
117
+ }
118
+ // ─── 5. Barrel export sync ────────────────────────────────────────────────
119
+ const uiComponentsDir = path.join(uiPkgDir, "src/components/ui");
120
+ let installed = [];
121
+ if (await pathExists(uiComponentsDir)) {
122
+ const files = await fs.readdir(uiComponentsDir);
123
+ installed = files
124
+ .filter((f) => f.endsWith(".tsx") || f.endsWith(".ts"))
125
+ .map((f) => f.replace(/\.tsx?$/, ""))
126
+ .sort();
127
+ }
128
+ let barrelContent = "";
129
+ if (await pathExists(barrelPath)) {
130
+ barrelContent = await fs.readFile(barrelPath, "utf-8");
131
+ }
132
+ const exported = new Set([...barrelContent.matchAll(/\.\/components\/ui\/([^"']+)/g)].map((m) => m[1]));
133
+ const missing = installed.filter((comp) => !exported.has(comp));
134
+ if (missing.length === 0) {
135
+ checks.push({
136
+ name: "Barrel exports",
137
+ status: "pass",
138
+ detail: `${installed.length} component${installed.length !== 1 ? "s" : ""} all exported`,
139
+ });
140
+ }
141
+ else {
142
+ // Auto-fix: append missing exports
143
+ const newLines = missing.map((c) => `export * from "./components/ui/${c}";`).join("\n");
144
+ const updated = barrelContent.endsWith("\n")
145
+ ? barrelContent + newLines + "\n"
146
+ : barrelContent + "\n" + newLines + "\n";
147
+ await writeFile(barrelPath, updated);
148
+ checks.push({
149
+ name: "Barrel exports",
150
+ status: "fix",
151
+ detail: `added ${missing.length} missing export${missing.length > 1 ? "s" : ""}: ${missing.join(", ")}`,
152
+ });
153
+ }
154
+ // ─── 6. Workspace protocol ────────────────────────────────────────────────
155
+ if (cfg) {
156
+ const appsDir = path.join(process.cwd(), "apps");
157
+ if (await pathExists(appsDir)) {
158
+ const apps = await fs.readdir(appsDir);
159
+ const wrongProtocol = [];
160
+ const expected = cfg.pkgManager === "npm" ? `"*"` : `"workspace:*"`;
161
+ for (const app of apps) {
162
+ const pkgPath = path.join(appsDir, app, "package.json");
163
+ if (!(await pathExists(pkgPath)))
164
+ continue;
165
+ try {
166
+ const pkgJson = await fs.readJson(pkgPath);
167
+ const dep = pkgJson?.dependencies?.[`@workspace/${uiPkgName}`];
168
+ if (dep !== undefined) {
169
+ const isCorrect = cfg.pkgManager === "npm"
170
+ ? dep === "*"
171
+ : dep === "workspace:*";
172
+ if (!isCorrect)
173
+ wrongProtocol.push(`${app} (has "${dep}", expected ${expected})`);
174
+ }
175
+ }
176
+ catch { /* skip */ }
177
+ }
178
+ if (wrongProtocol.length === 0) {
179
+ checks.push({ name: "Workspace protocol", status: "pass", detail: `${expected} used correctly` });
180
+ }
181
+ else {
182
+ checks.push({
183
+ name: "Workspace protocol",
184
+ status: "warn",
185
+ detail: `wrong protocol in: ${wrongProtocol.join("; ")}`,
186
+ });
187
+ }
188
+ }
189
+ }
190
+ // ─── Render all checks ────────────────────────────────────────────────────
191
+ renderChecks(checks);
192
+ const failures = checks.filter((ch) => ch.status === "fail");
193
+ const warnings = checks.filter((ch) => ch.status === "warn");
194
+ const fixes = checks.filter((ch) => ch.status === "fix");
195
+ if (failures.length === 0 && warnings.length === 0) {
196
+ printSuccess({
197
+ title: "All checks passed",
198
+ commands: fixes.length > 0
199
+ ? [{ cmd: "src/index.ts updated", comment: "barrel exports were fixed automatically" }]
200
+ : [{ cmd: "nx-factory list", comment: "view installed components" }],
201
+ });
202
+ }
203
+ else {
204
+ if (fixes.length > 0) {
205
+ console.log(` ${c.green("✓")} ${c.green(`Auto-fixed ${fixes.length} issue${fixes.length > 1 ? "s" : ""}`)}\n`);
206
+ }
207
+ if (warnings.length > 0 || failures.length > 0) {
208
+ printWarn(`${warnings.length + failures.length} issue${warnings.length + failures.length > 1 ? "s" : ""} need attention`, "See details above");
209
+ }
210
+ }
211
+ }
212
+ function renderChecks(checks) {
213
+ for (const ch of checks) {
214
+ const icon = ch.status === "pass" ? c.green("✓") :
215
+ ch.status === "fix" ? c.cyan("↻") :
216
+ ch.status === "warn" ? c.yellow("⚠") :
217
+ c.red("✗");
218
+ const label = c.white(ch.name.padEnd(22));
219
+ const detail = ch.status === "fix"
220
+ ? c.cyan(ch.detail)
221
+ : ch.status === "fail"
222
+ ? c.red(ch.detail)
223
+ : ch.status === "warn"
224
+ ? c.yellow(ch.detail)
225
+ : c.dim(ch.detail);
226
+ console.log(` ${icon} ${label} ${detail}`);
227
+ }
228
+ console.log();
229
+ }
230
+ //# sourceMappingURL=doctor.js.map