uniqueui-cli 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.
- package/dist/commands/add.js +167 -0
- package/dist/commands/init.js +58 -0
- package/dist/index.js +22 -0
- package/package.json +30 -0
- package/src/commands/add.ts +184 -0
- package/src/commands/init.ts +62 -0
- package/src/index.ts +25 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.add = add;
|
|
7
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
11
|
+
const ts_morph_1 = require("ts-morph");
|
|
12
|
+
const child_process_1 = require("child_process");
|
|
13
|
+
async function add(componentName, options) {
|
|
14
|
+
console.log(`Fetching ${componentName} from ${options.url}...`);
|
|
15
|
+
// 1. Load config
|
|
16
|
+
let config;
|
|
17
|
+
try {
|
|
18
|
+
config = await fs_extra_1.default.readJson("components.json");
|
|
19
|
+
}
|
|
20
|
+
catch (e) {
|
|
21
|
+
console.error(chalk_1.default.red("components.json not found. Run 'init' first."));
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
// 2. Fetch registry
|
|
25
|
+
let registry;
|
|
26
|
+
try {
|
|
27
|
+
// For local testing, if url is a file path, read it
|
|
28
|
+
if (options.url.startsWith(".")) {
|
|
29
|
+
registry = await fs_extra_1.default.readJson(options.url);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const res = await (0, node_fetch_1.default)(`${options.url}/registry.json`);
|
|
33
|
+
if (!res.ok)
|
|
34
|
+
throw new Error("Failed to fetch registry");
|
|
35
|
+
registry = await res.json();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
console.error(chalk_1.default.red("Could not fetch registry.json"), e);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
const item = registry.find((c) => c.name === componentName);
|
|
43
|
+
if (!item) {
|
|
44
|
+
console.error(chalk_1.default.red(`Component ${componentName} not found.`));
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
// 3. Install dependencies
|
|
48
|
+
if (item.dependencies.length) {
|
|
49
|
+
console.log(chalk_1.default.cyan(`Installing dependencies: ${item.dependencies.join(", ")}`));
|
|
50
|
+
try {
|
|
51
|
+
// Detect package manager - simplified
|
|
52
|
+
const pm = fs_extra_1.default.existsSync("pnpm-lock.yaml") ? "pnpm" : fs_extra_1.default.existsSync("yarn.lock") ? "yarn" : "npm";
|
|
53
|
+
const cmd = pm === "npm" ? "install" : "add"; // yarn add, pnpm add
|
|
54
|
+
(0, child_process_1.execSync)(`${pm} ${cmd} ${item.dependencies.join(" ")}`, { stdio: "inherit" });
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
console.warn(chalk_1.default.yellow("Failed to install dependencies automatically. Please install them manually."));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// 4. Update Tailwind Config
|
|
61
|
+
if (item.tailwindConfig) {
|
|
62
|
+
console.log(chalk_1.default.cyan("Updating tailwind.config..."));
|
|
63
|
+
await updateTailwindConfig(config.tailwind.config, item.tailwindConfig);
|
|
64
|
+
}
|
|
65
|
+
// 5. Write Files
|
|
66
|
+
const targetDir = path_1.default.resolve(config.paths.components || "components/ui");
|
|
67
|
+
await fs_extra_1.default.ensureDir(targetDir);
|
|
68
|
+
for (const file of item.files) {
|
|
69
|
+
// We only handle ui components for now
|
|
70
|
+
if (file.type === "registry:ui") {
|
|
71
|
+
const fileName = path_1.default.basename(file.path);
|
|
72
|
+
const targetPath = path_1.default.join(targetDir, fileName);
|
|
73
|
+
await fs_extra_1.default.writeFile(targetPath, file.content);
|
|
74
|
+
console.log(chalk_1.default.green(`Created ${fileName}`));
|
|
75
|
+
}
|
|
76
|
+
// Handle utils if needed, or other types
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async function updateTailwindConfig(configPath, newConfig) {
|
|
80
|
+
const project = new ts_morph_1.Project({
|
|
81
|
+
manipulationSettings: {
|
|
82
|
+
quoteKind: ts_morph_1.QuoteKind.Double,
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
// Attempt to add the file
|
|
86
|
+
const sourceFile = project.addSourceFileAtPath(configPath);
|
|
87
|
+
// Simplistic handling: look for export default or module.exports
|
|
88
|
+
// We expect the config to be an object literal.
|
|
89
|
+
// We need to merge `newConfig.theme.extend` into the existing config.
|
|
90
|
+
// logic: find 'theme' property -> find 'extend' property -> merge properties.
|
|
91
|
+
const exportAssignment = sourceFile.getExportAssignment((e) => !e.isExportEquals()); // export default
|
|
92
|
+
let objectLiteral;
|
|
93
|
+
if (exportAssignment) {
|
|
94
|
+
objectLiteral = exportAssignment.getExpression().asKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// try module.exports
|
|
98
|
+
const stmt = sourceFile.getStatement((s) => {
|
|
99
|
+
if (s.getKind() === ts_morph_1.SyntaxKind.ExpressionStatement) {
|
|
100
|
+
const expr = s.asKind(ts_morph_1.SyntaxKind.ExpressionStatement)?.getExpression();
|
|
101
|
+
if (expr && expr.getKind() === ts_morph_1.SyntaxKind.BinaryExpression) {
|
|
102
|
+
const binary = expr.asKind(ts_morph_1.SyntaxKind.BinaryExpression);
|
|
103
|
+
const left = binary?.getLeft();
|
|
104
|
+
if (left?.getText() === "module.exports")
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return false;
|
|
109
|
+
});
|
|
110
|
+
if (stmt) {
|
|
111
|
+
const binary = stmt.asKind(ts_morph_1.SyntaxKind.ExpressionStatement).getExpression().asKind(ts_morph_1.SyntaxKind.BinaryExpression);
|
|
112
|
+
objectLiteral = binary.getRight().asKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (!objectLiteral) {
|
|
116
|
+
console.warn(chalk_1.default.yellow("Could not parse tailwind config object. Skipping update."));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// Heuristics:
|
|
120
|
+
// newConfig is { theme: { extend: { animation: {...}, keyframes: {...} } } }
|
|
121
|
+
// Helper to get or create property object
|
|
122
|
+
const getOrCreateObjectProperty = (parentObj, name) => {
|
|
123
|
+
let prop = parentObj.getProperty(name);
|
|
124
|
+
if (!prop) {
|
|
125
|
+
parentObj.addPropertyAssignment({ name, initializer: "{}" });
|
|
126
|
+
prop = parentObj.getProperty(name);
|
|
127
|
+
}
|
|
128
|
+
const init = prop?.asKind(ts_morph_1.SyntaxKind.PropertyAssignment)?.getInitializer();
|
|
129
|
+
return init?.asKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
130
|
+
};
|
|
131
|
+
if (newConfig.theme?.extend) {
|
|
132
|
+
const themeObj = getOrCreateObjectProperty(objectLiteral, "theme");
|
|
133
|
+
if (themeObj) {
|
|
134
|
+
const extendObj = getOrCreateObjectProperty(themeObj, "extend");
|
|
135
|
+
if (extendObj) {
|
|
136
|
+
// Merge animations
|
|
137
|
+
const animations = newConfig.theme.extend.animation;
|
|
138
|
+
if (animations) {
|
|
139
|
+
const animObj = getOrCreateObjectProperty(extendObj, "animation");
|
|
140
|
+
if (animObj) {
|
|
141
|
+
for (const [key, value] of Object.entries(animations)) {
|
|
142
|
+
if (!animObj.getProperty(key)) {
|
|
143
|
+
animObj.addPropertyAssignment({ name: `"${key}"`, initializer: `"${value}"` });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Merge keyframes
|
|
149
|
+
const keyframes = newConfig.theme.extend.keyframes;
|
|
150
|
+
if (keyframes) {
|
|
151
|
+
const keyframesObj = getOrCreateObjectProperty(extendObj, "keyframes");
|
|
152
|
+
if (keyframesObj) {
|
|
153
|
+
for (const [key, value] of Object.entries(keyframes)) {
|
|
154
|
+
if (!keyframesObj.getProperty(key)) {
|
|
155
|
+
// value is an object, strictly JSON stringify might be valid JS valid object literal needed?
|
|
156
|
+
// "JSON.stringify(value)" produces valid JSON which is valid JS object literal initializer if keys are quoted.
|
|
157
|
+
keyframesObj.addPropertyAssignment({ name: `"${key}"`, initializer: JSON.stringify(value) });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
await sourceFile.save();
|
|
166
|
+
console.log(chalk_1.default.green("Tailwind config updated successfully."));
|
|
167
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.init = init;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
10
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
11
|
+
async function init() {
|
|
12
|
+
console.log(chalk_1.default.bold.green("Initializing UniqueUI..."));
|
|
13
|
+
const cwd = process.cwd();
|
|
14
|
+
const response = await (0, prompts_1.default)([
|
|
15
|
+
{
|
|
16
|
+
type: "text",
|
|
17
|
+
name: "componentsDir",
|
|
18
|
+
message: "Where would you like to install components?",
|
|
19
|
+
initial: "components/ui",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
type: "toggle",
|
|
23
|
+
name: "typescript",
|
|
24
|
+
message: "Are you using TypeScript?",
|
|
25
|
+
initial: true,
|
|
26
|
+
active: "yes",
|
|
27
|
+
inactive: "no",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
type: "text",
|
|
31
|
+
name: "tailwindConfig",
|
|
32
|
+
message: "Where is your tailwind.config.js located?",
|
|
33
|
+
initial: "tailwind.config.ts",
|
|
34
|
+
},
|
|
35
|
+
]);
|
|
36
|
+
const config = {
|
|
37
|
+
$schema: "https://uniqueui.com/schema.json",
|
|
38
|
+
style: "default",
|
|
39
|
+
rsc: true,
|
|
40
|
+
tsx: response.typescript,
|
|
41
|
+
tailwind: {
|
|
42
|
+
config: response.tailwindConfig,
|
|
43
|
+
css: "app/globals.css", // simplifying assumption or could ask
|
|
44
|
+
baseColor: "slate",
|
|
45
|
+
cssVariables: true,
|
|
46
|
+
},
|
|
47
|
+
aliases: {
|
|
48
|
+
components: "@/components",
|
|
49
|
+
utils: "@/lib/utils",
|
|
50
|
+
},
|
|
51
|
+
paths: {
|
|
52
|
+
components: response.componentsDir,
|
|
53
|
+
lib: "lib" // simplifying
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
await fs_1.promises.writeFile(path_1.default.join(cwd, "components.json"), JSON.stringify(config, null, 2));
|
|
57
|
+
console.log(chalk_1.default.green("Configuration saved to components.json"));
|
|
58
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const init_1 = require("./commands/init");
|
|
6
|
+
const add_1 = require("./commands/add");
|
|
7
|
+
const program = new commander_1.Command();
|
|
8
|
+
program
|
|
9
|
+
.name("uniqueui")
|
|
10
|
+
.description("Add components from UniqueUI to your project")
|
|
11
|
+
.version("0.1.0");
|
|
12
|
+
program
|
|
13
|
+
.command("init")
|
|
14
|
+
.description("Configure your project for UniqueUI")
|
|
15
|
+
.action(init_1.init);
|
|
16
|
+
program
|
|
17
|
+
.command("add")
|
|
18
|
+
.description("Add a component to your project")
|
|
19
|
+
.argument("<component>", "the component to add")
|
|
20
|
+
.option("--url <url>", "the base URL of the registry", "https://raw.githubusercontent.com/prashantkumarsingh/uniqueui/main")
|
|
21
|
+
.action(add_1.add);
|
|
22
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "uniqueui-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI for UniqueUI",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"uniqueui": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"start": "node dist/index.js",
|
|
12
|
+
"dev": "ts-node src/index.ts"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"commander": "^11.1.0",
|
|
16
|
+
"chalk": "^4.1.2",
|
|
17
|
+
"ts-morph": "^21.0.1",
|
|
18
|
+
"zod": "^3.22.4",
|
|
19
|
+
"node-fetch": "^3.3.2",
|
|
20
|
+
"ora": "^5.4.1",
|
|
21
|
+
"prompts": "^2.4.2"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^20.10.0",
|
|
25
|
+
"typescript": "^5.3.3",
|
|
26
|
+
"@types/prompts": "^2.4.9",
|
|
27
|
+
"@types/fs-extra": "^11.0.4",
|
|
28
|
+
"fs-extra": "^11.2.0"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import fetch from "node-fetch";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import fs from "fs-extra";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import { Project, SyntaxKind, QuoteKind } from "ts-morph";
|
|
8
|
+
import { execSync } from "child_process";
|
|
9
|
+
|
|
10
|
+
// Type definition for Registry (matching what we built)
|
|
11
|
+
type RegistryItem = {
|
|
12
|
+
name: string;
|
|
13
|
+
dependencies: string[];
|
|
14
|
+
files: Array<{ path: string; type: string; content: string }>;
|
|
15
|
+
tailwindConfig?: Record<string, any>;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export async function add(componentName: string, options: { url: string }) {
|
|
19
|
+
console.log(`Fetching ${componentName} from ${options.url}...`);
|
|
20
|
+
|
|
21
|
+
// 1. Load config
|
|
22
|
+
let config;
|
|
23
|
+
try {
|
|
24
|
+
config = await fs.readJson("components.json");
|
|
25
|
+
} catch (e) {
|
|
26
|
+
console.error(chalk.red("components.json not found. Run 'init' first."));
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 2. Fetch registry
|
|
31
|
+
let registry: RegistryItem[];
|
|
32
|
+
try {
|
|
33
|
+
// For local testing, if url is a file path, read it
|
|
34
|
+
if (options.url.startsWith(".")) {
|
|
35
|
+
registry = await fs.readJson(options.url);
|
|
36
|
+
} else {
|
|
37
|
+
const res = await fetch(`${options.url}/registry.json`);
|
|
38
|
+
if (!res.ok) throw new Error("Failed to fetch registry");
|
|
39
|
+
registry = await res.json() as RegistryItem[];
|
|
40
|
+
}
|
|
41
|
+
} catch (e) {
|
|
42
|
+
console.error(chalk.red("Could not fetch registry.json"), e);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const item = registry.find((c) => c.name === componentName);
|
|
47
|
+
if (!item) {
|
|
48
|
+
console.error(chalk.red(`Component ${componentName} not found.`));
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 3. Install dependencies
|
|
53
|
+
if (item.dependencies.length) {
|
|
54
|
+
console.log(chalk.cyan(`Installing dependencies: ${item.dependencies.join(", ")}`));
|
|
55
|
+
try {
|
|
56
|
+
// Detect package manager - simplified
|
|
57
|
+
const pm = fs.existsSync("pnpm-lock.yaml") ? "pnpm" : fs.existsSync("yarn.lock") ? "yarn" : "npm";
|
|
58
|
+
const cmd = pm === "npm" ? "install" : "add"; // yarn add, pnpm add
|
|
59
|
+
execSync(`${pm} ${cmd} ${item.dependencies.join(" ")}`, { stdio: "inherit" });
|
|
60
|
+
} catch (e) {
|
|
61
|
+
console.warn(chalk.yellow("Failed to install dependencies automatically. Please install them manually."));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 4. Update Tailwind Config
|
|
66
|
+
if (item.tailwindConfig) {
|
|
67
|
+
console.log(chalk.cyan("Updating tailwind.config..."));
|
|
68
|
+
await updateTailwindConfig(config.tailwind.config, item.tailwindConfig);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 5. Write Files
|
|
72
|
+
const targetDir = path.resolve(config.paths.components || "components/ui");
|
|
73
|
+
await fs.ensureDir(targetDir);
|
|
74
|
+
|
|
75
|
+
for (const file of item.files) {
|
|
76
|
+
// We only handle ui components for now
|
|
77
|
+
if (file.type === "registry:ui") {
|
|
78
|
+
const fileName = path.basename(file.path);
|
|
79
|
+
const targetPath = path.join(targetDir, fileName);
|
|
80
|
+
await fs.writeFile(targetPath, file.content);
|
|
81
|
+
console.log(chalk.green(`Created ${fileName}`));
|
|
82
|
+
}
|
|
83
|
+
// Handle utils if needed, or other types
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function updateTailwindConfig(configPath: string, newConfig: any) {
|
|
88
|
+
const project = new Project({
|
|
89
|
+
manipulationSettings: {
|
|
90
|
+
quoteKind: QuoteKind.Double,
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Attempt to add the file
|
|
95
|
+
const sourceFile = project.addSourceFileAtPath(configPath);
|
|
96
|
+
|
|
97
|
+
// Simplistic handling: look for export default or module.exports
|
|
98
|
+
// We expect the config to be an object literal.
|
|
99
|
+
|
|
100
|
+
// We need to merge `newConfig.theme.extend` into the existing config.
|
|
101
|
+
// logic: find 'theme' property -> find 'extend' property -> merge properties.
|
|
102
|
+
|
|
103
|
+
const exportAssignment = sourceFile.getExportAssignment((e) => !e.isExportEquals()); // export default
|
|
104
|
+
let objectLiteral;
|
|
105
|
+
|
|
106
|
+
if (exportAssignment) {
|
|
107
|
+
objectLiteral = exportAssignment.getExpression().asKind(SyntaxKind.ObjectLiteralExpression);
|
|
108
|
+
} else {
|
|
109
|
+
// try module.exports
|
|
110
|
+
const stmt = sourceFile.getStatement((s) => {
|
|
111
|
+
if (s.getKind() === SyntaxKind.ExpressionStatement) {
|
|
112
|
+
const expr = s.asKind(SyntaxKind.ExpressionStatement)?.getExpression();
|
|
113
|
+
if (expr && expr.getKind() === SyntaxKind.BinaryExpression) {
|
|
114
|
+
const binary = expr.asKind(SyntaxKind.BinaryExpression);
|
|
115
|
+
const left = binary?.getLeft();
|
|
116
|
+
if (left?.getText() === "module.exports") return true;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
});
|
|
121
|
+
if (stmt) {
|
|
122
|
+
const binary = stmt.asKind(SyntaxKind.ExpressionStatement)!.getExpression().asKind(SyntaxKind.BinaryExpression)!;
|
|
123
|
+
objectLiteral = binary.getRight().asKind(SyntaxKind.ObjectLiteralExpression);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!objectLiteral) {
|
|
128
|
+
console.warn(chalk.yellow("Could not parse tailwind config object. Skipping update."));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Heuristics:
|
|
133
|
+
// newConfig is { theme: { extend: { animation: {...}, keyframes: {...} } } }
|
|
134
|
+
|
|
135
|
+
// Helper to get or create property object
|
|
136
|
+
const getOrCreateObjectProperty = (parentObj: any, name: string) => {
|
|
137
|
+
let prop = parentObj.getProperty(name);
|
|
138
|
+
if (!prop) {
|
|
139
|
+
parentObj.addPropertyAssignment({ name, initializer: "{}" });
|
|
140
|
+
prop = parentObj.getProperty(name);
|
|
141
|
+
}
|
|
142
|
+
const init = prop?.asKind(SyntaxKind.PropertyAssignment)?.getInitializer();
|
|
143
|
+
return init?.asKind(SyntaxKind.ObjectLiteralExpression);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
if (newConfig.theme?.extend) {
|
|
147
|
+
const themeObj = getOrCreateObjectProperty(objectLiteral, "theme");
|
|
148
|
+
if (themeObj) {
|
|
149
|
+
const extendObj = getOrCreateObjectProperty(themeObj, "extend");
|
|
150
|
+
if (extendObj) {
|
|
151
|
+
// Merge animations
|
|
152
|
+
const animations = newConfig.theme.extend.animation;
|
|
153
|
+
if (animations) {
|
|
154
|
+
const animObj = getOrCreateObjectProperty(extendObj, "animation");
|
|
155
|
+
if (animObj) {
|
|
156
|
+
for (const [key, value] of Object.entries(animations)) {
|
|
157
|
+
if (!animObj.getProperty(key)) {
|
|
158
|
+
animObj.addPropertyAssignment({ name: `"${key}"`, initializer: `"${value}"` });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Merge keyframes
|
|
165
|
+
const keyframes = newConfig.theme.extend.keyframes;
|
|
166
|
+
if (keyframes) {
|
|
167
|
+
const keyframesObj = getOrCreateObjectProperty(extendObj, "keyframes");
|
|
168
|
+
if (keyframesObj) {
|
|
169
|
+
for (const [key, value] of Object.entries(keyframes)) {
|
|
170
|
+
if (!keyframesObj.getProperty(key)) {
|
|
171
|
+
// value is an object, strictly JSON stringify might be valid JS valid object literal needed?
|
|
172
|
+
// "JSON.stringify(value)" produces valid JSON which is valid JS object literal initializer if keys are quoted.
|
|
173
|
+
keyframesObj.addPropertyAssignment({ name: `"${key}"`, initializer: JSON.stringify(value) });
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
await sourceFile.save();
|
|
183
|
+
console.log(chalk.green("Tailwind config updated successfully."));
|
|
184
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import prompts from "prompts";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
|
|
7
|
+
export async function init() {
|
|
8
|
+
console.log(chalk.bold.green("Initializing UniqueUI..."));
|
|
9
|
+
|
|
10
|
+
const cwd = process.cwd();
|
|
11
|
+
|
|
12
|
+
const response = await prompts([
|
|
13
|
+
{
|
|
14
|
+
type: "text",
|
|
15
|
+
name: "componentsDir",
|
|
16
|
+
message: "Where would you like to install components?",
|
|
17
|
+
initial: "components/ui",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
type: "toggle",
|
|
21
|
+
name: "typescript",
|
|
22
|
+
message: "Are you using TypeScript?",
|
|
23
|
+
initial: true,
|
|
24
|
+
active: "yes",
|
|
25
|
+
inactive: "no",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
type: "text",
|
|
29
|
+
name: "tailwindConfig",
|
|
30
|
+
message: "Where is your tailwind.config.js located?",
|
|
31
|
+
initial: "tailwind.config.ts",
|
|
32
|
+
},
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
const config = {
|
|
36
|
+
$schema: "https://uniqueui.com/schema.json",
|
|
37
|
+
style: "default",
|
|
38
|
+
rsc: true,
|
|
39
|
+
tsx: response.typescript,
|
|
40
|
+
tailwind: {
|
|
41
|
+
config: response.tailwindConfig,
|
|
42
|
+
css: "app/globals.css", // simplifying assumption or could ask
|
|
43
|
+
baseColor: "slate",
|
|
44
|
+
cssVariables: true,
|
|
45
|
+
},
|
|
46
|
+
aliases: {
|
|
47
|
+
components: "@/components",
|
|
48
|
+
utils: "@/lib/utils",
|
|
49
|
+
},
|
|
50
|
+
paths: {
|
|
51
|
+
components: response.componentsDir,
|
|
52
|
+
lib: "lib" // simplifying
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
await fs.writeFile(
|
|
57
|
+
path.join(cwd, "components.json"),
|
|
58
|
+
JSON.stringify(config, null, 2)
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
console.log(chalk.green("Configuration saved to components.json"));
|
|
62
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { init } from "./commands/init";
|
|
4
|
+
import { add } from "./commands/add";
|
|
5
|
+
|
|
6
|
+
const program = new Command();
|
|
7
|
+
|
|
8
|
+
program
|
|
9
|
+
.name("uniqueui")
|
|
10
|
+
.description("Add components from UniqueUI to your project")
|
|
11
|
+
.version("0.1.0");
|
|
12
|
+
|
|
13
|
+
program
|
|
14
|
+
.command("init")
|
|
15
|
+
.description("Configure your project for UniqueUI")
|
|
16
|
+
.action(init);
|
|
17
|
+
|
|
18
|
+
program
|
|
19
|
+
.command("add")
|
|
20
|
+
.description("Add a component to your project")
|
|
21
|
+
.argument("<component>", "the component to add")
|
|
22
|
+
.option("--url <url>", "the base URL of the registry", "https://raw.githubusercontent.com/prashantkumarsingh/uniqueui/main")
|
|
23
|
+
.action(add);
|
|
24
|
+
|
|
25
|
+
program.parse();
|