@famgia/omnify-laravel 0.0.12 → 0.0.14
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-2JWTIYRL.js → chunk-UVF7W2J2.js} +614 -519
- package/dist/chunk-UVF7W2J2.js.map +1 -0
- package/dist/index.cjs +613 -538
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -198
- package/dist/index.d.ts +1 -198
- package/dist/index.js +1 -41
- package/dist/plugin.cjs +613 -484
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +24 -19
- package/dist/plugin.d.ts +24 -19
- package/dist/plugin.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-2JWTIYRL.js.map +0 -1
package/dist/plugin.cjs
CHANGED
|
@@ -293,11 +293,18 @@ function schemaToBlueprint(schema, allSchemas) {
|
|
|
293
293
|
}
|
|
294
294
|
if (schema.options?.indexes) {
|
|
295
295
|
for (const index of schema.options.indexes) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
296
|
+
if (typeof index === "string") {
|
|
297
|
+
indexes.push({
|
|
298
|
+
columns: [toColumnName(index)],
|
|
299
|
+
unique: false
|
|
300
|
+
});
|
|
301
|
+
} else {
|
|
302
|
+
indexes.push({
|
|
303
|
+
name: index.name,
|
|
304
|
+
columns: index.columns.map(toColumnName),
|
|
305
|
+
unique: index.unique ?? false
|
|
306
|
+
});
|
|
307
|
+
}
|
|
301
308
|
}
|
|
302
309
|
}
|
|
303
310
|
if (schema.options?.unique) {
|
|
@@ -684,489 +691,611 @@ function getMigrationPath(migration, outputDir = "database/migrations") {
|
|
|
684
691
|
return `${outputDir}/${migration.fileName}`;
|
|
685
692
|
}
|
|
686
693
|
|
|
687
|
-
// src/
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
Int: "number",
|
|
691
|
-
BigInt: "number",
|
|
692
|
-
Float: "number",
|
|
693
|
-
Boolean: "boolean",
|
|
694
|
-
Text: "string",
|
|
695
|
-
LongText: "string",
|
|
696
|
-
Date: "string",
|
|
697
|
-
Time: "string",
|
|
698
|
-
Timestamp: "string",
|
|
699
|
-
Json: "unknown",
|
|
700
|
-
Email: "string",
|
|
701
|
-
Password: "string",
|
|
702
|
-
Enum: "string",
|
|
703
|
-
Select: "string",
|
|
704
|
-
Lookup: "number"
|
|
705
|
-
};
|
|
706
|
-
var FILE_INTERFACE_NAME = "File";
|
|
707
|
-
var PK_TYPE_MAP = {
|
|
708
|
-
Int: "number",
|
|
709
|
-
BigInt: "number",
|
|
710
|
-
Uuid: "string",
|
|
711
|
-
String: "string"
|
|
712
|
-
};
|
|
713
|
-
function toPropertyName(name) {
|
|
714
|
-
return name;
|
|
694
|
+
// src/utils.ts
|
|
695
|
+
function toSnakeCase(str) {
|
|
696
|
+
return str.replace(/([A-Z])/g, "_$1").replace(/^_/, "").toLowerCase();
|
|
715
697
|
}
|
|
716
|
-
function
|
|
717
|
-
return
|
|
698
|
+
function toPascalCase(str) {
|
|
699
|
+
return str.replace(/[-_](.)/g, (_, c) => c.toUpperCase()).replace(/^(.)/, (_, c) => c.toUpperCase());
|
|
718
700
|
}
|
|
719
|
-
function
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
return
|
|
726
|
-
}
|
|
727
|
-
if (property.type === "Association") {
|
|
728
|
-
const assocProp = property;
|
|
729
|
-
const targetName = assocProp.target ?? "unknown";
|
|
730
|
-
switch (assocProp.relation) {
|
|
731
|
-
// Standard relations
|
|
732
|
-
case "OneToOne":
|
|
733
|
-
case "ManyToOne":
|
|
734
|
-
return targetName;
|
|
735
|
-
case "OneToMany":
|
|
736
|
-
case "ManyToMany":
|
|
737
|
-
return `${targetName}[]`;
|
|
738
|
-
// Polymorphic relations
|
|
739
|
-
case "MorphTo":
|
|
740
|
-
if (assocProp.targets && assocProp.targets.length > 0) {
|
|
741
|
-
return assocProp.targets.join(" | ");
|
|
742
|
-
}
|
|
743
|
-
return "unknown";
|
|
744
|
-
case "MorphOne":
|
|
745
|
-
return targetName;
|
|
746
|
-
case "MorphMany":
|
|
747
|
-
case "MorphToMany":
|
|
748
|
-
case "MorphedByMany":
|
|
749
|
-
return `${targetName}[]`;
|
|
750
|
-
default:
|
|
751
|
-
return "unknown";
|
|
752
|
-
}
|
|
701
|
+
function toCamelCase(str) {
|
|
702
|
+
const pascal = toPascalCase(str);
|
|
703
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
704
|
+
}
|
|
705
|
+
function pluralize(word) {
|
|
706
|
+
if (word.endsWith("y") && !["ay", "ey", "iy", "oy", "uy"].some((v) => word.endsWith(v))) {
|
|
707
|
+
return word.slice(0, -1) + "ies";
|
|
753
708
|
}
|
|
754
|
-
if (
|
|
755
|
-
|
|
756
|
-
if (typeof enumProp.enum === "string") {
|
|
757
|
-
return enumProp.enum;
|
|
758
|
-
}
|
|
759
|
-
if (Array.isArray(enumProp.enum)) {
|
|
760
|
-
return enumProp.enum.map((v) => `'${v}'`).join(" | ");
|
|
761
|
-
}
|
|
709
|
+
if (word.endsWith("s") || word.endsWith("x") || word.endsWith("z") || word.endsWith("ch") || word.endsWith("sh")) {
|
|
710
|
+
return word + "es";
|
|
762
711
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
712
|
+
return word + "s";
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// src/model/generator.ts
|
|
716
|
+
var DEFAULT_OPTIONS = {
|
|
717
|
+
baseModelNamespace: "App\\Models\\OmnifyBase",
|
|
718
|
+
modelNamespace: "App\\Models",
|
|
719
|
+
baseModelClassName: "BaseModel",
|
|
720
|
+
baseModelPath: "app/Models/OmnifyBase",
|
|
721
|
+
modelPath: "app/Models"
|
|
722
|
+
};
|
|
723
|
+
function resolveOptions(options) {
|
|
724
|
+
return {
|
|
725
|
+
baseModelNamespace: options?.baseModelNamespace ?? DEFAULT_OPTIONS.baseModelNamespace,
|
|
726
|
+
modelNamespace: options?.modelNamespace ?? DEFAULT_OPTIONS.modelNamespace,
|
|
727
|
+
baseModelClassName: options?.baseModelClassName ?? DEFAULT_OPTIONS.baseModelClassName,
|
|
728
|
+
baseModelPath: options?.baseModelPath ?? DEFAULT_OPTIONS.baseModelPath,
|
|
729
|
+
modelPath: options?.modelPath ?? DEFAULT_OPTIONS.modelPath
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
function getCastType(propDef) {
|
|
733
|
+
switch (propDef.type) {
|
|
734
|
+
case "Boolean":
|
|
735
|
+
return "boolean";
|
|
736
|
+
case "Int":
|
|
737
|
+
case "BigInt":
|
|
738
|
+
return "integer";
|
|
739
|
+
case "Float":
|
|
740
|
+
return "float";
|
|
741
|
+
case "Decimal":
|
|
742
|
+
return "decimal:" + (propDef.scale ?? 2);
|
|
743
|
+
case "Json":
|
|
744
|
+
return "array";
|
|
745
|
+
case "Date":
|
|
746
|
+
return "date";
|
|
747
|
+
case "Timestamp":
|
|
748
|
+
return "datetime";
|
|
749
|
+
case "Password":
|
|
750
|
+
return "hashed";
|
|
751
|
+
default:
|
|
752
|
+
return null;
|
|
768
753
|
}
|
|
769
|
-
return TYPE_MAP[property.type] ?? "unknown";
|
|
770
754
|
}
|
|
771
|
-
function
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
755
|
+
function isNullable(propDef) {
|
|
756
|
+
return "nullable" in propDef && propDef.nullable === true;
|
|
757
|
+
}
|
|
758
|
+
function getPhpDocType(propDef, schemas) {
|
|
759
|
+
const nullable = isNullable(propDef);
|
|
760
|
+
switch (propDef.type) {
|
|
761
|
+
case "String":
|
|
762
|
+
case "Text":
|
|
763
|
+
case "LongText":
|
|
764
|
+
case "Email":
|
|
765
|
+
case "Password":
|
|
766
|
+
return "string" + (nullable ? "|null" : "");
|
|
767
|
+
case "Int":
|
|
768
|
+
case "BigInt":
|
|
769
|
+
return "int" + (nullable ? "|null" : "");
|
|
770
|
+
case "Float":
|
|
771
|
+
case "Decimal":
|
|
772
|
+
return "float" + (nullable ? "|null" : "");
|
|
773
|
+
case "Boolean":
|
|
774
|
+
return "bool" + (nullable ? "|null" : "");
|
|
775
|
+
case "Date":
|
|
776
|
+
case "Time":
|
|
777
|
+
case "Timestamp":
|
|
778
|
+
return "\\Carbon\\Carbon" + (nullable ? "|null" : "");
|
|
779
|
+
case "Json":
|
|
780
|
+
return "array" + (nullable ? "|null" : "");
|
|
781
|
+
case "Enum":
|
|
782
|
+
case "EnumRef":
|
|
783
|
+
return "string" + (nullable ? "|null" : "");
|
|
784
|
+
case "Association": {
|
|
785
|
+
const assoc = propDef;
|
|
786
|
+
if (assoc.target) {
|
|
787
|
+
const className = toPascalCase(assoc.target);
|
|
788
|
+
switch (assoc.relation) {
|
|
789
|
+
case "OneToMany":
|
|
790
|
+
case "ManyToMany":
|
|
791
|
+
case "MorphMany":
|
|
792
|
+
case "MorphToMany":
|
|
793
|
+
case "MorphedByMany":
|
|
794
|
+
return `\\Illuminate\\Database\\Eloquent\\Collection<${className}>`;
|
|
795
|
+
default:
|
|
796
|
+
return className + "|null";
|
|
802
797
|
}
|
|
803
|
-
|
|
798
|
+
}
|
|
799
|
+
return "mixed";
|
|
804
800
|
}
|
|
801
|
+
default:
|
|
802
|
+
return "mixed";
|
|
805
803
|
}
|
|
806
|
-
const type = getPropertyType(property, allSchemas);
|
|
807
|
-
return [{
|
|
808
|
-
name: toPropertyName(propertyName),
|
|
809
|
-
type,
|
|
810
|
-
optional: baseProp.nullable ?? false,
|
|
811
|
-
readonly: isReadonly,
|
|
812
|
-
comment: baseProp.displayName
|
|
813
|
-
}];
|
|
814
804
|
}
|
|
815
|
-
function
|
|
816
|
-
const
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
type: PK_TYPE_MAP[pkType] ?? "number",
|
|
822
|
-
optional: false,
|
|
823
|
-
readonly: options.readonly ?? true,
|
|
824
|
-
comment: "Primary key"
|
|
825
|
-
});
|
|
826
|
-
}
|
|
827
|
-
if (schema.properties) {
|
|
828
|
-
for (const [propName, property] of Object.entries(schema.properties)) {
|
|
829
|
-
properties.push(...propertyToTSProperties(propName, property, allSchemas, options));
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
if (schema.options?.timestamps !== false) {
|
|
833
|
-
properties.push(
|
|
834
|
-
{
|
|
835
|
-
name: "createdAt",
|
|
836
|
-
type: "string",
|
|
837
|
-
optional: true,
|
|
838
|
-
readonly: options.readonly ?? true,
|
|
839
|
-
comment: "Creation timestamp"
|
|
840
|
-
},
|
|
841
|
-
{
|
|
842
|
-
name: "updatedAt",
|
|
843
|
-
type: "string",
|
|
844
|
-
optional: true,
|
|
845
|
-
readonly: options.readonly ?? true,
|
|
846
|
-
comment: "Last update timestamp"
|
|
847
|
-
}
|
|
848
|
-
);
|
|
849
|
-
}
|
|
850
|
-
if (schema.options?.softDelete) {
|
|
851
|
-
properties.push({
|
|
852
|
-
name: "deletedAt",
|
|
853
|
-
type: "string",
|
|
854
|
-
optional: true,
|
|
855
|
-
readonly: options.readonly ?? true,
|
|
856
|
-
comment: "Soft delete timestamp"
|
|
857
|
-
});
|
|
858
|
-
}
|
|
805
|
+
function generateBaseModel(schemas, options, stubContent) {
|
|
806
|
+
const modelMap = Object.values(schemas).filter((s) => s.kind !== "enum").map((s) => {
|
|
807
|
+
const className = toPascalCase(s.name);
|
|
808
|
+
return ` '${s.name}' => \\${options.modelNamespace}\\${className}::class,`;
|
|
809
|
+
}).join("\n");
|
|
810
|
+
const content = stubContent.replace(/\{\{BASE_MODEL_NAMESPACE\}\}/g, options.baseModelNamespace).replace(/\{\{BASE_MODEL_CLASS\}\}/g, options.baseModelClassName).replace(/\{\{MODEL_MAP\}\}/g, modelMap);
|
|
859
811
|
return {
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
812
|
+
path: `${options.baseModelPath}/${options.baseModelClassName}.php`,
|
|
813
|
+
content,
|
|
814
|
+
type: "base-model",
|
|
815
|
+
overwrite: true,
|
|
816
|
+
schemaName: "__base__"
|
|
863
817
|
};
|
|
864
818
|
}
|
|
865
|
-
function
|
|
866
|
-
const
|
|
867
|
-
const
|
|
868
|
-
const
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
const
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
const
|
|
878
|
-
const
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
819
|
+
function generateEntityBaseModel(schema, schemas, options, stubContent, authStubContent) {
|
|
820
|
+
const className = toPascalCase(schema.name);
|
|
821
|
+
const tableName = schema.options?.tableName ?? pluralize(toSnakeCase(schema.name));
|
|
822
|
+
const isAuth = schema.options?.authenticatable ?? false;
|
|
823
|
+
const primaryKey = "id";
|
|
824
|
+
const idType = schema.options?.idType ?? "BigInt";
|
|
825
|
+
const isUuid = idType === "Uuid";
|
|
826
|
+
const isStringKey = idType === "Uuid" || idType === "String";
|
|
827
|
+
const imports = [];
|
|
828
|
+
const traits = [];
|
|
829
|
+
const fillable = [];
|
|
830
|
+
const hidden = [];
|
|
831
|
+
const appends = [];
|
|
832
|
+
const casts = [];
|
|
833
|
+
const relations = [];
|
|
834
|
+
const docProperties = [];
|
|
835
|
+
if (schema.options?.softDelete) {
|
|
836
|
+
imports.push("use Illuminate\\Database\\Eloquent\\SoftDeletes;");
|
|
837
|
+
traits.push(" use SoftDeletes;");
|
|
838
|
+
}
|
|
839
|
+
const properties = schema.properties ?? {};
|
|
840
|
+
for (const [propName, propDef] of Object.entries(properties)) {
|
|
841
|
+
const snakeName = toSnakeCase(propName);
|
|
842
|
+
const phpType = getPhpDocType(propDef, schemas);
|
|
843
|
+
docProperties.push(` * @property ${phpType} $${snakeName}`);
|
|
844
|
+
if (propDef.type === "Association") {
|
|
845
|
+
const assoc = propDef;
|
|
846
|
+
if (assoc.target) {
|
|
847
|
+
imports.push(`use ${options.modelNamespace}\\${toPascalCase(assoc.target)};`);
|
|
848
|
+
}
|
|
849
|
+
relations.push(generateRelation(propName, assoc, options));
|
|
850
|
+
if (assoc.relation === "ManyToOne" || assoc.relation === "OneToOne") {
|
|
851
|
+
if (!assoc.mappedBy) {
|
|
852
|
+
const fkName = toSnakeCase(propName) + "_id";
|
|
853
|
+
fillable.push(` '${fkName}',`);
|
|
854
|
+
docProperties.push(` * @property int|null $${fkName}`);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
} else if (propDef.type === "Password") {
|
|
858
|
+
fillable.push(` '${snakeName}',`);
|
|
859
|
+
hidden.push(` '${snakeName}',`);
|
|
860
|
+
const cast = getCastType(propDef);
|
|
861
|
+
if (cast) {
|
|
862
|
+
casts.push(` '${snakeName}' => '${cast}',`);
|
|
863
|
+
}
|
|
864
|
+
} else if (propDef.type === "File") {
|
|
865
|
+
const relMethod = generateFileRelation(propName, propDef);
|
|
866
|
+
relations.push(relMethod);
|
|
867
|
+
} else {
|
|
868
|
+
fillable.push(` '${snakeName}',`);
|
|
869
|
+
const cast = getCastType(propDef);
|
|
870
|
+
if (cast) {
|
|
871
|
+
casts.push(` '${snakeName}' => '${cast}',`);
|
|
872
|
+
}
|
|
888
873
|
}
|
|
889
|
-
interfaces.push(schemaToInterface(schema, schemas, options));
|
|
890
874
|
}
|
|
891
|
-
|
|
892
|
-
}
|
|
875
|
+
const docComment = `/**
|
|
876
|
+
* ${className}BaseModel
|
|
877
|
+
*
|
|
878
|
+
${docProperties.join("\n")}
|
|
879
|
+
*/`;
|
|
880
|
+
const stub = isAuth ? authStubContent : stubContent;
|
|
881
|
+
const keyType = isStringKey ? ` /**
|
|
882
|
+
* The "type" of the primary key ID.
|
|
883
|
+
*/
|
|
884
|
+
protected $keyType = 'string';
|
|
893
885
|
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
886
|
+
` : "";
|
|
887
|
+
const incrementing = isUuid ? ` /**
|
|
888
|
+
* Indicates if the IDs are auto-incrementing.
|
|
889
|
+
*/
|
|
890
|
+
public $incrementing = false;
|
|
891
|
+
|
|
892
|
+
` : "";
|
|
893
|
+
if (isUuid) {
|
|
894
|
+
imports.push("use Illuminate\\Database\\Eloquent\\Concerns\\HasUuids;");
|
|
895
|
+
traits.push(" use HasUuids;");
|
|
904
896
|
}
|
|
905
|
-
const
|
|
906
|
-
name: toEnumMemberName(value),
|
|
907
|
-
value
|
|
908
|
-
}));
|
|
897
|
+
const content = stub.replace(/\{\{BASE_MODEL_NAMESPACE\}\}/g, options.baseModelNamespace).replace(/\{\{BASE_MODEL_CLASS\}\}/g, options.baseModelClassName).replace(/\{\{CLASS_NAME\}\}/g, className).replace(/\{\{TABLE_NAME\}\}/g, tableName).replace(/\{\{PRIMARY_KEY\}\}/g, primaryKey).replace(/\{\{KEY_TYPE\}\}/g, keyType).replace(/\{\{INCREMENTING\}\}/g, incrementing).replace(/\{\{TIMESTAMPS\}\}/g, schema.options?.timestamps !== false ? "true" : "false").replace(/\{\{IMPORTS\}\}/g, [...new Set(imports)].sort().join("\n")).replace(/\{\{TRAITS\}\}/g, traits.join("\n")).replace(/\{\{DOC_COMMENT\}\}/g, docComment).replace(/\{\{FILLABLE\}\}/g, fillable.join("\n")).replace(/\{\{HIDDEN\}\}/g, hidden.join("\n")).replace(/\{\{APPENDS\}\}/g, appends.join("\n")).replace(/\{\{CASTS\}\}/g, casts.join("\n")).replace(/\{\{RELATIONS\}\}/g, relations.join("\n\n"));
|
|
909
898
|
return {
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
899
|
+
path: `${options.baseModelPath}/${className}BaseModel.php`,
|
|
900
|
+
content,
|
|
901
|
+
type: "entity-base",
|
|
902
|
+
overwrite: true,
|
|
903
|
+
schemaName: schema.name
|
|
913
904
|
};
|
|
914
905
|
}
|
|
915
|
-
function
|
|
916
|
-
const
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
906
|
+
function generateRelation(propName, assoc, options) {
|
|
907
|
+
const methodName = toCamelCase(propName);
|
|
908
|
+
const targetClass = assoc.target ? toPascalCase(assoc.target) : "";
|
|
909
|
+
const fkName = toSnakeCase(propName) + "_id";
|
|
910
|
+
switch (assoc.relation) {
|
|
911
|
+
case "ManyToOne":
|
|
912
|
+
return ` /**
|
|
913
|
+
* Get the ${propName} that owns this model.
|
|
914
|
+
*/
|
|
915
|
+
public function ${methodName}(): BelongsTo
|
|
916
|
+
{
|
|
917
|
+
return $this->belongsTo(${targetClass}::class, '${fkName}');
|
|
918
|
+
}`;
|
|
919
|
+
case "OneToOne":
|
|
920
|
+
if (assoc.mappedBy) {
|
|
921
|
+
return ` /**
|
|
922
|
+
* Get the ${propName} for this model.
|
|
923
|
+
*/
|
|
924
|
+
public function ${methodName}(): HasOne
|
|
925
|
+
{
|
|
926
|
+
return $this->hasOne(${targetClass}::class, '${toSnakeCase(assoc.mappedBy)}_id');
|
|
927
|
+
}`;
|
|
922
928
|
}
|
|
929
|
+
return ` /**
|
|
930
|
+
* Get the ${propName} that owns this model.
|
|
931
|
+
*/
|
|
932
|
+
public function ${methodName}(): BelongsTo
|
|
933
|
+
{
|
|
934
|
+
return $this->belongsTo(${targetClass}::class, '${fkName}');
|
|
935
|
+
}`;
|
|
936
|
+
case "OneToMany":
|
|
937
|
+
return ` /**
|
|
938
|
+
* Get the ${propName} for this model.
|
|
939
|
+
*/
|
|
940
|
+
public function ${methodName}(): HasMany
|
|
941
|
+
{
|
|
942
|
+
return $this->hasMany(${targetClass}::class, '${toSnakeCase(assoc.inversedBy ?? propName)}_id');
|
|
943
|
+
}`;
|
|
944
|
+
case "ManyToMany": {
|
|
945
|
+
const pivotTable = assoc.joinTable ?? `${toSnakeCase(propName)}_pivot`;
|
|
946
|
+
return ` /**
|
|
947
|
+
* The ${propName} that belong to this model.
|
|
948
|
+
*/
|
|
949
|
+
public function ${methodName}(): BelongsToMany
|
|
950
|
+
{
|
|
951
|
+
return $this->belongsToMany(${targetClass}::class, '${pivotTable}')
|
|
952
|
+
->withTimestamps();
|
|
953
|
+
}`;
|
|
923
954
|
}
|
|
955
|
+
case "MorphTo":
|
|
956
|
+
return ` /**
|
|
957
|
+
* Get the parent ${propName} model.
|
|
958
|
+
*/
|
|
959
|
+
public function ${methodName}(): MorphTo
|
|
960
|
+
{
|
|
961
|
+
return $this->morphTo('${methodName}');
|
|
962
|
+
}`;
|
|
963
|
+
case "MorphOne":
|
|
964
|
+
return ` /**
|
|
965
|
+
* Get the ${propName} for this model.
|
|
966
|
+
*/
|
|
967
|
+
public function ${methodName}(): MorphOne
|
|
968
|
+
{
|
|
969
|
+
return $this->morphOne(${targetClass}::class, '${assoc.morphName ?? propName}');
|
|
970
|
+
}`;
|
|
971
|
+
case "MorphMany":
|
|
972
|
+
return ` /**
|
|
973
|
+
* Get the ${propName} for this model.
|
|
974
|
+
*/
|
|
975
|
+
public function ${methodName}(): MorphMany
|
|
976
|
+
{
|
|
977
|
+
return $this->morphMany(${targetClass}::class, '${assoc.morphName ?? propName}');
|
|
978
|
+
}`;
|
|
979
|
+
default:
|
|
980
|
+
return ` // TODO: Implement ${assoc.relation} relation for ${propName}`;
|
|
924
981
|
}
|
|
925
|
-
return enums;
|
|
926
982
|
}
|
|
927
|
-
function
|
|
928
|
-
const
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
`
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
${
|
|
935
|
-
|
|
983
|
+
function generateFileRelation(propName, propDef) {
|
|
984
|
+
const methodName = toCamelCase(propName);
|
|
985
|
+
const relationType = propDef.multiple ? "MorphMany" : "MorphOne";
|
|
986
|
+
const relationMethod = propDef.multiple ? "morphMany" : "morphOne";
|
|
987
|
+
return ` /**
|
|
988
|
+
* Get the ${propName} file(s) for this model.
|
|
989
|
+
*/
|
|
990
|
+
public function ${methodName}(): ${relationType}
|
|
991
|
+
{
|
|
992
|
+
return $this->${relationMethod}(FileUpload::class, 'uploadable')
|
|
993
|
+
->where('attribute_name', '${propName}');
|
|
994
|
+
}`;
|
|
936
995
|
}
|
|
937
|
-
function
|
|
938
|
-
const
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
996
|
+
function generateEntityModel(schema, options, stubContent) {
|
|
997
|
+
const className = toPascalCase(schema.name);
|
|
998
|
+
const content = stubContent.replace(/\{\{BASE_MODEL_NAMESPACE\}\}/g, options.baseModelNamespace).replace(/\{\{MODEL_NAMESPACE\}\}/g, options.modelNamespace).replace(/\{\{CLASS_NAME\}\}/g, className);
|
|
999
|
+
return {
|
|
1000
|
+
path: `${options.modelPath}/${className}.php`,
|
|
1001
|
+
content,
|
|
1002
|
+
type: "entity",
|
|
1003
|
+
overwrite: false,
|
|
1004
|
+
// Never overwrite user models
|
|
1005
|
+
schemaName: schema.name
|
|
1006
|
+
};
|
|
943
1007
|
}
|
|
944
|
-
function
|
|
945
|
-
const
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1008
|
+
function getStubContent(stubName) {
|
|
1009
|
+
const stubs = {
|
|
1010
|
+
"base-model": `<?php
|
|
1011
|
+
|
|
1012
|
+
namespace {{BASE_MODEL_NAMESPACE}};
|
|
1013
|
+
|
|
1014
|
+
/**
|
|
1015
|
+
* Base model class for all Omnify-generated models.
|
|
1016
|
+
* Contains model mapping for polymorphic relations.
|
|
1017
|
+
*
|
|
1018
|
+
* DO NOT EDIT - This file is auto-generated by Omnify.
|
|
1019
|
+
* Any changes will be overwritten on next generation.
|
|
1020
|
+
*
|
|
1021
|
+
* @generated by @famgia/omnify-laravel
|
|
1022
|
+
*/
|
|
1023
|
+
|
|
1024
|
+
use Illuminate\\Database\\Eloquent\\Model;
|
|
1025
|
+
use Illuminate\\Database\\Eloquent\\Relations\\Relation;
|
|
1026
|
+
|
|
1027
|
+
abstract class {{BASE_MODEL_CLASS}} extends Model
|
|
1028
|
+
{
|
|
1029
|
+
/**
|
|
1030
|
+
* Model class map for polymorphic relations.
|
|
1031
|
+
*/
|
|
1032
|
+
protected static array $modelMap = [
|
|
1033
|
+
{{MODEL_MAP}}
|
|
1034
|
+
];
|
|
1035
|
+
|
|
1036
|
+
/**
|
|
1037
|
+
* Boot the model and register morph map.
|
|
1038
|
+
*/
|
|
1039
|
+
protected static function boot(): void
|
|
1040
|
+
{
|
|
1041
|
+
parent::boot();
|
|
1042
|
+
|
|
1043
|
+
// Register morph map for polymorphic relations
|
|
1044
|
+
Relation::enforceMorphMap(static::$modelMap);
|
|
949
1045
|
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
type: enumProp.enum.map((v) => `'${v}'`).join(" | "),
|
|
958
|
-
comment: enumProp.displayName ?? `${schema.name} ${propName} enum`
|
|
959
|
-
});
|
|
960
|
-
}
|
|
961
|
-
}
|
|
962
|
-
if (property.type === "Select") {
|
|
963
|
-
const selectProp = property;
|
|
964
|
-
if (selectProp.options && selectProp.options.length > 0) {
|
|
965
|
-
const typeName = `${schema.name}${propName.charAt(0).toUpperCase() + propName.slice(1)}`;
|
|
966
|
-
typeAliases.push({
|
|
967
|
-
name: typeName,
|
|
968
|
-
type: selectProp.options.map((v) => `'${v}'`).join(" | "),
|
|
969
|
-
comment: selectProp.displayName ?? `${schema.name} ${propName} options`
|
|
970
|
-
});
|
|
971
|
-
}
|
|
972
|
-
}
|
|
1046
|
+
|
|
1047
|
+
/**
|
|
1048
|
+
* Get the model class for a given morph type.
|
|
1049
|
+
*/
|
|
1050
|
+
public static function getModelClass(string $morphType): ?string
|
|
1051
|
+
{
|
|
1052
|
+
return static::$modelMap[$morphType] ?? null;
|
|
973
1053
|
}
|
|
974
|
-
}
|
|
975
|
-
return typeAliases;
|
|
976
1054
|
}
|
|
1055
|
+
`,
|
|
1056
|
+
"entity-base": `<?php
|
|
977
1057
|
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
function generateHeader() {
|
|
986
|
-
return `/**
|
|
987
|
-
* Auto-generated TypeScript types from Omnify schemas.
|
|
988
|
-
* DO NOT EDIT - This file is automatically generated.
|
|
1058
|
+
namespace {{BASE_MODEL_NAMESPACE}};
|
|
1059
|
+
|
|
1060
|
+
/**
|
|
1061
|
+
* DO NOT EDIT - This file is auto-generated by Omnify.
|
|
1062
|
+
* Any changes will be overwritten on next generation.
|
|
1063
|
+
*
|
|
1064
|
+
* @generated by @famgia/omnify-laravel
|
|
989
1065
|
*/
|
|
990
1066
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1067
|
+
use Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;
|
|
1068
|
+
use Illuminate\\Database\\Eloquent\\Relations\\HasMany;
|
|
1069
|
+
use Illuminate\\Database\\Eloquent\\Relations\\HasOne;
|
|
1070
|
+
use Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany;
|
|
1071
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphTo;
|
|
1072
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphOne;
|
|
1073
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphMany;
|
|
1074
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphToMany;
|
|
1075
|
+
use Illuminate\\Database\\Eloquent\\Collection as EloquentCollection;
|
|
1076
|
+
{{IMPORTS}}
|
|
1077
|
+
|
|
1078
|
+
{{DOC_COMMENT}}
|
|
1079
|
+
class {{CLASS_NAME}}BaseModel extends {{BASE_MODEL_CLASS}}
|
|
1080
|
+
{
|
|
1081
|
+
{{TRAITS}}
|
|
1082
|
+
/**
|
|
1083
|
+
* The table associated with the model.
|
|
1084
|
+
*/
|
|
1085
|
+
protected $table = '{{TABLE_NAME}}';
|
|
1086
|
+
|
|
1087
|
+
/**
|
|
1088
|
+
* The primary key for the model.
|
|
1089
|
+
*/
|
|
1090
|
+
protected $primaryKey = '{{PRIMARY_KEY}}';
|
|
1091
|
+
|
|
1092
|
+
{{KEY_TYPE}}
|
|
1093
|
+
{{INCREMENTING}}
|
|
1094
|
+
/**
|
|
1095
|
+
* Indicates if the model should be timestamped.
|
|
1096
|
+
*/
|
|
1097
|
+
public $timestamps = {{TIMESTAMPS}};
|
|
1098
|
+
|
|
1099
|
+
/**
|
|
1100
|
+
* The attributes that are mass assignable.
|
|
1101
|
+
*/
|
|
1102
|
+
protected $fillable = [
|
|
1103
|
+
{{FILLABLE}}
|
|
1104
|
+
];
|
|
1105
|
+
|
|
1106
|
+
/**
|
|
1107
|
+
* The attributes that should be hidden for serialization.
|
|
1108
|
+
*/
|
|
1109
|
+
protected $hidden = [
|
|
1110
|
+
{{HIDDEN}}
|
|
1111
|
+
];
|
|
1112
|
+
|
|
1113
|
+
/**
|
|
1114
|
+
* The accessors to append to the model's array form.
|
|
1115
|
+
*/
|
|
1116
|
+
protected $appends = [
|
|
1117
|
+
{{APPENDS}}
|
|
1118
|
+
];
|
|
1119
|
+
|
|
1120
|
+
/**
|
|
1121
|
+
* Get the attributes that should be cast.
|
|
1122
|
+
*/
|
|
1123
|
+
protected function casts(): array
|
|
1124
|
+
{
|
|
1125
|
+
return [
|
|
1126
|
+
{{CASTS}}
|
|
1127
|
+
];
|
|
1022
1128
|
}
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
fileName: opts.fileName ?? "types.ts",
|
|
1026
|
-
content: parts.join("").trim() + "\n",
|
|
1027
|
-
types
|
|
1028
|
-
};
|
|
1029
|
-
}
|
|
1030
|
-
function generateTypeScriptFiles(schemas, options = {}) {
|
|
1031
|
-
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
1032
|
-
const files = [];
|
|
1033
|
-
const enums = generateEnums(schemas);
|
|
1034
|
-
if (enums.length > 0) {
|
|
1035
|
-
const content = generateHeader() + enums.map(formatEnum).join("\n\n") + "\n";
|
|
1036
|
-
files.push({
|
|
1037
|
-
fileName: "enums.ts",
|
|
1038
|
-
content,
|
|
1039
|
-
types: enums.map((e) => e.name)
|
|
1040
|
-
});
|
|
1041
|
-
}
|
|
1042
|
-
const inlineEnums = extractInlineEnums(schemas);
|
|
1043
|
-
if (inlineEnums.length > 0) {
|
|
1044
|
-
const content = generateHeader() + inlineEnums.map(formatTypeAlias).join("\n\n") + "\n";
|
|
1045
|
-
files.push({
|
|
1046
|
-
fileName: "type-aliases.ts",
|
|
1047
|
-
content,
|
|
1048
|
-
types: inlineEnums.map((a) => a.name)
|
|
1049
|
-
});
|
|
1050
|
-
}
|
|
1051
|
-
const interfaces = generateInterfaces(schemas, opts);
|
|
1052
|
-
for (const iface of interfaces) {
|
|
1053
|
-
const imports = collectImports(iface, enums, inlineEnums, interfaces);
|
|
1054
|
-
const importStatement = formatImports(imports);
|
|
1055
|
-
const content = generateHeader() + (importStatement ? importStatement + "\n\n" : "") + formatInterface(iface) + "\n";
|
|
1056
|
-
files.push({
|
|
1057
|
-
fileName: `${toKebabCase(iface.name)}.ts`,
|
|
1058
|
-
content,
|
|
1059
|
-
types: [iface.name]
|
|
1060
|
-
});
|
|
1061
|
-
}
|
|
1062
|
-
const indexContent = generateIndexFile(files);
|
|
1063
|
-
files.push({
|
|
1064
|
-
fileName: "index.ts",
|
|
1065
|
-
content: indexContent,
|
|
1066
|
-
types: []
|
|
1067
|
-
});
|
|
1068
|
-
return files;
|
|
1069
|
-
}
|
|
1070
|
-
function toKebabCase(name) {
|
|
1071
|
-
return name.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
|
|
1129
|
+
|
|
1130
|
+
{{RELATIONS}}
|
|
1072
1131
|
}
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1132
|
+
`,
|
|
1133
|
+
"entity-base-auth": `<?php
|
|
1134
|
+
|
|
1135
|
+
namespace {{BASE_MODEL_NAMESPACE}};
|
|
1136
|
+
|
|
1137
|
+
/**
|
|
1138
|
+
* DO NOT EDIT - This file is auto-generated by Omnify.
|
|
1139
|
+
* Any changes will be overwritten on next generation.
|
|
1140
|
+
*
|
|
1141
|
+
* @generated by @famgia/omnify-laravel
|
|
1142
|
+
*/
|
|
1143
|
+
|
|
1144
|
+
use Illuminate\\Foundation\\Auth\\User as Authenticatable;
|
|
1145
|
+
use Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;
|
|
1146
|
+
use Illuminate\\Database\\Eloquent\\Relations\\HasMany;
|
|
1147
|
+
use Illuminate\\Database\\Eloquent\\Relations\\HasOne;
|
|
1148
|
+
use Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany;
|
|
1149
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphTo;
|
|
1150
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphOne;
|
|
1151
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphMany;
|
|
1152
|
+
use Illuminate\\Database\\Eloquent\\Relations\\MorphToMany;
|
|
1153
|
+
use Illuminate\\Database\\Eloquent\\Collection as EloquentCollection;
|
|
1154
|
+
use Illuminate\\Notifications\\Notifiable;
|
|
1155
|
+
{{IMPORTS}}
|
|
1156
|
+
|
|
1157
|
+
{{DOC_COMMENT}}
|
|
1158
|
+
class {{CLASS_NAME}}BaseModel extends Authenticatable
|
|
1159
|
+
{
|
|
1160
|
+
use Notifiable;
|
|
1161
|
+
{{TRAITS}}
|
|
1162
|
+
/**
|
|
1163
|
+
* The table associated with the model.
|
|
1164
|
+
*/
|
|
1165
|
+
protected $table = '{{TABLE_NAME}}';
|
|
1166
|
+
|
|
1167
|
+
/**
|
|
1168
|
+
* The primary key for the model.
|
|
1169
|
+
*/
|
|
1170
|
+
protected $primaryKey = '{{PRIMARY_KEY}}';
|
|
1171
|
+
|
|
1172
|
+
{{KEY_TYPE}}
|
|
1173
|
+
{{INCREMENTING}}
|
|
1174
|
+
/**
|
|
1175
|
+
* Indicates if the model should be timestamped.
|
|
1176
|
+
*/
|
|
1177
|
+
public $timestamps = {{TIMESTAMPS}};
|
|
1178
|
+
|
|
1179
|
+
/**
|
|
1180
|
+
* The attributes that are mass assignable.
|
|
1181
|
+
*/
|
|
1182
|
+
protected $fillable = [
|
|
1183
|
+
{{FILLABLE}}
|
|
1184
|
+
];
|
|
1185
|
+
|
|
1186
|
+
/**
|
|
1187
|
+
* The attributes that should be hidden for serialization.
|
|
1188
|
+
*/
|
|
1189
|
+
protected $hidden = [
|
|
1190
|
+
{{HIDDEN}}
|
|
1191
|
+
];
|
|
1192
|
+
|
|
1193
|
+
/**
|
|
1194
|
+
* The accessors to append to the model's array form.
|
|
1195
|
+
*/
|
|
1196
|
+
protected $appends = [
|
|
1197
|
+
{{APPENDS}}
|
|
1198
|
+
];
|
|
1199
|
+
|
|
1200
|
+
/**
|
|
1201
|
+
* Get the attributes that should be cast.
|
|
1202
|
+
*/
|
|
1203
|
+
protected function casts(): array
|
|
1204
|
+
{
|
|
1205
|
+
return [
|
|
1206
|
+
{{CASTS}}
|
|
1207
|
+
];
|
|
1090
1208
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1209
|
+
|
|
1210
|
+
{{RELATIONS}}
|
|
1211
|
+
}
|
|
1212
|
+
`,
|
|
1213
|
+
"entity": `<?php
|
|
1214
|
+
|
|
1215
|
+
namespace {{MODEL_NAMESPACE}};
|
|
1216
|
+
|
|
1217
|
+
use {{BASE_MODEL_NAMESPACE}}\\{{CLASS_NAME}}BaseModel;
|
|
1218
|
+
use Illuminate\\Database\\Eloquent\\Factories\\HasFactory;
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* {{CLASS_NAME}} Model
|
|
1222
|
+
*
|
|
1223
|
+
* This file is generated once and can be customized.
|
|
1224
|
+
* Add your custom methods and logic here.
|
|
1225
|
+
*/
|
|
1226
|
+
class {{CLASS_NAME}} extends {{CLASS_NAME}}BaseModel
|
|
1227
|
+
{
|
|
1228
|
+
use HasFactory;
|
|
1229
|
+
|
|
1230
|
+
/**
|
|
1231
|
+
* Create a new model instance.
|
|
1232
|
+
*/
|
|
1233
|
+
public function __construct(array $attributes = [])
|
|
1234
|
+
{
|
|
1235
|
+
parent::__construct($attributes);
|
|
1098
1236
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1237
|
+
|
|
1238
|
+
// Add your custom methods here
|
|
1101
1239
|
}
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
for (const [path, names] of imports) {
|
|
1106
|
-
lines.push(`import type { ${names.join(", ")} } from '${path}';`);
|
|
1107
|
-
}
|
|
1108
|
-
return lines.join("\n");
|
|
1240
|
+
`
|
|
1241
|
+
};
|
|
1242
|
+
return stubs[stubName] ?? "";
|
|
1109
1243
|
}
|
|
1110
|
-
function
|
|
1111
|
-
const
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1244
|
+
function generateModels(schemas, options) {
|
|
1245
|
+
const resolved = resolveOptions(options);
|
|
1246
|
+
const models = [];
|
|
1247
|
+
models.push(generateBaseModel(schemas, resolved, getStubContent("base-model")));
|
|
1248
|
+
for (const schema of Object.values(schemas)) {
|
|
1249
|
+
if (schema.kind === "enum") {
|
|
1250
|
+
continue;
|
|
1251
|
+
}
|
|
1252
|
+
models.push(generateEntityBaseModel(
|
|
1253
|
+
schema,
|
|
1254
|
+
schemas,
|
|
1255
|
+
resolved,
|
|
1256
|
+
getStubContent("entity-base"),
|
|
1257
|
+
getStubContent("entity-base-auth")
|
|
1258
|
+
));
|
|
1259
|
+
models.push(generateEntityModel(schema, resolved, getStubContent("entity")));
|
|
1260
|
+
}
|
|
1261
|
+
return models;
|
|
1118
1262
|
}
|
|
1119
|
-
function
|
|
1120
|
-
|
|
1121
|
-
if (opts.singleFile) {
|
|
1122
|
-
return [generateTypeScriptFile(schemas, opts)];
|
|
1123
|
-
}
|
|
1124
|
-
return generateTypeScriptFiles(schemas, opts);
|
|
1263
|
+
function getModelPath(model) {
|
|
1264
|
+
return model.path;
|
|
1125
1265
|
}
|
|
1126
1266
|
|
|
1127
1267
|
// src/plugin.ts
|
|
1128
1268
|
var LARAVEL_CONFIG_SCHEMA = {
|
|
1129
1269
|
fields: [
|
|
1130
|
-
// Paths group
|
|
1131
1270
|
{
|
|
1132
1271
|
key: "migrationsPath",
|
|
1133
1272
|
type: "path",
|
|
1134
1273
|
label: "Migrations Path",
|
|
1135
1274
|
description: "Directory for Laravel migration files",
|
|
1136
1275
|
default: "database/migrations",
|
|
1137
|
-
group: "
|
|
1276
|
+
group: "output"
|
|
1138
1277
|
},
|
|
1139
1278
|
{
|
|
1140
|
-
key: "
|
|
1279
|
+
key: "modelsPath",
|
|
1141
1280
|
type: "path",
|
|
1142
|
-
label: "
|
|
1143
|
-
description: "Directory for
|
|
1144
|
-
default: "
|
|
1145
|
-
group: "
|
|
1146
|
-
},
|
|
1147
|
-
// Generators group
|
|
1148
|
-
{
|
|
1149
|
-
key: "generateMigrations",
|
|
1150
|
-
type: "boolean",
|
|
1151
|
-
label: "Generate Migrations",
|
|
1152
|
-
description: "Generate Laravel migration files",
|
|
1153
|
-
default: true,
|
|
1154
|
-
group: "generators"
|
|
1281
|
+
label: "Models Path",
|
|
1282
|
+
description: "Directory for user-editable model files",
|
|
1283
|
+
default: "app/Models",
|
|
1284
|
+
group: "output"
|
|
1155
1285
|
},
|
|
1156
1286
|
{
|
|
1157
|
-
key: "
|
|
1158
|
-
type: "
|
|
1159
|
-
label: "
|
|
1160
|
-
description: "
|
|
1161
|
-
default:
|
|
1162
|
-
group: "
|
|
1287
|
+
key: "baseModelsPath",
|
|
1288
|
+
type: "path",
|
|
1289
|
+
label: "Base Models Path",
|
|
1290
|
+
description: "Directory for auto-generated base model files",
|
|
1291
|
+
default: "app/Models/OmnifyBase",
|
|
1292
|
+
group: "output"
|
|
1163
1293
|
},
|
|
1164
|
-
// Options group
|
|
1165
1294
|
{
|
|
1166
|
-
key: "
|
|
1295
|
+
key: "generateModels",
|
|
1167
1296
|
type: "boolean",
|
|
1168
|
-
label: "
|
|
1169
|
-
description: "Generate
|
|
1297
|
+
label: "Generate Models",
|
|
1298
|
+
description: "Generate Eloquent model classes",
|
|
1170
1299
|
default: true,
|
|
1171
1300
|
group: "options"
|
|
1172
1301
|
},
|
|
@@ -1180,69 +1309,69 @@ var LARAVEL_CONFIG_SCHEMA = {
|
|
|
1180
1309
|
}
|
|
1181
1310
|
]
|
|
1182
1311
|
};
|
|
1183
|
-
function
|
|
1312
|
+
function resolveOptions2(options) {
|
|
1184
1313
|
return {
|
|
1185
1314
|
migrationsPath: options?.migrationsPath ?? "database/migrations",
|
|
1186
|
-
|
|
1187
|
-
|
|
1315
|
+
modelsPath: options?.modelsPath ?? "app/Models",
|
|
1316
|
+
baseModelsPath: options?.baseModelsPath ?? "app/Models/OmnifyBase",
|
|
1317
|
+
modelNamespace: options?.modelNamespace ?? "App\\Models",
|
|
1318
|
+
baseModelNamespace: options?.baseModelNamespace ?? "App\\Models\\OmnifyBase",
|
|
1319
|
+
generateModels: options?.generateModels ?? true,
|
|
1188
1320
|
connection: options?.connection,
|
|
1189
|
-
timestamp: options?.timestamp
|
|
1190
|
-
generateTypes: options?.generateTypes ?? true,
|
|
1191
|
-
generateMigrations: options?.generateMigrations ?? true
|
|
1321
|
+
timestamp: options?.timestamp
|
|
1192
1322
|
};
|
|
1193
1323
|
}
|
|
1194
1324
|
function laravelPlugin(options) {
|
|
1195
|
-
const resolved =
|
|
1325
|
+
const resolved = resolveOptions2(options);
|
|
1326
|
+
const migrationGenerator = {
|
|
1327
|
+
name: "laravel-migrations",
|
|
1328
|
+
description: "Generate Laravel migration files",
|
|
1329
|
+
generate: async (ctx) => {
|
|
1330
|
+
const migrationOptions = {
|
|
1331
|
+
connection: resolved.connection,
|
|
1332
|
+
timestamp: resolved.timestamp
|
|
1333
|
+
};
|
|
1334
|
+
const migrations = generateMigrations(ctx.schemas, migrationOptions);
|
|
1335
|
+
return migrations.map((migration) => ({
|
|
1336
|
+
path: getMigrationPath(migration, resolved.migrationsPath),
|
|
1337
|
+
content: migration.content,
|
|
1338
|
+
type: "migration",
|
|
1339
|
+
metadata: {
|
|
1340
|
+
tableName: migration.tables[0],
|
|
1341
|
+
migrationType: migration.type
|
|
1342
|
+
}
|
|
1343
|
+
}));
|
|
1344
|
+
}
|
|
1345
|
+
};
|
|
1346
|
+
const modelGenerator = {
|
|
1347
|
+
name: "laravel-models",
|
|
1348
|
+
description: "Generate Eloquent model classes",
|
|
1349
|
+
generate: async (ctx) => {
|
|
1350
|
+
const modelOptions = {
|
|
1351
|
+
modelNamespace: resolved.modelNamespace,
|
|
1352
|
+
baseModelNamespace: resolved.baseModelNamespace,
|
|
1353
|
+
modelPath: resolved.modelsPath,
|
|
1354
|
+
baseModelPath: resolved.baseModelsPath
|
|
1355
|
+
};
|
|
1356
|
+
const models = generateModels(ctx.schemas, modelOptions);
|
|
1357
|
+
return models.map((model) => ({
|
|
1358
|
+
path: getModelPath(model),
|
|
1359
|
+
content: model.content,
|
|
1360
|
+
type: "model",
|
|
1361
|
+
// Skip writing user models if they already exist
|
|
1362
|
+
skipIfExists: !model.overwrite,
|
|
1363
|
+
metadata: {
|
|
1364
|
+
modelType: model.type,
|
|
1365
|
+
schemaName: model.schemaName
|
|
1366
|
+
}
|
|
1367
|
+
}));
|
|
1368
|
+
}
|
|
1369
|
+
};
|
|
1196
1370
|
return {
|
|
1197
1371
|
name: "@famgia/omnify-laravel",
|
|
1198
|
-
version: "0.0.
|
|
1372
|
+
version: "0.0.14",
|
|
1199
1373
|
configSchema: LARAVEL_CONFIG_SCHEMA,
|
|
1200
|
-
generators: [
|
|
1201
|
-
// Laravel Migrations Generator
|
|
1202
|
-
...resolved.generateMigrations ? [
|
|
1203
|
-
{
|
|
1204
|
-
name: "laravel-migrations",
|
|
1205
|
-
description: "Generate Laravel migration files",
|
|
1206
|
-
generate: async (ctx) => {
|
|
1207
|
-
const migrationOptions = {
|
|
1208
|
-
connection: resolved.connection,
|
|
1209
|
-
timestamp: resolved.timestamp
|
|
1210
|
-
};
|
|
1211
|
-
const migrations = generateMigrations(ctx.schemas, migrationOptions);
|
|
1212
|
-
return migrations.map((migration) => ({
|
|
1213
|
-
path: getMigrationPath(migration, resolved.migrationsPath),
|
|
1214
|
-
content: migration.content,
|
|
1215
|
-
type: "migration",
|
|
1216
|
-
metadata: {
|
|
1217
|
-
tableName: migration.tables[0],
|
|
1218
|
-
migrationType: migration.type
|
|
1219
|
-
}
|
|
1220
|
-
}));
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
] : [],
|
|
1224
|
-
// TypeScript Types Generator
|
|
1225
|
-
...resolved.generateTypes ? [
|
|
1226
|
-
{
|
|
1227
|
-
name: "typescript-types",
|
|
1228
|
-
description: "Generate TypeScript type definitions",
|
|
1229
|
-
generate: async (ctx) => {
|
|
1230
|
-
const tsOptions = {
|
|
1231
|
-
singleFile: resolved.singleFile
|
|
1232
|
-
};
|
|
1233
|
-
const files = generateTypeScript(ctx.schemas, tsOptions);
|
|
1234
|
-
return files.map((file) => ({
|
|
1235
|
-
path: `${resolved.typesPath}/${file.fileName}`,
|
|
1236
|
-
content: file.content,
|
|
1237
|
-
type: "type",
|
|
1238
|
-
metadata: {
|
|
1239
|
-
types: file.types
|
|
1240
|
-
}
|
|
1241
|
-
}));
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
] : []
|
|
1245
|
-
]
|
|
1374
|
+
generators: resolved.generateModels ? [migrationGenerator, modelGenerator] : [migrationGenerator]
|
|
1246
1375
|
};
|
|
1247
1376
|
}
|
|
1248
1377
|
// Annotate the CommonJS export names for ESM import in node:
|