@jvxtor-react/cli 0.0.0-stage → 1.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.
package/bin/index.js ADDED
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ import { cancel, intro, isCancel, log, outro, select } from "@clack/prompts";
3
+ import { detectPM, install } from "../src/utils.js";
4
+ import { setupShadcn } from "../src/shadcn.js";
5
+
6
+ const comando = process.argv[2];
7
+
8
+ if (comando !== "init") {
9
+ console.log("Uso: npx @jvxtor-react/cli init");
10
+ process.exit(0);
11
+ }
12
+
13
+ intro("@jvxtor-react/cli");
14
+
15
+ const escolha = await select({
16
+ message: "Qual lib de estilização você quer instalar?",
17
+ options: [
18
+ { value: "shadcn", label: "shadcn + Tailwind CSS" },
19
+ { value: "antd", label: "Ant Design" },
20
+ { value: "bootstrap", label: "Bootstrap" },
21
+ ],
22
+ });
23
+
24
+ if (isCancel(escolha)) {
25
+ cancel("Cancelado.");
26
+ process.exit(0);
27
+ }
28
+
29
+ try {
30
+ if (escolha === "shadcn") setupShadcn();
31
+
32
+ if (escolha === "antd") install(detectPM(), ["antd"]);
33
+
34
+ if (escolha === "bootstrap") {
35
+ install(detectPM(), ["bootstrap"]);
36
+ log.info(
37
+ 'Importe no seu main: import "bootstrap/dist/css/bootstrap.min.css"',
38
+ );
39
+ }
40
+
41
+ outro("Pronto!");
42
+ } catch (err) {
43
+ log.error(err.message);
44
+ process.exit(1);
45
+ }
package/package.json CHANGED
@@ -1,6 +1,20 @@
1
1
  {
2
2
  "name": "@jvxtor-react/cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.2",
4
+ "description": "CLI para configurar a lib de estilização em projetos React + Vite",
5
+ "type": "module",
6
+ "bin": {
7
+ "jvxtor-react": "./bin/index.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "src"
12
+ ],
13
+ "engines": {
14
+ "node": ">=18"
15
+ },
16
+ "dependencies": {
17
+ "@clack/prompts": "^0.11.0",
18
+ "jsonc-parser": "^3.3.1"
19
+ }
6
20
  }
