@vira-ui/cli 1.0.2 → 1.1.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/index.js +75 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -91,7 +91,7 @@ const program = new commander_1.Command();
|
|
|
91
91
|
program
|
|
92
92
|
.name("vira")
|
|
93
93
|
.description("ViraJS CLI - Create projects and generate code")
|
|
94
|
-
.version("1.
|
|
94
|
+
.version("1.1.1");
|
|
95
95
|
const SUPPORTED_TEMPLATES = ["frontend", "fullstack", "kanban"];
|
|
96
96
|
/**
|
|
97
97
|
* Инициализация проекта в текущей директории
|
|
@@ -283,15 +283,6 @@ make
|
|
|
283
283
|
await generateGoHandler(name, options.dir);
|
|
284
284
|
console.log(chalk_1.default.green(`✓ handler ${name} created in ${options.dir}`));
|
|
285
285
|
});
|
|
286
|
-
make
|
|
287
|
-
.command("model")
|
|
288
|
-
.description("Create Go model struct")
|
|
289
|
-
.argument("<name>", "Model name (e.g. User)")
|
|
290
|
-
.option("-d, --dir <directory>", "Target directory", path.join("backend", "internal", "models"))
|
|
291
|
-
.action(async (name, options) => {
|
|
292
|
-
await generateGoModel(name, options.dir);
|
|
293
|
-
console.log(chalk_1.default.green(`✓ model ${name} created in ${options.dir}`));
|
|
294
|
-
});
|
|
295
286
|
make
|
|
296
287
|
.command("migration")
|
|
297
288
|
.description("Create SQL migration (up/down)")
|
|
@@ -310,6 +301,16 @@ make
|
|
|
310
301
|
await generateEventHandler(name, options.dir);
|
|
311
302
|
console.log(chalk_1.default.green(`✓ event handler ${name} created in ${options.dir}`));
|
|
312
303
|
});
|
|
304
|
+
make
|
|
305
|
+
.command("model")
|
|
306
|
+
.description("Create a Go model struct")
|
|
307
|
+
.argument("<name>", "Model name (e.g. Client)")
|
|
308
|
+
.option("-d, --dir <directory>", "Target directory", path.join("backend", "internal", "models"))
|
|
309
|
+
.option("-f, --fields <fields>", "Comma-separated field definitions (e.g. 'name:string,email:string,phone:string')")
|
|
310
|
+
.action(async (name, options) => {
|
|
311
|
+
await generateGoModel(name, options.dir, options.fields || undefined);
|
|
312
|
+
console.log(chalk_1.default.green(`✓ Go model ${name} created in ${options.dir}`));
|
|
313
|
+
});
|
|
313
314
|
make
|
|
314
315
|
.command("crud")
|
|
315
316
|
.description("Create CRUD handlers for a resource")
|
|
@@ -1184,7 +1185,7 @@ export function ${name}Page() {
|
|
|
1184
1185
|
/**
|
|
1185
1186
|
* Генерация модели
|
|
1186
1187
|
*/
|
|
1187
|
-
async function generateModel(name, dir) {
|
|
1188
|
+
async function generateModel(name, dir, fields) {
|
|
1188
1189
|
const modelPath = path.join(process.cwd(), dir, "models", `${name}.ts`);
|
|
1189
1190
|
await fs.ensureDir(path.dirname(modelPath));
|
|
1190
1191
|
const modelCode = `import { defineModel } from '@vira-ui/core';
|
|
@@ -1521,21 +1522,42 @@ func ${handlerName}(w http.ResponseWriter, r *http.Request) {
|
|
|
1521
1522
|
/**
|
|
1522
1523
|
* Go model scaffold
|
|
1523
1524
|
*/
|
|
1524
|
-
async function generateGoModel(name, dir) {
|
|
1525
|
+
async function generateGoModel(name, dir, fields) {
|
|
1525
1526
|
const modelName = capitalize(name);
|
|
1526
1527
|
const targetDir = path.join(process.cwd(), dir);
|
|
1527
1528
|
await fs.ensureDir(targetDir);
|
|
1529
|
+
// Парсим поля если указаны
|
|
1530
|
+
let fieldsCode = "";
|
|
1531
|
+
if (fields) {
|
|
1532
|
+
const fieldList = fields.split(",").map(f => f.trim());
|
|
1533
|
+
fieldsCode = fieldList.map(field => {
|
|
1534
|
+
const [fieldName, fieldType] = field.split(":").map(s => s.trim());
|
|
1535
|
+
const goType = mapTypeScriptToGo(fieldType || "string");
|
|
1536
|
+
return ` ${capitalize(fieldName)} ${goType} \`db:"${fieldName.toLowerCase()}" json:"${fieldName.toLowerCase()}"\``;
|
|
1537
|
+
}).join("\n");
|
|
1538
|
+
// Добавляем стандартные поля если их нет
|
|
1539
|
+
if (!fieldList.some(f => f.toLowerCase().includes("id"))) {
|
|
1540
|
+
fieldsCode = ` ID string \`db:"id" json:"id"\`
|
|
1541
|
+
${fieldsCode}
|
|
1542
|
+
CreatedAt time.Time \`db:"created_at" json:"created_at"\`
|
|
1543
|
+
UpdatedAt time.Time \`db:"updated_at" json:"updated_at"\``;
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
else {
|
|
1547
|
+
// Дефолтные поля для типичной модели
|
|
1548
|
+
fieldsCode = ` ID string \`db:"id" json:"id"\`
|
|
1549
|
+
CreatedAt time.Time \`db:"created_at" json:"created_at"\`
|
|
1550
|
+
UpdatedAt time.Time \`db:"updated_at" json:"updated_at"\``;
|
|
1551
|
+
}
|
|
1528
1552
|
const modelCode = `package models
|
|
1529
1553
|
|
|
1530
1554
|
import "time"
|
|
1531
1555
|
|
|
1532
1556
|
type ${modelName} struct {
|
|
1533
|
-
|
|
1534
|
-
CreatedAt time.Time \`db:"created_at"\`
|
|
1535
|
-
UpdatedAt time.Time \`db:"updated_at"\`
|
|
1557
|
+
${fieldsCode}
|
|
1536
1558
|
}
|
|
1537
1559
|
`;
|
|
1538
|
-
await fs.writeFile(path.join(targetDir, `${modelName}.go`), modelCode);
|
|
1560
|
+
await fs.writeFile(path.join(targetDir, `${modelName.toLowerCase()}.go`), modelCode);
|
|
1539
1561
|
}
|
|
1540
1562
|
/**
|
|
1541
1563
|
* SQL migration scaffold (timestamped up/down)
|
|
@@ -1583,6 +1605,19 @@ function capitalize(value) {
|
|
|
1583
1605
|
return value;
|
|
1584
1606
|
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
1585
1607
|
}
|
|
1608
|
+
/**
|
|
1609
|
+
* Маппинг TypeScript типов в Go типы
|
|
1610
|
+
*/
|
|
1611
|
+
function mapTypeScriptToGo(tsType) {
|
|
1612
|
+
const mapping = {
|
|
1613
|
+
"string": "string",
|
|
1614
|
+
"number": "int",
|
|
1615
|
+
"boolean": "bool",
|
|
1616
|
+
"Date": "time.Time",
|
|
1617
|
+
"date": "time.Time",
|
|
1618
|
+
};
|
|
1619
|
+
return mapping[tsType.toLowerCase()] || "string";
|
|
1620
|
+
}
|
|
1586
1621
|
function toPascal(value) {
|
|
1587
1622
|
return value
|
|
1588
1623
|
.split(/[^a-zA-Z0-9]+/)
|
|
@@ -1599,6 +1634,21 @@ async function generateCRUDHandler(name, dir, modelName) {
|
|
|
1599
1634
|
const model = modelName || capitalize(name);
|
|
1600
1635
|
const targetDir = path.join(process.cwd(), dir);
|
|
1601
1636
|
await fs.ensureDir(targetDir);
|
|
1637
|
+
// Попытка определить модуль из go.mod
|
|
1638
|
+
let modulePath = "your-project/backend";
|
|
1639
|
+
try {
|
|
1640
|
+
const goModPath = path.join(process.cwd(), dir, "..", "..", "go.mod");
|
|
1641
|
+
if (await fs.pathExists(goModPath)) {
|
|
1642
|
+
const goModContent = await fs.readFile(goModPath, "utf8");
|
|
1643
|
+
const moduleMatch = goModContent.match(/^module\\s+(.+)$/m);
|
|
1644
|
+
if (moduleMatch) {
|
|
1645
|
+
modulePath = moduleMatch[1];
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
catch (e) {
|
|
1650
|
+
// Игнорируем ошибки, используем дефолтный путь
|
|
1651
|
+
}
|
|
1602
1652
|
const handlerCode = `package handlers
|
|
1603
1653
|
|
|
1604
1654
|
import (
|
|
@@ -1609,6 +1659,8 @@ import (
|
|
|
1609
1659
|
"github.com/gorilla/mux"
|
|
1610
1660
|
"github.com/go-playground/validator/v10"
|
|
1611
1661
|
"github.com/google/uuid"
|
|
1662
|
+
|
|
1663
|
+
"${modulePath}/internal/models"
|
|
1612
1664
|
)
|
|
1613
1665
|
|
|
1614
1666
|
var validate = validator.New()
|
|
@@ -1622,7 +1674,7 @@ type PaginationParams struct {
|
|
|
1622
1674
|
|
|
1623
1675
|
// 🎯 Production-ready: List response with pagination
|
|
1624
1676
|
type ${handlerName}ListResponse struct {
|
|
1625
|
-
Items []
|
|
1677
|
+
Items []models.${model} \`json:"items"\`
|
|
1626
1678
|
Total int \`json:"total"\`
|
|
1627
1679
|
Limit int \`json:"limit"\`
|
|
1628
1680
|
Offset int \`json:"offset"\`
|
|
@@ -1635,8 +1687,8 @@ type ${handlerName}Event struct {
|
|
|
1635
1687
|
Type string \`json:"type"\` // created, updated, deleted
|
|
1636
1688
|
EntityID string \`json:"entity_id"\`
|
|
1637
1689
|
UserID string \`json:"user_id,omitempty"\`
|
|
1638
|
-
OldValue
|
|
1639
|
-
NewValue
|
|
1690
|
+
OldValue *models.${model} \`json:"old_value,omitempty"\`
|
|
1691
|
+
NewValue *models.${model} \`json:"new_value,omitempty"\`
|
|
1640
1692
|
Timestamp time.Time \`json:"timestamp"\`
|
|
1641
1693
|
}
|
|
1642
1694
|
|
|
@@ -1685,7 +1737,7 @@ func List${handlerName}(w http.ResponseWriter, r *http.Request) {
|
|
|
1685
1737
|
// }
|
|
1686
1738
|
|
|
1687
1739
|
response := ${handlerName}ListResponse{
|
|
1688
|
-
Items: []
|
|
1740
|
+
Items: []models.${model}{},
|
|
1689
1741
|
Total: 0,
|
|
1690
1742
|
Limit: limit,
|
|
1691
1743
|
Offset: offset,
|
|
@@ -1719,7 +1771,7 @@ func Get${handlerName}(w http.ResponseWriter, r *http.Request) {
|
|
|
1719
1771
|
// return
|
|
1720
1772
|
// }
|
|
1721
1773
|
|
|
1722
|
-
item :=
|
|
1774
|
+
item := models.${model}{ID: id}
|
|
1723
1775
|
|
|
1724
1776
|
// 🎯 Production-ready: Cache detail (TTL 5min)
|
|
1725
1777
|
// redis.Set(cacheKey, item, 5*time.Minute)
|
|
@@ -1729,7 +1781,7 @@ func Get${handlerName}(w http.ResponseWriter, r *http.Request) {
|
|
|
1729
1781
|
|
|
1730
1782
|
// Create${handlerName} handles POST /${safeName}
|
|
1731
1783
|
func Create${handlerName}(w http.ResponseWriter, r *http.Request) {
|
|
1732
|
-
var input
|
|
1784
|
+
var input models.${model}
|
|
1733
1785
|
|
|
1734
1786
|
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
|
1735
1787
|
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
|
@@ -1787,7 +1839,7 @@ func Update${handlerName}(w http.ResponseWriter, r *http.Request) {
|
|
|
1787
1839
|
vars := mux.Vars(r)
|
|
1788
1840
|
id := vars["id"]
|
|
1789
1841
|
|
|
1790
|
-
var input
|
|
1842
|
+
var input models.${model}
|
|
1791
1843
|
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
|
1792
1844
|
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
|
1793
1845
|
return
|