rewampui 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,40 @@
1
+ #!/usr/bin/env node
2
+ import { runAdd } from '../src/commands/add.js';
3
+ import { runInit } from '../src/commands/init.js';
4
+
5
+ const [, , command, ...args] = process.argv;
6
+
7
+ async function main() {
8
+ if (command === 'init') {
9
+ await runInit(args);
10
+ return;
11
+ }
12
+
13
+ if (command === 'add') {
14
+ await runAdd(args);
15
+ return;
16
+ }
17
+
18
+ console.log(`rewampui <command>
19
+
20
+ Commands:
21
+ init Create a components.json config in the current project
22
+ add <component...> Copy one or more component sources + deps into your project
23
+ add --all Install every component in the registry
24
+
25
+ Examples:
26
+ npx rewampui init
27
+ npx rewampui add theme-toggle
28
+ npx rewampui add arch-card-carousel theme-toggle
29
+ npx rewampui add --all
30
+
31
+ pnpm dlx rewampui add theme-toggle
32
+ bunx rewampui add theme-toggle
33
+ yarn dlx rewampui add theme-toggle`);
34
+ process.exit(command ? 1 : 0);
35
+ }
36
+
37
+ main().catch((err) => {
38
+ console.error(`✖ ${err.message}`);
39
+ process.exit(1);
40
+ });
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "rewampui",
3
+ "version": "0.1.0",
4
+ "description": "CLI to add Rewamp UI components' source code directly into your project.",
5
+ "type": "module",
6
+ "bin": {
7
+ "rewampui": "bin/rewampui.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "src"
12
+ ],
13
+ "dependencies": {
14
+ "prompts": "^2.4.2"
15
+ },
16
+ "engines": {
17
+ "node": ">=18"
18
+ },
19
+ "license": "MIT",
20
+ "author": "palakonweb",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/palakonweb/Rewamp-UI.git",
24
+ "directory": "cli"
25
+ },
26
+ "homepage": "https://github.com/palakonweb/Rewamp-UI#readme",
27
+ "keywords": [
28
+ "react",
29
+ "components",
30
+ "ui",
31
+ "cli",
32
+ "framer-motion",
33
+ "tailwind"
34
+ ]
35
+ }
@@ -0,0 +1,69 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { spawnSync } from 'node:child_process';
4
+ import {
5
+ readConfig,
6
+ fetchRegistryItem,
7
+ readSourceFile,
8
+ listAllRegistryNames,
9
+ } from '../utils/registry.js';
10
+ import { detectPackageManager, installArgs, installCommand } from '../utils/package-manager.js';
11
+
12
+ export async function runAdd(args) {
13
+ if (args.length === 0) {
14
+ throw new Error('Usage: rewampui add <component...> | rewampui add --all');
15
+ }
16
+
17
+ const cwd = process.cwd();
18
+ const config = readConfig(cwd);
19
+ const componentsDir = path.resolve(cwd, config.aliases?.components || 'src/components/ui');
20
+
21
+ const names = args.includes('--all') ? listAllRegistryNames() : args;
22
+ if (names.length === 0) {
23
+ throw new Error('No components found in the registry.');
24
+ }
25
+
26
+ const resolved = new Map(); // name -> registry item
27
+ const queue = [...names];
28
+ while (queue.length) {
29
+ const name = queue.shift();
30
+ if (resolved.has(name)) continue;
31
+ const item = await fetchRegistryItem(name, config);
32
+ resolved.set(name, item);
33
+ for (const dep of item.registryDependencies || []) {
34
+ if (!resolved.has(dep)) queue.push(dep);
35
+ }
36
+ }
37
+
38
+ const npmDeps = new Set();
39
+ fs.mkdirSync(componentsDir, { recursive: true });
40
+
41
+ for (const [name, item] of resolved) {
42
+ for (const dep of item.npmDependencies || []) npmDeps.add(dep);
43
+
44
+ for (const file of item.files) {
45
+ const targetPath = path.join(componentsDir, file.target);
46
+ const wasExplicitlyRequested = names.includes(name) || names.includes('--all');
47
+ if (fs.existsSync(targetPath) && !wasExplicitlyRequested) {
48
+ console.log(`- skip ${file.target} (already exists)`);
49
+ continue;
50
+ }
51
+ const source = await readSourceFile(file.source, config);
52
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
53
+ fs.writeFileSync(targetPath, source, 'utf8');
54
+ console.log(`+ added ${file.target}`);
55
+ }
56
+ }
57
+
58
+ if (npmDeps.size > 0) {
59
+ const pm = detectPackageManager(cwd);
60
+ const deps = [...npmDeps];
61
+ console.log(`\nInstalling dependencies with ${pm}: ${installCommand(pm, deps)}`);
62
+ const result = spawnSync(pm, installArgs(pm, deps), { cwd, stdio: 'inherit', shell: true });
63
+ if (result.status !== 0) {
64
+ throw new Error(`Failed to install dependencies. Run manually: ${installCommand(pm, deps)}`);
65
+ }
66
+ }
67
+
68
+ console.log(`\nDone. Added: ${[...resolved.keys()].join(', ')}`);
69
+ }
@@ -0,0 +1,27 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ const REPO_RAW_BASE = 'https://raw.githubusercontent.com/palakonweb/Rewamp-UI/main';
5
+
6
+ const DEFAULT_CONFIG = {
7
+ $schema: `${REPO_RAW_BASE}/registry/schema.json`,
8
+ registryUrl: `${REPO_RAW_BASE}/registry`,
9
+ repoRawUrl: REPO_RAW_BASE,
10
+ aliases: {
11
+ components: 'src/components/ui',
12
+ },
13
+ };
14
+
15
+ export async function runInit(args) {
16
+ const cwd = process.cwd();
17
+ const configPath = path.join(cwd, 'components.json');
18
+
19
+ if (fs.existsSync(configPath) && !args.includes('--force')) {
20
+ console.log('components.json already exists. Pass --force to overwrite.');
21
+ return;
22
+ }
23
+
24
+ fs.writeFileSync(configPath, `${JSON.stringify(DEFAULT_CONFIG, null, 2)}\n`, 'utf8');
25
+ console.log('+ created components.json');
26
+ console.log('\nNow run: npx rewampui add <component>');
27
+ }
@@ -0,0 +1,50 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ const LOCKFILES = [
5
+ { file: 'bun.lockb', pm: 'bun' },
6
+ { file: 'pnpm-lock.yaml', pm: 'pnpm' },
7
+ { file: 'yarn.lock', pm: 'yarn' },
8
+ { file: 'package-lock.json', pm: 'npm' },
9
+ ];
10
+
11
+ /** Walks up from cwd looking for a lockfile to infer the project's package manager. */
12
+ export function detectPackageManager(cwd = process.cwd()) {
13
+ let dir = cwd;
14
+ while (true) {
15
+ for (const { file, pm } of LOCKFILES) {
16
+ if (fs.existsSync(path.join(dir, file))) return pm;
17
+ }
18
+ const parent = path.dirname(dir);
19
+ if (parent === dir) break;
20
+ dir = parent;
21
+ }
22
+ return 'npm';
23
+ }
24
+
25
+ export function installCommand(pm, packages) {
26
+ const list = packages.join(' ');
27
+ switch (pm) {
28
+ case 'pnpm':
29
+ return `pnpm add ${list}`;
30
+ case 'yarn':
31
+ return `yarn add ${list}`;
32
+ case 'bun':
33
+ return `bun add ${list}`;
34
+ default:
35
+ return `npm install ${list}`;
36
+ }
37
+ }
38
+
39
+ export function installArgs(pm, packages) {
40
+ switch (pm) {
41
+ case 'pnpm':
42
+ return ['add', ...packages];
43
+ case 'yarn':
44
+ return ['add', ...packages];
45
+ case 'bun':
46
+ return ['add', ...packages];
47
+ default:
48
+ return ['install', ...packages];
49
+ }
50
+ }
@@ -0,0 +1,56 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
+ // When developing inside the RewampUI monorepo the registry lives two levels up.
7
+ // A real published install falls back to fetching from components.json's registryUrl.
8
+ const LOCAL_REGISTRY_DIR = path.resolve(__dirname, '../../../registry');
9
+
10
+ export function readConfig(cwd = process.cwd()) {
11
+ const configPath = path.join(cwd, 'components.json');
12
+ if (!fs.existsSync(configPath)) {
13
+ throw new Error(
14
+ 'No components.json found in this project. Run `npx rewampui init` first (or copy components.json from the RewampUI repo).'
15
+ );
16
+ }
17
+ return JSON.parse(fs.readFileSync(configPath, 'utf8'));
18
+ }
19
+
20
+ export async function fetchRegistryItem(name, config) {
21
+ const localPath = path.join(LOCAL_REGISTRY_DIR, `${name}.json`);
22
+ if (fs.existsSync(localPath)) {
23
+ return JSON.parse(fs.readFileSync(localPath, 'utf8'));
24
+ }
25
+
26
+ const url = `${config.registryUrl.replace(/\/$/, '')}/${name}.json`;
27
+ const res = await fetch(url);
28
+ if (!res.ok) {
29
+ throw new Error(`Component "${name}" not found in registry (${url})`);
30
+ }
31
+ return res.json();
32
+ }
33
+
34
+ export function listAllRegistryNames() {
35
+ if (!fs.existsSync(LOCAL_REGISTRY_DIR)) return [];
36
+ return fs
37
+ .readdirSync(LOCAL_REGISTRY_DIR)
38
+ .filter((f) => f.endsWith('.json') && f !== 'schema.json')
39
+ .map((f) => f.replace(/\.json$/, ''));
40
+ }
41
+
42
+ /** Resolves a file's raw source, either from local disk (monorepo dev) or over HTTP. */
43
+ export async function readSourceFile(source, config) {
44
+ const localPath = path.resolve(LOCAL_REGISTRY_DIR, '..', source);
45
+ if (fs.existsSync(localPath)) {
46
+ return fs.readFileSync(localPath, 'utf8');
47
+ }
48
+
49
+ // Outside the monorepo (a real published install) there's no local registry/
50
+ // folder — fall back to fetching the file straight from the public GitHub repo.
51
+ const base = config?.repoRawUrl || config?.registryUrl?.replace(/\/registry\/?$/, '');
52
+ const url = base ? `${base.replace(/\/$/, '')}/${source}` : source;
53
+ const res = await fetch(url);
54
+ if (!res.ok) throw new Error(`Could not fetch source file: ${url}`);
55
+ return res.text();
56
+ }