package/src/shadcn.js ADDED
@@ -0,0 +1,141 @@
1
+ import fs from "node:fs"
2
+ import path from "node:path"
3
+ import { applyEdits, modify } from "jsonc-parser"
4
+ import { log } from "@clack/prompts"
5
+ import {
6
+ detectPM,
7
+ execPackage,
8
+ findClosingBracket,
9
+ install,
10
+ } from "./utils.js"
11
+
12
+ const VITE_CONFIGS = [
13
+ "vite.config.ts",
14
+ "vite.config.mts",
15
+ "vite.config.js",
16
+ "vite.config.mjs",
17
+ ]
18
+
19
+ const ALIAS_SNIPPET = `resolve: {
20
+ alias: {
21
+ "@": path.resolve(__dirname, "./src"),
22
+ },
23
+ }`
24
+
25
+ // 2. vite.config: plugin do Tailwind + alias "@"
26
+ export function patchViteConfig(cwd) {
27
+ const file = VITE_CONFIGS.map((f) => path.join(cwd, f)).find((f) =>
28
+ fs.existsSync(f)
29
+ )
30
+ if (!file) {
31
+ log.warn("vite.config não encontrado. Adicione o plugin e o alias manualmente.")
32
+ return
33
+ }
34
+
35
+ let src = fs.readFileSync(file, "utf8")
36
+ const imports = []
37
+
38
+ if (!/from\s+["'](node:)?path["']/.test(src)) {
39
+ imports.push('import path from "path"')
40
+ }
41
+ if (!src.includes("@tailwindcss/vite")) {
42
+ imports.push('import tailwindcss from "@tailwindcss/vite"')
43
+ }
44
+
45
+ const pluginsIdx = src.search(/plugins\s*:\s*\[/)
46
+ if (pluginsIdx === -1) {
47
+ log.warn(`Não achei "plugins: [...]" em ${path.basename(file)}. Adicione tailwindcss() e o alias manualmente.`)
48
+ return
49
+ }
50
+ const open = src.indexOf("[", pluginsIdx)
51
+ const close = findClosingBracket(src, open)
52
+ if (close === -1) {
53
+ log.warn(`Não consegui interpretar ${path.basename(file)}. Edite manualmente.`)
54
+ return
55
+ }
56
+
57
+ let inner = src.slice(open + 1, close)
58
+ if (!/tailwindcss\s*\(/.test(inner)) {
59
+ const trimmed = inner.trimEnd()
60
+ const sep = trimmed === "" ? "" : trimmed.endsWith(",") ? " " : ", "
61
+ inner = trimmed + sep + "tailwindcss()"
62
+ }
63
+
64
+ let after = src.slice(close + 1)
65
+ if (!/resolve\s*:/.test(src)) {
66
+ after = `,\n ${ALIAS_SNIPPET}` + after
67
+ } else if (!/alias\s*:/.test(src)) {
68
+ log.warn('Já existe "resolve" no vite.config sem "alias". Adicione o alias "@" manualmente.')
69
+ }
70
+
71
+ src = src.slice(0, open + 1) + inner + "]" + after
72
+ if (imports.length) src = imports.join("\n") + "\n" + src
73
+
74
+ fs.writeFileSync(file, src)
75
+ log.success(`${path.basename(file)} atualizado`)
76
+ }
77
+
78
+ // 3. CSS com @import "tailwindcss"
79
+ export function writeCss(cwd) {
80
+ const file = path.join(cwd, "src", "index.css")
81
+ fs.mkdirSync(path.dirname(file), { recursive: true })
82
+ fs.writeFileSync(file, '@import "tailwindcss";\n')
83
+ log.success("src/index.css atualizado")
84
+ }
85
+
86
+ function addAlias(file) {
87
+ let text = fs.readFileSync(file, "utf8")
88
+ const fmt = { formattingOptions: { insertSpaces: true, tabSize: 2 } }
89
+ text = applyEdits(text, modify(text, ["compilerOptions", "baseUrl"], ".", fmt))
90
+ text = applyEdits(
91
+ text,
92
+ modify(text, ["compilerOptions", "paths"], { "@/*": ["./src/*"] }, fmt)
93
+ )
94
+ fs.writeFileSync(file, text)
95
+ log.success(`${path.basename(file)} atualizado`)
96
+ }
97
+
98
+ // 4. Alias no TypeScript (ou jsconfig.json em projetos JS)
99
+ export function patchTsconfig(cwd) {
100
+ const ts = fs.existsSync(path.join(cwd, "tsconfig.json"))
101
+ if (!ts) {
102
+ const js = path.join(cwd, "jsconfig.json")
103
+ if (!fs.existsSync(js)) fs.writeFileSync(js, "{}\n")
104
+ addAlias(js)
105
+ return
106
+ }
107
+ addAlias(path.join(cwd, "tsconfig.json"))
108
+ const app = path.join(cwd, "tsconfig.app.json")
109
+ if (fs.existsSync(app)) addAlias(app)
110
+ }
111
+
112
+ export function setupShadcn(cwd = process.cwd()) {
113
+ const pkgPath = path.join(cwd, "package.json")
114
+ if (!fs.existsSync(pkgPath)) {
115
+ throw new Error("package.json não encontrado. Rode o comando na raiz do projeto.")
116
+ }
117
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"))
118
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies }
119
+ if (!deps.vite) {
120
+ throw new Error("Este projeto não parece usar Vite.")
121
+ }
122
+
123
+ const pm = detectPM(cwd)
124
+ const isTs = fs.existsSync(path.join(cwd, "tsconfig.json"))
125
+
126
+ log.step("1/5 Instalando Tailwind e o plugin do Vite")
127
+ install(pm, ["tailwindcss", "@tailwindcss/vite"], { cwd })
128
+ if (isTs) install(pm, ["@types/node"], { dev: true, cwd })
129
+
130
+ log.step("2/5 Configurando vite.config")
131
+ patchViteConfig(cwd)
132
+
133
+ log.step("3/5 Configurando o CSS")
134
+ writeCss(cwd)
135
+
136
+ log.step("4/5 Configurando o alias @")
137
+ patchTsconfig(cwd)
138
+
139
+ log.step("5/5 Inicializando o shadcn")
140
+ execPackage(pm, "shadcn@latest init", { cwd })
141
+ }
package/src/utils.js ADDED
@@ -0,0 +1,44 @@
1
+ import fs from "node:fs"
2
+ import path from "node:path"
3
+ import { execSync } from "node:child_process"
4
+
5
+ export function detectPM(cwd = process.cwd()) {
6
+ const has = (f) => fs.existsSync(path.join(cwd, f))
7
+ if (has("pnpm-lock.yaml")) return "pnpm"
8
+ if (has("yarn.lock")) return "yarn"
9
+ if (has("bun.lockb") || has("bun.lock")) return "bun"
10
+ return "npm"
11
+ }
12
+
13
+ const COMMANDS = {
14
+ npm: { add: "npm install", addDev: "npm install -D", exec: "npx" },
15
+ pnpm: { add: "pnpm add", addDev: "pnpm add -D", exec: "pnpm dlx" },
16
+ yarn: { add: "yarn add", addDev: "yarn add -D", exec: "npx" },
17
+ bun: { add: "bun add", addDev: "bun add -d", exec: "bunx" },
18
+ }
19
+
20
+ export function run(cmd, cwd = process.cwd()) {
21
+ execSync(cmd, { stdio: "inherit", cwd })
22
+ }
23
+
24
+ export function install(pm, packages, { dev = false, cwd } = {}) {
25
+ const base = dev ? COMMANDS[pm].addDev : COMMANDS[pm].add
26
+ run(`${base} ${packages.join(" ")}`, cwd)
27
+ }
28
+
29
+ export function execPackage(pm, command, { cwd } = {}) {
30
+ run(`${COMMANDS[pm].exec} ${command}`, cwd)
31
+ }
32
+
33
+ // Acha o índice do "]" que fecha o "[" em openIndex (considera colchetes aninhados)
34
+ export function findClosingBracket(src, openIndex) {
35
+ let depth = 0
36
+ for (let i = openIndex; i < src.length; i++) {
37
+ if (src[i] === "[") depth++
38
+ if (src[i] === "]") {
39
+ depth--
40
+ if (depth === 0) return i
41
+ }
42
+ }
43
+ return -1
44
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.