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