materialme-cli 0.0.1
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.d.ts +1 -0
- package/dist/commands/add.js +100 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +108 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +13 -0
- package/dist/registry/index.d.ts +4 -0
- package/dist/registry/index.js +36 -0
- package/dist/types.d.ts +30 -0
- package/dist/types.js +1 -0
- package/package.json +30 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function addCommand(componentName?: string): Promise<void>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import prompts from "prompts";
|
|
4
|
+
import { fetchRegistryIndex, fetchComponent, getRegistryDependencies } from "../registry/index.js";
|
|
5
|
+
const CONFIG_FILE = "components.json";
|
|
6
|
+
export async function addCommand(componentName) {
|
|
7
|
+
const projectRoot = process.cwd();
|
|
8
|
+
const configPath = path.join(projectRoot, CONFIG_FILE);
|
|
9
|
+
// Load config
|
|
10
|
+
if (!await fs.pathExists(configPath)) {
|
|
11
|
+
console.error("Error: components.json not found. Run 'materialme init' first.");
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const config = await fs.readJSON(configPath);
|
|
15
|
+
// Fetch registry index
|
|
16
|
+
let index;
|
|
17
|
+
try {
|
|
18
|
+
index = await fetchRegistryIndex(config.registry);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
console.error(error);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
// If no component specified, show available components
|
|
25
|
+
if (!componentName) {
|
|
26
|
+
const components = Object.keys(index);
|
|
27
|
+
if (components.length === 0) {
|
|
28
|
+
console.log("No components available in registry.");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const response = await prompts({
|
|
32
|
+
type: "multiselect",
|
|
33
|
+
name: "components",
|
|
34
|
+
message: "Which components would you like to add?",
|
|
35
|
+
choices: components.map((name) => ({ title: name, value: name })),
|
|
36
|
+
});
|
|
37
|
+
if (!response.components || response.components.length === 0) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
for (const name of response.components) {
|
|
41
|
+
await installComponent(name, index, config, projectRoot);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
await installComponent(componentName, index, config, projectRoot);
|
|
46
|
+
}
|
|
47
|
+
console.log("\n✓ Done!");
|
|
48
|
+
}
|
|
49
|
+
async function installComponent(name, index, config, projectRoot) {
|
|
50
|
+
const component = await fetchComponent(name, config.registry);
|
|
51
|
+
if (!component) {
|
|
52
|
+
console.error(`Component "${name}" not found in registry.`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
console.log(`\nInstalling ${name}...`);
|
|
56
|
+
// Get all registry dependencies
|
|
57
|
+
const deps = getRegistryDependencies(component, index);
|
|
58
|
+
const allComponents = [component, ...deps];
|
|
59
|
+
// Install npm dependencies
|
|
60
|
+
if (component.dependencies && component.dependencies.length > 0) {
|
|
61
|
+
console.log(`Installing npm dependencies: ${component.dependencies.join(", ")}`);
|
|
62
|
+
const { execSync } = await import("child_process");
|
|
63
|
+
try {
|
|
64
|
+
execSync(`npm install ${component.dependencies.join(" ")}`, {
|
|
65
|
+
stdio: "inherit",
|
|
66
|
+
cwd: projectRoot,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.error("Failed to install dependencies");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Create directories and write files
|
|
74
|
+
for (const comp of allComponents) {
|
|
75
|
+
for (const file of comp.files) {
|
|
76
|
+
const targetPath = path.join(projectRoot, file.path);
|
|
77
|
+
const targetDir = path.dirname(targetPath);
|
|
78
|
+
await fs.ensureDir(targetDir);
|
|
79
|
+
if (file.url) {
|
|
80
|
+
// Fetch from URL
|
|
81
|
+
try {
|
|
82
|
+
const response = await fetch(file.url);
|
|
83
|
+
const content = await response.text();
|
|
84
|
+
await fs.writeFile(targetPath, content);
|
|
85
|
+
console.log(` ✓ ${file.path}`);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
console.error(` ✗ Failed to fetch ${file.url}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (file.content) {
|
|
92
|
+
await fs.writeFile(targetPath, file.content);
|
|
93
|
+
console.log(` ✓ ${file.path}`);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
console.log(` ⚠ ${file.path} (no content)`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function initCommand(): Promise<void>;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import prompts from "prompts";
|
|
4
|
+
const DEFAULT_CONFIG = {
|
|
5
|
+
style: "default",
|
|
6
|
+
tailwind: {
|
|
7
|
+
config: "tailwind.config.js",
|
|
8
|
+
css: "src/app/globals.css",
|
|
9
|
+
baseColor: "slate",
|
|
10
|
+
},
|
|
11
|
+
aliases: {
|
|
12
|
+
utils: "@/lib/utils",
|
|
13
|
+
components: "@/components",
|
|
14
|
+
lib: "@/lib",
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
export async function initCommand() {
|
|
18
|
+
console.log("Initializing materialme components...\n");
|
|
19
|
+
const projectRoot = process.cwd();
|
|
20
|
+
// Check if package.json exists
|
|
21
|
+
const packageJsonPath = path.join(projectRoot, "package.json");
|
|
22
|
+
if (!await fs.pathExists(packageJsonPath)) {
|
|
23
|
+
console.error("Error: package.json not found. Run 'npm init' first.");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
// Ask for configuration options
|
|
27
|
+
const response = await prompts([
|
|
28
|
+
{
|
|
29
|
+
type: "select",
|
|
30
|
+
name: "style",
|
|
31
|
+
message: "Which style would you like to use?",
|
|
32
|
+
choices: [
|
|
33
|
+
{ title: "Default", value: "default" },
|
|
34
|
+
{ title: "New York", value: "new-york" },
|
|
35
|
+
],
|
|
36
|
+
initial: 0,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
type: "text",
|
|
40
|
+
name: "componentsDir",
|
|
41
|
+
message: "Components directory:",
|
|
42
|
+
initial: "components",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
type: "text",
|
|
46
|
+
name: "utilsDir",
|
|
47
|
+
message: "Utils directory:",
|
|
48
|
+
initial: "lib",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
type: "text",
|
|
52
|
+
name: "registryUrl",
|
|
53
|
+
message: "Registry URL (optional):",
|
|
54
|
+
initial: "",
|
|
55
|
+
},
|
|
56
|
+
]);
|
|
57
|
+
const config = {
|
|
58
|
+
style: response.style || "default",
|
|
59
|
+
tailwind: DEFAULT_CONFIG.tailwind,
|
|
60
|
+
aliases: {
|
|
61
|
+
utils: `@/${response.utilsDir || "lib"}/utils`,
|
|
62
|
+
components: `@/${response.componentsDir || "components"}`,
|
|
63
|
+
lib: `@/${response.utilsDir || "lib"}`,
|
|
64
|
+
},
|
|
65
|
+
registry: response.registryUrl || undefined,
|
|
66
|
+
};
|
|
67
|
+
// Create components.json
|
|
68
|
+
const configPath = path.join(projectRoot, "components.json");
|
|
69
|
+
await fs.writeJSON(configPath, config, { spaces: 2 });
|
|
70
|
+
console.log(`✓ Created components.json`);
|
|
71
|
+
// Create component directories
|
|
72
|
+
const componentsPath = path.join(projectRoot, response.componentsDir || "components");
|
|
73
|
+
const utilsPath = path.join(projectRoot, response.utilsDir || "lib");
|
|
74
|
+
await fs.ensureDir(componentsPath);
|
|
75
|
+
console.log(`✓ Created components directory: ${componentsPath}`);
|
|
76
|
+
await fs.ensureDir(utilsPath);
|
|
77
|
+
console.log(`✓ Created utils directory: ${utilsPath}`);
|
|
78
|
+
// Create utils.ts if it doesn't exist
|
|
79
|
+
const utilsFilePath = path.join(utilsPath, "utils.ts");
|
|
80
|
+
if (!await fs.pathExists(utilsFilePath)) {
|
|
81
|
+
const utilsContent = `import { clsx, type ClassValue } from "clsx"
|
|
82
|
+
import { twMerge } from "tailwind-merge"
|
|
83
|
+
|
|
84
|
+
export function cn(...inputs: ClassValue[]) {
|
|
85
|
+
return twMerge(clsx(...inputs))
|
|
86
|
+
}
|
|
87
|
+
`;
|
|
88
|
+
await fs.writeFile(utilsFilePath, utilsContent);
|
|
89
|
+
console.log(`✓ Created utils.ts`);
|
|
90
|
+
}
|
|
91
|
+
// Install dependencies
|
|
92
|
+
console.log("\nInstalling dependencies...");
|
|
93
|
+
const { execSync } = await import("child_process");
|
|
94
|
+
try {
|
|
95
|
+
execSync("npm install -D tailwind-merge clsx class-variance-authority", {
|
|
96
|
+
stdio: "inherit",
|
|
97
|
+
cwd: projectRoot,
|
|
98
|
+
});
|
|
99
|
+
console.log("✓ Dependencies installed");
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
console.error("Failed to install dependencies. Please install manually:");
|
|
103
|
+
console.error(" npm install -D tailwind-merge clsx class-variance-authority");
|
|
104
|
+
}
|
|
105
|
+
console.log("\n✓ Initialization complete!");
|
|
106
|
+
console.log("\nYou can now add components with:");
|
|
107
|
+
console.log(" npx materialme add <component-name>");
|
|
108
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { initCommand } from "./commands/init.js";
|
|
3
|
+
import { addCommand } from "./commands/add.js";
|
|
4
|
+
const [, , cmd] = process.argv;
|
|
5
|
+
if (cmd === "init") {
|
|
6
|
+
initCommand();
|
|
7
|
+
}
|
|
8
|
+
else if (cmd === "add") {
|
|
9
|
+
addCommand();
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
console.log("Usage: materialme <init|add>");
|
|
13
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { RegistryIndex, RegistryComponent } from "../types.js";
|
|
2
|
+
export declare function fetchRegistryIndex(registryUrl?: string): Promise<RegistryIndex>;
|
|
3
|
+
export declare function fetchComponent(name: string, registryUrl?: string): Promise<RegistryComponent | null>;
|
|
4
|
+
export declare function getRegistryDependencies(component: RegistryComponent, index: RegistryIndex): RegistryComponent[];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const DEFAULT_REGISTRY_URL = "https://raw.githubusercontent.com/vladislavkors/materialme/main/registry.json";
|
|
2
|
+
export async function fetchRegistryIndex(registryUrl) {
|
|
3
|
+
const url = registryUrl || DEFAULT_REGISTRY_URL;
|
|
4
|
+
try {
|
|
5
|
+
const response = await fetch(url);
|
|
6
|
+
if (!response.ok) {
|
|
7
|
+
throw new Error(`Failed to fetch registry from ${url}: ${response.statusText}`);
|
|
8
|
+
}
|
|
9
|
+
const data = await response.json();
|
|
10
|
+
return data;
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (error instanceof Error) {
|
|
14
|
+
throw new Error(`Could not fetch registry index: ${error.message}`);
|
|
15
|
+
}
|
|
16
|
+
throw new Error(`Could not fetch registry index`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export async function fetchComponent(name, registryUrl) {
|
|
20
|
+
const index = await fetchRegistryIndex(registryUrl);
|
|
21
|
+
return index[name] || null;
|
|
22
|
+
}
|
|
23
|
+
export function getRegistryDependencies(component, index) {
|
|
24
|
+
const deps = [];
|
|
25
|
+
if (!component.registryDependencies) {
|
|
26
|
+
return deps;
|
|
27
|
+
}
|
|
28
|
+
for (const depName of component.registryDependencies) {
|
|
29
|
+
const dep = index[depName];
|
|
30
|
+
if (dep) {
|
|
31
|
+
deps.push(dep);
|
|
32
|
+
deps.push(...getRegistryDependencies(dep, index));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return deps;
|
|
36
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface ComponentConfig {
|
|
2
|
+
style: "default" | "new-york";
|
|
3
|
+
tailwind: {
|
|
4
|
+
config: string;
|
|
5
|
+
css: string;
|
|
6
|
+
baseColor: string;
|
|
7
|
+
};
|
|
8
|
+
aliases: {
|
|
9
|
+
utils: string;
|
|
10
|
+
components: string;
|
|
11
|
+
lib: string;
|
|
12
|
+
};
|
|
13
|
+
registry?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface RegistryComponent {
|
|
16
|
+
name: string;
|
|
17
|
+
type: "component" | "hook" | "util" | "style";
|
|
18
|
+
files: RegistryFile[];
|
|
19
|
+
dependencies?: string[];
|
|
20
|
+
registryDependencies?: string[];
|
|
21
|
+
}
|
|
22
|
+
export interface RegistryFile {
|
|
23
|
+
path: string;
|
|
24
|
+
type: "component" | "util" | "style";
|
|
25
|
+
content?: string;
|
|
26
|
+
url?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface RegistryIndex {
|
|
29
|
+
[name: string]: RegistryComponent;
|
|
30
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "materialme-cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Material Me CLI for adding components",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/vladislavkors/materialme.git"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"materialme": "dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"fs-extra": "^11.1.1",
|
|
22
|
+
"prompts": "^2.4.2"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/fs-extra": "^11.0.4",
|
|
26
|
+
"@types/node": "^20.11.0",
|
|
27
|
+
"@types/prompts": "^2.4.9",
|
|
28
|
+
"typescript": "^5.3.3"
|
|
29
|
+
}
|
|
30
|
+
}
|