@famgia/omnify-laravel 0.0.14 → 0.0.15
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/{chunk-UVF7W2J2.js → chunk-REDFZUQY.js} +550 -15
- package/dist/chunk-REDFZUQY.js.map +1 -0
- package/dist/index.cjs +549 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/plugin.cjs +547 -14
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +16 -1
- package/dist/plugin.d.ts +16 -1
- package/dist/plugin.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-UVF7W2J2.js.map +0 -1
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// src/plugin.ts
|
|
2
|
+
import { readFileSync, existsSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
|
|
1
5
|
// src/migration/schema-builder.ts
|
|
2
6
|
var TYPE_METHOD_MAP = {
|
|
3
7
|
String: "string",
|
|
@@ -76,9 +80,8 @@ function propertyToColumnMethod(propertyName, property) {
|
|
|
76
80
|
if (baseProp.unique) {
|
|
77
81
|
modifiers.push({ method: "unique" });
|
|
78
82
|
}
|
|
79
|
-
if (baseProp.default !== void 0) {
|
|
80
|
-
|
|
81
|
-
modifiers.push({ method: "default", args: [defaultValue] });
|
|
83
|
+
if (baseProp.default !== void 0 && baseProp.default !== null) {
|
|
84
|
+
modifiers.push({ method: "default", args: [baseProp.default] });
|
|
82
85
|
}
|
|
83
86
|
if (baseProp.unsigned && (method === "integer" || method === "bigInteger")) {
|
|
84
87
|
modifiers.push({ method: "unsigned" });
|
|
@@ -314,6 +317,12 @@ function formatColumnMethod(column) {
|
|
|
314
317
|
if (typeof arg === "string") {
|
|
315
318
|
return `'${arg}'`;
|
|
316
319
|
}
|
|
320
|
+
if (typeof arg === "boolean") {
|
|
321
|
+
return arg ? "true" : "false";
|
|
322
|
+
}
|
|
323
|
+
if (typeof arg === "number") {
|
|
324
|
+
return String(arg);
|
|
325
|
+
}
|
|
317
326
|
return String(arg);
|
|
318
327
|
}).join(", ");
|
|
319
328
|
code += `->${modifier.method}(${modArgs})`;
|
|
@@ -421,6 +430,7 @@ function generatePivotTableBlueprint(pivot) {
|
|
|
421
430
|
args: [pivot.targetColumn],
|
|
422
431
|
modifiers: []
|
|
423
432
|
});
|
|
433
|
+
columns.push(...generateTimestampColumns());
|
|
424
434
|
foreignKeys.push({
|
|
425
435
|
columns: [pivot.sourceColumn],
|
|
426
436
|
references: "id",
|
|
@@ -1150,7 +1160,7 @@ function generateEntityBaseModel(schema, schemas, options, stubContent, authStub
|
|
|
1150
1160
|
if (assoc.target) {
|
|
1151
1161
|
imports.push(`use ${options.modelNamespace}\\${toPascalCase(assoc.target)};`);
|
|
1152
1162
|
}
|
|
1153
|
-
relations.push(generateRelation(propName, assoc, options));
|
|
1163
|
+
relations.push(generateRelation(propName, assoc, schema, schemas, options));
|
|
1154
1164
|
if (assoc.relation === "ManyToOne" || assoc.relation === "OneToOne") {
|
|
1155
1165
|
if (!assoc.mappedBy) {
|
|
1156
1166
|
const fkName = toSnakeCase(propName) + "_id";
|
|
@@ -1207,7 +1217,22 @@ ${docProperties.join("\n")}
|
|
|
1207
1217
|
schemaName: schema.name
|
|
1208
1218
|
};
|
|
1209
1219
|
}
|
|
1210
|
-
function
|
|
1220
|
+
function findInverseRelation(currentSchemaName, targetSchemaName, schemas) {
|
|
1221
|
+
const targetSchema = schemas[targetSchemaName];
|
|
1222
|
+
if (!targetSchema || !targetSchema.properties) {
|
|
1223
|
+
return null;
|
|
1224
|
+
}
|
|
1225
|
+
for (const [propName, propDef] of Object.entries(targetSchema.properties)) {
|
|
1226
|
+
if (propDef.type === "Association") {
|
|
1227
|
+
const assoc = propDef;
|
|
1228
|
+
if (assoc.relation === "ManyToOne" && assoc.target === currentSchemaName) {
|
|
1229
|
+
return propName;
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
return null;
|
|
1234
|
+
}
|
|
1235
|
+
function generateRelation(propName, assoc, schema, schemas, options) {
|
|
1211
1236
|
const methodName = toCamelCase(propName);
|
|
1212
1237
|
const targetClass = assoc.target ? toPascalCase(assoc.target) : "";
|
|
1213
1238
|
const fkName = toSnakeCase(propName) + "_id";
|
|
@@ -1237,14 +1262,28 @@ function generateRelation(propName, assoc, options) {
|
|
|
1237
1262
|
{
|
|
1238
1263
|
return $this->belongsTo(${targetClass}::class, '${fkName}');
|
|
1239
1264
|
}`;
|
|
1240
|
-
case "OneToMany":
|
|
1265
|
+
case "OneToMany": {
|
|
1266
|
+
let foreignKey;
|
|
1267
|
+
if (assoc.inversedBy) {
|
|
1268
|
+
foreignKey = toSnakeCase(assoc.inversedBy) + "_id";
|
|
1269
|
+
} else if (assoc.target) {
|
|
1270
|
+
const inverseRelation = findInverseRelation(schema.name, assoc.target, schemas);
|
|
1271
|
+
if (inverseRelation) {
|
|
1272
|
+
foreignKey = toSnakeCase(inverseRelation) + "_id";
|
|
1273
|
+
} else {
|
|
1274
|
+
foreignKey = toSnakeCase(schema.name) + "_id";
|
|
1275
|
+
}
|
|
1276
|
+
} else {
|
|
1277
|
+
foreignKey = toSnakeCase(propName) + "_id";
|
|
1278
|
+
}
|
|
1241
1279
|
return ` /**
|
|
1242
1280
|
* Get the ${propName} for this model.
|
|
1243
1281
|
*/
|
|
1244
1282
|
public function ${methodName}(): HasMany
|
|
1245
1283
|
{
|
|
1246
|
-
return $this->hasMany(${targetClass}::class, '${
|
|
1284
|
+
return $this->hasMany(${targetClass}::class, '${foreignKey}');
|
|
1247
1285
|
}`;
|
|
1286
|
+
}
|
|
1248
1287
|
case "ManyToMany": {
|
|
1249
1288
|
const pivotTable = assoc.joinTable ?? `${toSnakeCase(propName)}_pivot`;
|
|
1250
1289
|
return ` /**
|
|
@@ -1541,14 +1580,73 @@ class {{CLASS_NAME}} extends {{CLASS_NAME}}BaseModel
|
|
|
1541
1580
|
|
|
1542
1581
|
// Add your custom methods here
|
|
1543
1582
|
}
|
|
1583
|
+
`,
|
|
1584
|
+
"service-provider": `<?php
|
|
1585
|
+
|
|
1586
|
+
namespace App\\Providers;
|
|
1587
|
+
|
|
1588
|
+
use Illuminate\\Database\\Eloquent\\Relations\\Relation;
|
|
1589
|
+
use Illuminate\\Support\\ServiceProvider;
|
|
1590
|
+
|
|
1591
|
+
/**
|
|
1592
|
+
* Omnify Service Provider
|
|
1593
|
+
*
|
|
1594
|
+
* DO NOT EDIT - This file is auto-generated by Omnify.
|
|
1595
|
+
* Any changes will be overwritten on next generation.
|
|
1596
|
+
*
|
|
1597
|
+
* - Loads Omnify migrations from database/migrations/omnify
|
|
1598
|
+
* - Registers morph map for polymorphic relationships
|
|
1599
|
+
*
|
|
1600
|
+
* @generated by @famgia/omnify-laravel
|
|
1601
|
+
*/
|
|
1602
|
+
class OmnifyServiceProvider extends ServiceProvider
|
|
1603
|
+
{
|
|
1604
|
+
/**
|
|
1605
|
+
* Register any application services.
|
|
1606
|
+
*/
|
|
1607
|
+
public function register(): void
|
|
1608
|
+
{
|
|
1609
|
+
//
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
/**
|
|
1613
|
+
* Bootstrap any application services.
|
|
1614
|
+
*/
|
|
1615
|
+
public function boot(): void
|
|
1616
|
+
{
|
|
1617
|
+
// Load Omnify migrations from custom directory
|
|
1618
|
+
$this->loadMigrationsFrom(database_path('migrations/omnify'));
|
|
1619
|
+
|
|
1620
|
+
// Register morph map for polymorphic relationships
|
|
1621
|
+
Relation::enforceMorphMap([
|
|
1622
|
+
{{MORPH_MAP}}
|
|
1623
|
+
]);
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1544
1626
|
`
|
|
1545
1627
|
};
|
|
1546
1628
|
return stubs[stubName] ?? "";
|
|
1547
1629
|
}
|
|
1630
|
+
function generateServiceProvider(schemas, options, stubContent) {
|
|
1631
|
+
const morphMap = Object.values(schemas).filter((s) => s.kind !== "enum").map((s) => {
|
|
1632
|
+
const className = toPascalCase(s.name);
|
|
1633
|
+
return ` '${s.name}' => \\${options.modelNamespace}\\${className}::class,`;
|
|
1634
|
+
}).join("\n");
|
|
1635
|
+
const content = stubContent.replace(/\{\{MORPH_MAP\}\}/g, morphMap);
|
|
1636
|
+
return {
|
|
1637
|
+
path: "app/Providers/OmnifyServiceProvider.php",
|
|
1638
|
+
content,
|
|
1639
|
+
type: "service-provider",
|
|
1640
|
+
overwrite: true,
|
|
1641
|
+
// Always overwrite to keep morph map in sync
|
|
1642
|
+
schemaName: "__service_provider__"
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1548
1645
|
function generateModels(schemas, options) {
|
|
1549
1646
|
const resolved = resolveOptions(options);
|
|
1550
1647
|
const models = [];
|
|
1551
1648
|
models.push(generateBaseModel(schemas, resolved, getStubContent("base-model")));
|
|
1649
|
+
models.push(generateServiceProvider(schemas, resolved, getStubContent("service-provider")));
|
|
1552
1650
|
for (const schema of Object.values(schemas)) {
|
|
1553
1651
|
if (schema.kind === "enum") {
|
|
1554
1652
|
continue;
|
|
@@ -1567,6 +1665,355 @@ function generateModels(schemas, options) {
|
|
|
1567
1665
|
function getModelPath(model) {
|
|
1568
1666
|
return model.path;
|
|
1569
1667
|
}
|
|
1668
|
+
function generateProviderRegistration(existingContent, laravelVersion) {
|
|
1669
|
+
const providerClass = "App\\Providers\\OmnifyServiceProvider::class";
|
|
1670
|
+
const providerLine = ` ${providerClass},`;
|
|
1671
|
+
if (existingContent && existingContent.includes("OmnifyServiceProvider")) {
|
|
1672
|
+
return {
|
|
1673
|
+
path: laravelVersion === "laravel11+" ? "bootstrap/providers.php" : "config/app.php",
|
|
1674
|
+
content: existingContent,
|
|
1675
|
+
laravelVersion,
|
|
1676
|
+
alreadyRegistered: true
|
|
1677
|
+
};
|
|
1678
|
+
}
|
|
1679
|
+
if (laravelVersion === "laravel11+") {
|
|
1680
|
+
if (existingContent) {
|
|
1681
|
+
const lines = existingContent.split("\n");
|
|
1682
|
+
const result = [];
|
|
1683
|
+
let inserted = false;
|
|
1684
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1685
|
+
const line = lines[i];
|
|
1686
|
+
if (!inserted && line.trim() === "];") {
|
|
1687
|
+
result.push(providerLine);
|
|
1688
|
+
inserted = true;
|
|
1689
|
+
}
|
|
1690
|
+
result.push(line);
|
|
1691
|
+
}
|
|
1692
|
+
return {
|
|
1693
|
+
path: "bootstrap/providers.php",
|
|
1694
|
+
content: result.join("\n"),
|
|
1695
|
+
laravelVersion,
|
|
1696
|
+
alreadyRegistered: false
|
|
1697
|
+
};
|
|
1698
|
+
} else {
|
|
1699
|
+
return {
|
|
1700
|
+
path: "bootstrap/providers.php",
|
|
1701
|
+
content: `<?php
|
|
1702
|
+
|
|
1703
|
+
return [
|
|
1704
|
+
App\\Providers\\AppServiceProvider::class,
|
|
1705
|
+
${providerLine}
|
|
1706
|
+
];
|
|
1707
|
+
`,
|
|
1708
|
+
laravelVersion,
|
|
1709
|
+
alreadyRegistered: false
|
|
1710
|
+
};
|
|
1711
|
+
}
|
|
1712
|
+
} else {
|
|
1713
|
+
if (existingContent) {
|
|
1714
|
+
const providersSectionRegex = /'providers'\s*=>\s*\[[\s\S]*?\n(\s*)\]/m;
|
|
1715
|
+
const match = existingContent.match(providersSectionRegex);
|
|
1716
|
+
if (match) {
|
|
1717
|
+
const providersStart = existingContent.indexOf("'providers'");
|
|
1718
|
+
if (providersStart === -1) {
|
|
1719
|
+
return null;
|
|
1720
|
+
}
|
|
1721
|
+
let depth = 0;
|
|
1722
|
+
let foundStart = false;
|
|
1723
|
+
let insertPos = -1;
|
|
1724
|
+
for (let i = providersStart; i < existingContent.length; i++) {
|
|
1725
|
+
const char = existingContent[i];
|
|
1726
|
+
if (char === "[") {
|
|
1727
|
+
foundStart = true;
|
|
1728
|
+
depth++;
|
|
1729
|
+
} else if (char === "]") {
|
|
1730
|
+
depth--;
|
|
1731
|
+
if (foundStart && depth === 0) {
|
|
1732
|
+
insertPos = i;
|
|
1733
|
+
break;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
if (insertPos !== -1) {
|
|
1738
|
+
const beforeClose = existingContent.substring(0, insertPos);
|
|
1739
|
+
const lastNewline = beforeClose.lastIndexOf("\n");
|
|
1740
|
+
const content = existingContent.substring(0, lastNewline + 1) + providerLine + "\n" + existingContent.substring(lastNewline + 1);
|
|
1741
|
+
return {
|
|
1742
|
+
path: "config/app.php",
|
|
1743
|
+
content,
|
|
1744
|
+
laravelVersion,
|
|
1745
|
+
alreadyRegistered: false
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
return null;
|
|
1750
|
+
} else {
|
|
1751
|
+
return null;
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
// src/factory/generator.ts
|
|
1757
|
+
function resolveOptions2(options) {
|
|
1758
|
+
return {
|
|
1759
|
+
modelNamespace: options?.modelNamespace ?? "App\\Models",
|
|
1760
|
+
factoryPath: options?.factoryPath ?? "database/factories",
|
|
1761
|
+
fakerLocale: options?.fakerLocale ?? "en_US"
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1764
|
+
function getStubContent2() {
|
|
1765
|
+
return `<?php
|
|
1766
|
+
|
|
1767
|
+
namespace Database\\Factories;
|
|
1768
|
+
|
|
1769
|
+
use {{MODEL_NAMESPACE}}\\{{MODEL_NAME}};
|
|
1770
|
+
use Illuminate\\Database\\Eloquent\\Factories\\Factory;
|
|
1771
|
+
{{IMPORTS}}
|
|
1772
|
+
|
|
1773
|
+
/**
|
|
1774
|
+
* @extends Factory<{{MODEL_NAME}}>
|
|
1775
|
+
*/
|
|
1776
|
+
class {{MODEL_NAME}}Factory extends Factory
|
|
1777
|
+
{
|
|
1778
|
+
protected $model = {{MODEL_NAME}}::class;
|
|
1779
|
+
|
|
1780
|
+
/**
|
|
1781
|
+
* Define the model's default state.
|
|
1782
|
+
*
|
|
1783
|
+
* @return array<string, mixed>
|
|
1784
|
+
*/
|
|
1785
|
+
public function definition(): array
|
|
1786
|
+
{
|
|
1787
|
+
return [
|
|
1788
|
+
{{ATTRIBUTES}}
|
|
1789
|
+
];
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
`;
|
|
1793
|
+
}
|
|
1794
|
+
function generateFakeData(propertyName, property, schema, schemas) {
|
|
1795
|
+
const type = property.type;
|
|
1796
|
+
if (["deleted_at", "created_at", "updated_at"].includes(propertyName)) {
|
|
1797
|
+
return null;
|
|
1798
|
+
}
|
|
1799
|
+
if (type === "Association") {
|
|
1800
|
+
return null;
|
|
1801
|
+
}
|
|
1802
|
+
switch (type) {
|
|
1803
|
+
case "String":
|
|
1804
|
+
return generateStringFake(propertyName, property);
|
|
1805
|
+
case "Email":
|
|
1806
|
+
return `'${propertyName}' => fake()->unique()->safeEmail(),`;
|
|
1807
|
+
case "Password":
|
|
1808
|
+
return `'${propertyName}' => bcrypt('password'),`;
|
|
1809
|
+
case "Int":
|
|
1810
|
+
case "BigInt":
|
|
1811
|
+
return generateIntFake(propertyName, property);
|
|
1812
|
+
case "Float":
|
|
1813
|
+
case "Decimal":
|
|
1814
|
+
return `'${propertyName}' => fake()->randomFloat(2, 1, 10000),`;
|
|
1815
|
+
case "Boolean":
|
|
1816
|
+
return `'${propertyName}' => fake()->boolean(),`;
|
|
1817
|
+
case "Text":
|
|
1818
|
+
return `'${propertyName}' => fake()->paragraphs(3, true),`;
|
|
1819
|
+
case "LongText":
|
|
1820
|
+
return `'${propertyName}' => fake()->paragraphs(5, true),`;
|
|
1821
|
+
case "Date":
|
|
1822
|
+
return `'${propertyName}' => fake()->date(),`;
|
|
1823
|
+
case "Time":
|
|
1824
|
+
return `'${propertyName}' => fake()->time(),`;
|
|
1825
|
+
case "Timestamp":
|
|
1826
|
+
case "DateTime":
|
|
1827
|
+
return `'${propertyName}' => fake()->dateTime(),`;
|
|
1828
|
+
case "Json":
|
|
1829
|
+
return `'${propertyName}' => [],`;
|
|
1830
|
+
case "Enum":
|
|
1831
|
+
return generateEnumFake(propertyName, property);
|
|
1832
|
+
case "EnumRef":
|
|
1833
|
+
return generateEnumRefFake(propertyName, property, schemas);
|
|
1834
|
+
default:
|
|
1835
|
+
return `'${propertyName}' => fake()->sentence(),`;
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
function generateStringFake(propertyName, property) {
|
|
1839
|
+
if (propertyName === "slug") {
|
|
1840
|
+
return `'${propertyName}' => fake()->unique()->slug(),`;
|
|
1841
|
+
}
|
|
1842
|
+
if (propertyName === "uuid" || propertyName === "uid") {
|
|
1843
|
+
return `'${propertyName}' => (string) \\Illuminate\\Support\\Str::uuid(),`;
|
|
1844
|
+
}
|
|
1845
|
+
if (propertyName.includes("email")) {
|
|
1846
|
+
return `'${propertyName}' => fake()->unique()->safeEmail(),`;
|
|
1847
|
+
}
|
|
1848
|
+
if (propertyName.includes("phone")) {
|
|
1849
|
+
return `'${propertyName}' => fake()->phoneNumber(),`;
|
|
1850
|
+
}
|
|
1851
|
+
if (propertyName.includes("image") || propertyName.includes("photo") || propertyName.includes("avatar")) {
|
|
1852
|
+
return `'${propertyName}' => fake()->imageUrl(),`;
|
|
1853
|
+
}
|
|
1854
|
+
if (propertyName.includes("url") || propertyName.includes("website")) {
|
|
1855
|
+
return `'${propertyName}' => fake()->url(),`;
|
|
1856
|
+
}
|
|
1857
|
+
if (propertyName.includes("path") || propertyName.includes("file")) {
|
|
1858
|
+
return `'${propertyName}' => 'uploads/' . fake()->uuid() . '.jpg',`;
|
|
1859
|
+
}
|
|
1860
|
+
if (propertyName === "name" || propertyName === "title") {
|
|
1861
|
+
return `'${propertyName}' => fake()->sentence(3),`;
|
|
1862
|
+
}
|
|
1863
|
+
if (propertyName.includes("name")) {
|
|
1864
|
+
return `'${propertyName}' => fake()->name(),`;
|
|
1865
|
+
}
|
|
1866
|
+
if (propertyName.includes("address")) {
|
|
1867
|
+
return `'${propertyName}' => fake()->address(),`;
|
|
1868
|
+
}
|
|
1869
|
+
if (propertyName.includes("city")) {
|
|
1870
|
+
return `'${propertyName}' => fake()->city(),`;
|
|
1871
|
+
}
|
|
1872
|
+
if (propertyName.includes("country")) {
|
|
1873
|
+
return `'${propertyName}' => fake()->country(),`;
|
|
1874
|
+
}
|
|
1875
|
+
if (propertyName.includes("zip") || propertyName.includes("postal")) {
|
|
1876
|
+
return `'${propertyName}' => fake()->postcode(),`;
|
|
1877
|
+
}
|
|
1878
|
+
if (propertyName.includes("color")) {
|
|
1879
|
+
return `'${propertyName}' => fake()->hexColor(),`;
|
|
1880
|
+
}
|
|
1881
|
+
if (propertyName.includes("token") || propertyName.includes("secret") || propertyName.includes("key")) {
|
|
1882
|
+
return `'${propertyName}' => \\Illuminate\\Support\\Str::random(32),`;
|
|
1883
|
+
}
|
|
1884
|
+
if (propertyName.includes("code")) {
|
|
1885
|
+
return `'${propertyName}' => fake()->unique()->regexify('[A-Z0-9]{8}'),`;
|
|
1886
|
+
}
|
|
1887
|
+
const length = property.length;
|
|
1888
|
+
if (length && length <= 50) {
|
|
1889
|
+
return `'${propertyName}' => fake()->words(3, true),`;
|
|
1890
|
+
}
|
|
1891
|
+
return `'${propertyName}' => fake()->sentence(),`;
|
|
1892
|
+
}
|
|
1893
|
+
function generateIntFake(propertyName, property) {
|
|
1894
|
+
if (propertyName.includes("count") || propertyName.includes("quantity")) {
|
|
1895
|
+
return `'${propertyName}' => fake()->numberBetween(0, 100),`;
|
|
1896
|
+
}
|
|
1897
|
+
if (propertyName.includes("price") || propertyName.includes("amount") || propertyName.includes("cost")) {
|
|
1898
|
+
return `'${propertyName}' => fake()->numberBetween(100, 10000),`;
|
|
1899
|
+
}
|
|
1900
|
+
if (propertyName.includes("order") || propertyName.includes("sort") || propertyName.includes("position")) {
|
|
1901
|
+
return `'${propertyName}' => fake()->numberBetween(1, 100),`;
|
|
1902
|
+
}
|
|
1903
|
+
if (propertyName.includes("age")) {
|
|
1904
|
+
return `'${propertyName}' => fake()->numberBetween(18, 80),`;
|
|
1905
|
+
}
|
|
1906
|
+
if (propertyName.includes("year")) {
|
|
1907
|
+
return `'${propertyName}' => fake()->year(),`;
|
|
1908
|
+
}
|
|
1909
|
+
return `'${propertyName}' => fake()->numberBetween(1, 1000),`;
|
|
1910
|
+
}
|
|
1911
|
+
function generateEnumFake(propertyName, property) {
|
|
1912
|
+
const enumValues = property.enum;
|
|
1913
|
+
if (!enumValues || enumValues.length === 0) {
|
|
1914
|
+
return `'${propertyName}' => null,`;
|
|
1915
|
+
}
|
|
1916
|
+
const values = enumValues.map((v) => typeof v === "string" ? v : v.value);
|
|
1917
|
+
const valuesStr = values.map((v) => `'${v}'`).join(", ");
|
|
1918
|
+
return `'${propertyName}' => fake()->randomElement([${valuesStr}]),`;
|
|
1919
|
+
}
|
|
1920
|
+
function generateEnumRefFake(propertyName, property, schemas) {
|
|
1921
|
+
const enumName = property.enum;
|
|
1922
|
+
if (!enumName) {
|
|
1923
|
+
return `'${propertyName}' => null,`;
|
|
1924
|
+
}
|
|
1925
|
+
const enumSchema = schemas[enumName];
|
|
1926
|
+
if (!enumSchema || enumSchema.kind !== "enum" || !enumSchema.values) {
|
|
1927
|
+
return `'${propertyName}' => null,`;
|
|
1928
|
+
}
|
|
1929
|
+
const valuesStr = enumSchema.values.map((v) => `'${v}'`).join(", ");
|
|
1930
|
+
return `'${propertyName}' => fake()->randomElement([${valuesStr}]),`;
|
|
1931
|
+
}
|
|
1932
|
+
function generateAssociationFake(propertyName, property, schema, schemas, modelNamespace) {
|
|
1933
|
+
if (property.type !== "Association") {
|
|
1934
|
+
return null;
|
|
1935
|
+
}
|
|
1936
|
+
const relation = property.relation;
|
|
1937
|
+
const target = property.target;
|
|
1938
|
+
if (relation !== "ManyToOne" || !target) {
|
|
1939
|
+
return null;
|
|
1940
|
+
}
|
|
1941
|
+
const foreignKey = `${toSnakeCase(propertyName)}_id`;
|
|
1942
|
+
const isNullable2 = property.nullable ?? false;
|
|
1943
|
+
const targetSchema = schemas[target];
|
|
1944
|
+
if (!targetSchema) {
|
|
1945
|
+
return null;
|
|
1946
|
+
}
|
|
1947
|
+
let fake;
|
|
1948
|
+
if (isNullable2) {
|
|
1949
|
+
fake = `'${foreignKey}' => ${target}::query()->inRandomOrder()->first()?->id,`;
|
|
1950
|
+
} else {
|
|
1951
|
+
fake = `'${foreignKey}' => ${target}::query()->inRandomOrder()->first()?->id ?? ${target}::factory()->create()->id,`;
|
|
1952
|
+
}
|
|
1953
|
+
let importStatement;
|
|
1954
|
+
if (target !== schema.name) {
|
|
1955
|
+
importStatement = `use ${modelNamespace}\\${target};`;
|
|
1956
|
+
}
|
|
1957
|
+
return { fake, import: importStatement };
|
|
1958
|
+
}
|
|
1959
|
+
function generateFactory(schema, schemas, options, stubContent) {
|
|
1960
|
+
if (schema.kind === "enum") {
|
|
1961
|
+
return null;
|
|
1962
|
+
}
|
|
1963
|
+
const modelName = toPascalCase(schema.name);
|
|
1964
|
+
const factoryName = `${modelName}Factory`;
|
|
1965
|
+
const attributes = [];
|
|
1966
|
+
const imports = [];
|
|
1967
|
+
if (schema.properties) {
|
|
1968
|
+
for (const [propName, prop] of Object.entries(schema.properties)) {
|
|
1969
|
+
if (prop.type === "Association") {
|
|
1970
|
+
const assocResult = generateAssociationFake(propName, prop, schema, schemas, options.modelNamespace);
|
|
1971
|
+
if (assocResult) {
|
|
1972
|
+
attributes.push(assocResult.fake);
|
|
1973
|
+
if (assocResult.import) {
|
|
1974
|
+
imports.push(assocResult.import);
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
continue;
|
|
1978
|
+
}
|
|
1979
|
+
const fake = generateFakeData(propName, prop, schema, schemas);
|
|
1980
|
+
if (fake) {
|
|
1981
|
+
attributes.push(fake);
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
let content = stubContent;
|
|
1986
|
+
content = content.replace(/\{\{MODEL_NAMESPACE\}\}/g, options.modelNamespace);
|
|
1987
|
+
content = content.replace(/\{\{MODEL_NAME\}\}/g, modelName);
|
|
1988
|
+
const uniqueImports = [...new Set(imports)];
|
|
1989
|
+
const importsStr = uniqueImports.length > 0 ? "\n" + uniqueImports.join("\n") : "";
|
|
1990
|
+
content = content.replace(/\{\{IMPORTS\}\}/g, importsStr);
|
|
1991
|
+
const attributesStr = attributes.length > 0 ? attributes.map((a) => ` ${a}`).join("\n") : "";
|
|
1992
|
+
content = content.replace(/\{\{ATTRIBUTES\}\}/g, attributesStr);
|
|
1993
|
+
return {
|
|
1994
|
+
name: factoryName,
|
|
1995
|
+
schemaName: schema.name,
|
|
1996
|
+
path: `${options.factoryPath}/${factoryName}.php`,
|
|
1997
|
+
content,
|
|
1998
|
+
overwrite: false
|
|
1999
|
+
// Factories should not overwrite existing files
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
2002
|
+
function generateFactories(schemas, options) {
|
|
2003
|
+
const resolved = resolveOptions2(options);
|
|
2004
|
+
const stubContent = getStubContent2();
|
|
2005
|
+
const factories = [];
|
|
2006
|
+
for (const schema of Object.values(schemas)) {
|
|
2007
|
+
const factory = generateFactory(schema, schemas, resolved, stubContent);
|
|
2008
|
+
if (factory) {
|
|
2009
|
+
factories.push(factory);
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
return factories;
|
|
2013
|
+
}
|
|
2014
|
+
function getFactoryPath(factory) {
|
|
2015
|
+
return factory.path;
|
|
2016
|
+
}
|
|
1570
2017
|
|
|
1571
2018
|
// src/plugin.ts
|
|
1572
2019
|
var LARAVEL_CONFIG_SCHEMA = {
|
|
@@ -1575,8 +2022,8 @@ var LARAVEL_CONFIG_SCHEMA = {
|
|
|
1575
2022
|
key: "migrationsPath",
|
|
1576
2023
|
type: "path",
|
|
1577
2024
|
label: "Migrations Path",
|
|
1578
|
-
description: "Directory for Laravel migration files",
|
|
1579
|
-
default: "database/migrations",
|
|
2025
|
+
description: "Directory for Laravel migration files (loaded via OmnifyServiceProvider)",
|
|
2026
|
+
default: "database/migrations/omnify",
|
|
1580
2027
|
group: "output"
|
|
1581
2028
|
},
|
|
1582
2029
|
{
|
|
@@ -1603,6 +2050,22 @@ var LARAVEL_CONFIG_SCHEMA = {
|
|
|
1603
2050
|
default: true,
|
|
1604
2051
|
group: "options"
|
|
1605
2052
|
},
|
|
2053
|
+
{
|
|
2054
|
+
key: "factoriesPath",
|
|
2055
|
+
type: "path",
|
|
2056
|
+
label: "Factories Path",
|
|
2057
|
+
description: "Directory for Laravel factory files",
|
|
2058
|
+
default: "database/factories",
|
|
2059
|
+
group: "output"
|
|
2060
|
+
},
|
|
2061
|
+
{
|
|
2062
|
+
key: "generateFactories",
|
|
2063
|
+
type: "boolean",
|
|
2064
|
+
label: "Generate Factories",
|
|
2065
|
+
description: "Generate Laravel factory classes for testing",
|
|
2066
|
+
default: true,
|
|
2067
|
+
group: "options"
|
|
2068
|
+
},
|
|
1606
2069
|
{
|
|
1607
2070
|
key: "connection",
|
|
1608
2071
|
type: "string",
|
|
@@ -1613,20 +2076,23 @@ var LARAVEL_CONFIG_SCHEMA = {
|
|
|
1613
2076
|
}
|
|
1614
2077
|
]
|
|
1615
2078
|
};
|
|
1616
|
-
function
|
|
2079
|
+
function resolveOptions3(options) {
|
|
1617
2080
|
return {
|
|
1618
|
-
migrationsPath: options?.migrationsPath ?? "database/migrations",
|
|
2081
|
+
migrationsPath: options?.migrationsPath ?? "database/migrations/omnify",
|
|
1619
2082
|
modelsPath: options?.modelsPath ?? "app/Models",
|
|
1620
2083
|
baseModelsPath: options?.baseModelsPath ?? "app/Models/OmnifyBase",
|
|
1621
2084
|
modelNamespace: options?.modelNamespace ?? "App\\Models",
|
|
1622
2085
|
baseModelNamespace: options?.baseModelNamespace ?? "App\\Models\\OmnifyBase",
|
|
1623
2086
|
generateModels: options?.generateModels ?? true,
|
|
2087
|
+
factoriesPath: options?.factoriesPath ?? "database/factories",
|
|
2088
|
+
generateFactories: options?.generateFactories ?? true,
|
|
2089
|
+
fakerLocale: options?.fakerLocale ?? "en_US",
|
|
1624
2090
|
connection: options?.connection,
|
|
1625
2091
|
timestamp: options?.timestamp
|
|
1626
2092
|
};
|
|
1627
2093
|
}
|
|
1628
2094
|
function laravelPlugin(options) {
|
|
1629
|
-
const resolved =
|
|
2095
|
+
const resolved = resolveOptions3(options);
|
|
1630
2096
|
const migrationGenerator = {
|
|
1631
2097
|
name: "laravel-migrations",
|
|
1632
2098
|
description: "Generate Laravel migration files",
|
|
@@ -1658,7 +2124,7 @@ function laravelPlugin(options) {
|
|
|
1658
2124
|
baseModelPath: resolved.baseModelsPath
|
|
1659
2125
|
};
|
|
1660
2126
|
const models = generateModels(ctx.schemas, modelOptions);
|
|
1661
|
-
|
|
2127
|
+
const outputs = models.map((model) => ({
|
|
1662
2128
|
path: getModelPath(model),
|
|
1663
2129
|
content: model.content,
|
|
1664
2130
|
type: "model",
|
|
@@ -1669,13 +2135,82 @@ function laravelPlugin(options) {
|
|
|
1669
2135
|
schemaName: model.schemaName
|
|
1670
2136
|
}
|
|
1671
2137
|
}));
|
|
2138
|
+
const bootstrapProvidersPath = join(ctx.cwd, "bootstrap/providers.php");
|
|
2139
|
+
const configAppPath = join(ctx.cwd, "config/app.php");
|
|
2140
|
+
let existingContent = null;
|
|
2141
|
+
let laravelVersion;
|
|
2142
|
+
if (existsSync(bootstrapProvidersPath)) {
|
|
2143
|
+
laravelVersion = "laravel11+";
|
|
2144
|
+
try {
|
|
2145
|
+
existingContent = readFileSync(bootstrapProvidersPath, "utf-8");
|
|
2146
|
+
} catch {
|
|
2147
|
+
existingContent = null;
|
|
2148
|
+
}
|
|
2149
|
+
} else if (existsSync(configAppPath)) {
|
|
2150
|
+
laravelVersion = "laravel10-";
|
|
2151
|
+
try {
|
|
2152
|
+
existingContent = readFileSync(configAppPath, "utf-8");
|
|
2153
|
+
} catch {
|
|
2154
|
+
existingContent = null;
|
|
2155
|
+
}
|
|
2156
|
+
} else {
|
|
2157
|
+
laravelVersion = "laravel11+";
|
|
2158
|
+
}
|
|
2159
|
+
const registration = generateProviderRegistration(existingContent, laravelVersion);
|
|
2160
|
+
if (registration && !registration.alreadyRegistered) {
|
|
2161
|
+
outputs.push({
|
|
2162
|
+
path: registration.path,
|
|
2163
|
+
content: registration.content,
|
|
2164
|
+
type: "other",
|
|
2165
|
+
skipIfExists: false,
|
|
2166
|
+
// We want to modify the file
|
|
2167
|
+
metadata: {
|
|
2168
|
+
registrationType: "provider-registration",
|
|
2169
|
+
laravelVersion: registration.laravelVersion
|
|
2170
|
+
}
|
|
2171
|
+
});
|
|
2172
|
+
ctx.logger.info(`OmnifyServiceProvider will be registered in ${registration.path}`);
|
|
2173
|
+
} else if (registration?.alreadyRegistered) {
|
|
2174
|
+
ctx.logger.info("OmnifyServiceProvider is already registered");
|
|
2175
|
+
}
|
|
2176
|
+
return outputs;
|
|
2177
|
+
}
|
|
2178
|
+
};
|
|
2179
|
+
const factoryGenerator = {
|
|
2180
|
+
name: "laravel-factories",
|
|
2181
|
+
description: "Generate Laravel factory classes for testing",
|
|
2182
|
+
generate: async (ctx) => {
|
|
2183
|
+
const factoryOptions = {
|
|
2184
|
+
modelNamespace: resolved.modelNamespace,
|
|
2185
|
+
factoryPath: resolved.factoriesPath,
|
|
2186
|
+
fakerLocale: resolved.fakerLocale
|
|
2187
|
+
};
|
|
2188
|
+
const factories = generateFactories(ctx.schemas, factoryOptions);
|
|
2189
|
+
return factories.map((factory) => ({
|
|
2190
|
+
path: getFactoryPath(factory),
|
|
2191
|
+
content: factory.content,
|
|
2192
|
+
type: "factory",
|
|
2193
|
+
// Skip writing factories if they already exist (allow customization)
|
|
2194
|
+
skipIfExists: !factory.overwrite,
|
|
2195
|
+
metadata: {
|
|
2196
|
+
factoryName: factory.name,
|
|
2197
|
+
schemaName: factory.schemaName
|
|
2198
|
+
}
|
|
2199
|
+
}));
|
|
1672
2200
|
}
|
|
1673
2201
|
};
|
|
2202
|
+
const generators = [migrationGenerator];
|
|
2203
|
+
if (resolved.generateModels) {
|
|
2204
|
+
generators.push(modelGenerator);
|
|
2205
|
+
}
|
|
2206
|
+
if (resolved.generateFactories) {
|
|
2207
|
+
generators.push(factoryGenerator);
|
|
2208
|
+
}
|
|
1674
2209
|
return {
|
|
1675
2210
|
name: "@famgia/omnify-laravel",
|
|
1676
2211
|
version: "0.0.14",
|
|
1677
2212
|
configSchema: LARAVEL_CONFIG_SCHEMA,
|
|
1678
|
-
generators
|
|
2213
|
+
generators
|
|
1679
2214
|
};
|
|
1680
2215
|
}
|
|
1681
2216
|
|
|
@@ -1701,4 +2236,4 @@ export {
|
|
|
1701
2236
|
generateMigrationsFromChanges,
|
|
1702
2237
|
laravelPlugin
|
|
1703
2238
|
};
|
|
1704
|
-
//# sourceMappingURL=chunk-
|
|
2239
|
+
//# sourceMappingURL=chunk-REDFZUQY.js.map
|