@famgia/omnify-laravel 0.0.12 → 0.0.13

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/plugin.cjs CHANGED
@@ -684,491 +684,16 @@ function getMigrationPath(migration, outputDir = "database/migrations") {
684
684
  return `${outputDir}/${migration.fileName}`;
685
685
  }
686
686
 
687
- // src/typescript/interface-generator.ts
688
- var TYPE_MAP = {
689
- String: "string",
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;
715
- }
716
- function toInterfaceName(schemaName) {
717
- return schemaName;
718
- }
719
- function getPropertyType(property, _allSchemas) {
720
- if (property.type === "File") {
721
- const fileProp = property;
722
- if (fileProp.multiple) {
723
- return `${FILE_INTERFACE_NAME}[]`;
724
- }
725
- return `${FILE_INTERFACE_NAME} | null`;
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
- }
753
- }
754
- if (property.type === "Enum") {
755
- const enumProp = property;
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
- }
762
- }
763
- if (property.type === "Select") {
764
- const selectProp = property;
765
- if (selectProp.options && selectProp.options.length > 0) {
766
- return selectProp.options.map((v) => `'${v}'`).join(" | ");
767
- }
768
- }
769
- return TYPE_MAP[property.type] ?? "unknown";
770
- }
771
- function propertyToTSProperties(propertyName, property, allSchemas, options = {}) {
772
- const baseProp = property;
773
- const isReadonly = options.readonly ?? true;
774
- if (property.type === "Association") {
775
- const assocProp = property;
776
- if (assocProp.relation === "MorphTo" && assocProp.targets && assocProp.targets.length > 0) {
777
- const propBaseName = toPropertyName(propertyName);
778
- const targetUnion = assocProp.targets.map((t) => `'${t}'`).join(" | ");
779
- const relationUnion = assocProp.targets.join(" | ");
780
- return [
781
- {
782
- name: `${propBaseName}Type`,
783
- type: targetUnion,
784
- optional: true,
785
- // Polymorphic columns are nullable
786
- readonly: isReadonly,
787
- comment: `Polymorphic type for ${propertyName}`
788
- },
789
- {
790
- name: `${propBaseName}Id`,
791
- type: "number",
792
- optional: true,
793
- readonly: isReadonly,
794
- comment: `Polymorphic ID for ${propertyName}`
795
- },
796
- {
797
- name: propBaseName,
798
- type: `${relationUnion} | null`,
799
- optional: true,
800
- readonly: isReadonly,
801
- comment: baseProp.displayName ?? `Polymorphic relation to ${assocProp.targets.join(", ")}`
802
- }
803
- ];
804
- }
805
- }
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
- }
815
- function schemaToInterface(schema, allSchemas, options = {}) {
816
- const properties = [];
817
- if (schema.options?.id !== false) {
818
- const pkType = schema.options?.idType ?? "BigInt";
819
- properties.push({
820
- name: "id",
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
- }
859
- return {
860
- name: toInterfaceName(schema.name),
861
- properties,
862
- comment: schema.displayName ?? schema.name
863
- };
864
- }
865
- function formatProperty(property) {
866
- const readonly = property.readonly ? "readonly " : "";
867
- const optional = property.optional ? "?" : "";
868
- const comment = property.comment ? ` /** ${property.comment} */
869
- ` : "";
870
- return `${comment} ${readonly}${property.name}${optional}: ${property.type};`;
871
- }
872
- function formatInterface(iface) {
873
- const comment = iface.comment ? `/**
874
- * ${iface.comment}
875
- */
876
- ` : "";
877
- const extendsClause = iface.extends && iface.extends.length > 0 ? ` extends ${iface.extends.join(", ")}` : "";
878
- const properties = iface.properties.map(formatProperty).join("\n");
879
- return `${comment}export interface ${iface.name}${extendsClause} {
880
- ${properties}
881
- }`;
882
- }
883
- function generateInterfaces(schemas, options = {}) {
884
- const interfaces = [];
885
- for (const schema of Object.values(schemas)) {
886
- if (schema.kind === "enum") {
887
- continue;
888
- }
889
- interfaces.push(schemaToInterface(schema, schemas, options));
890
- }
891
- return interfaces;
892
- }
893
-
894
- // src/typescript/enum-generator.ts
895
- function toEnumMemberName(value) {
896
- return value.split(/[-_\s]+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("").replace(/[^a-zA-Z0-9]/g, "");
897
- }
898
- function toEnumName(schemaName) {
899
- return schemaName;
900
- }
901
- function schemaToEnum(schema) {
902
- if (schema.kind !== "enum" || !schema.values) {
903
- return null;
904
- }
905
- const values = schema.values.map((value) => ({
906
- name: toEnumMemberName(value),
907
- value
908
- }));
909
- return {
910
- name: toEnumName(schema.name),
911
- values,
912
- comment: schema.displayName ?? schema.name
913
- };
914
- }
915
- function generateEnums(schemas) {
916
- const enums = [];
917
- for (const schema of Object.values(schemas)) {
918
- if (schema.kind === "enum") {
919
- const enumDef = schemaToEnum(schema);
920
- if (enumDef) {
921
- enums.push(enumDef);
922
- }
923
- }
924
- }
925
- return enums;
926
- }
927
- function formatEnum(enumDef) {
928
- const comment = enumDef.comment ? `/**
929
- * ${enumDef.comment}
930
- */
931
- ` : "";
932
- const values = enumDef.values.map((v) => ` ${v.name} = '${v.value}',`).join("\n");
933
- return `${comment}export enum ${enumDef.name} {
934
- ${values}
935
- }`;
936
- }
937
- function formatTypeAlias(alias) {
938
- const comment = alias.comment ? `/**
939
- * ${alias.comment}
940
- */
941
- ` : "";
942
- return `${comment}export type ${alias.name} = ${alias.type};`;
943
- }
944
- function extractInlineEnums(schemas) {
945
- const typeAliases = [];
946
- for (const schema of Object.values(schemas)) {
947
- if (schema.kind === "enum" || !schema.properties) {
948
- continue;
949
- }
950
- for (const [propName, property] of Object.entries(schema.properties)) {
951
- if (property.type === "Enum") {
952
- const enumProp = property;
953
- if (Array.isArray(enumProp.enum) && enumProp.enum.length > 0) {
954
- const typeName = `${schema.name}${propName.charAt(0).toUpperCase() + propName.slice(1)}`;
955
- typeAliases.push({
956
- name: typeName,
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
- }
973
- }
974
- }
975
- return typeAliases;
976
- }
977
-
978
- // src/typescript/generator.ts
979
- var DEFAULT_OPTIONS = {
980
- singleFile: true,
981
- fileName: "types.ts",
982
- readonly: true,
983
- strictNullChecks: true
984
- };
985
- function generateHeader() {
986
- return `/**
987
- * Auto-generated TypeScript types from Omnify schemas.
988
- * DO NOT EDIT - This file is automatically generated.
989
- */
990
-
991
- `;
992
- }
993
- function generateTypeScriptFile(schemas, options = {}) {
994
- const opts = { ...DEFAULT_OPTIONS, ...options };
995
- const parts = [generateHeader()];
996
- const types = [];
997
- const enums = generateEnums(schemas);
998
- if (enums.length > 0) {
999
- parts.push("// Enums\n");
1000
- for (const enumDef of enums) {
1001
- parts.push(formatEnum(enumDef));
1002
- parts.push("\n\n");
1003
- types.push(enumDef.name);
1004
- }
1005
- }
1006
- const inlineEnums = extractInlineEnums(schemas);
1007
- if (inlineEnums.length > 0) {
1008
- parts.push("// Type Aliases\n");
1009
- for (const alias of inlineEnums) {
1010
- parts.push(formatTypeAlias(alias));
1011
- parts.push("\n\n");
1012
- types.push(alias.name);
1013
- }
1014
- }
1015
- const interfaces = generateInterfaces(schemas, opts);
1016
- if (interfaces.length > 0) {
1017
- parts.push("// Interfaces\n");
1018
- for (const iface of interfaces) {
1019
- parts.push(formatInterface(iface));
1020
- parts.push("\n\n");
1021
- types.push(iface.name);
1022
- }
1023
- }
1024
- return {
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(/^-/, "");
1072
- }
1073
- function collectImports(iface, enums, typeAliases, allInterfaces) {
1074
- const imports = /* @__PURE__ */ new Map();
1075
- const enumNames = new Set(enums.map((e) => e.name));
1076
- const aliasNames = new Set(typeAliases.map((a) => a.name));
1077
- const interfaceNames = new Set(allInterfaces.map((i) => i.name));
1078
- for (const prop of iface.properties) {
1079
- if (enumNames.has(prop.type)) {
1080
- const existing = imports.get("./enums.js") ?? [];
1081
- if (!existing.includes(prop.type)) {
1082
- imports.set("./enums.js", [...existing, prop.type]);
1083
- }
1084
- }
1085
- if (aliasNames.has(prop.type)) {
1086
- const existing = imports.get("./type-aliases.js") ?? [];
1087
- if (!existing.includes(prop.type)) {
1088
- imports.set("./type-aliases.js", [...existing, prop.type]);
1089
- }
1090
- }
1091
- const baseType = prop.type.replace("[]", "");
1092
- if (interfaceNames.has(baseType) && baseType !== iface.name) {
1093
- const fileName = `./${toKebabCase(baseType)}.js`;
1094
- const existing = imports.get(fileName) ?? [];
1095
- if (!existing.includes(baseType)) {
1096
- imports.set(fileName, [...existing, baseType]);
1097
- }
1098
- }
1099
- }
1100
- return imports;
1101
- }
1102
- function formatImports(imports) {
1103
- if (imports.size === 0) return "";
1104
- const lines = [];
1105
- for (const [path, names] of imports) {
1106
- lines.push(`import type { ${names.join(", ")} } from '${path}';`);
1107
- }
1108
- return lines.join("\n");
1109
- }
1110
- function generateIndexFile(files) {
1111
- const exports2 = [generateHeader().trim(), ""];
1112
- for (const file of files) {
1113
- if (file.fileName === "index.ts") continue;
1114
- const moduleName = file.fileName.replace(".ts", ".js");
1115
- exports2.push(`export * from './${moduleName}';`);
1116
- }
1117
- return exports2.join("\n") + "\n";
1118
- }
1119
- function generateTypeScript(schemas, options = {}) {
1120
- const opts = { ...DEFAULT_OPTIONS, ...options };
1121
- if (opts.singleFile) {
1122
- return [generateTypeScriptFile(schemas, opts)];
1123
- }
1124
- return generateTypeScriptFiles(schemas, opts);
1125
- }
1126
-
1127
687
  // src/plugin.ts
1128
688
  var LARAVEL_CONFIG_SCHEMA = {
1129
689
  fields: [
1130
- // Paths group
1131
690
  {
1132
691
  key: "migrationsPath",
1133
692
  type: "path",
1134
693
  label: "Migrations Path",
1135
694
  description: "Directory for Laravel migration files",
1136
695
  default: "database/migrations",
1137
- group: "paths"
1138
- },
1139
- {
1140
- key: "typesPath",
1141
- type: "path",
1142
- label: "TypeScript Types Path",
1143
- description: "Directory for generated TypeScript type files",
1144
- default: "types",
1145
- group: "paths"
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"
1155
- },
1156
- {
1157
- key: "generateTypes",
1158
- type: "boolean",
1159
- label: "Generate TypeScript Types",
1160
- description: "Generate TypeScript type definitions",
1161
- default: true,
1162
- group: "generators"
1163
- },
1164
- // Options group
1165
- {
1166
- key: "singleFile",
1167
- type: "boolean",
1168
- label: "Single File Output",
1169
- description: "Generate all types in a single file",
1170
- default: true,
1171
- group: "options"
696
+ group: "output"
1172
697
  },
1173
698
  {
1174
699
  key: "connection",
@@ -1183,65 +708,37 @@ var LARAVEL_CONFIG_SCHEMA = {
1183
708
  function resolveOptions(options) {
1184
709
  return {
1185
710
  migrationsPath: options?.migrationsPath ?? "database/migrations",
1186
- typesPath: options?.typesPath ?? "types",
1187
- singleFile: options?.singleFile ?? true,
1188
711
  connection: options?.connection,
1189
- timestamp: options?.timestamp,
1190
- generateTypes: options?.generateTypes ?? true,
1191
- generateMigrations: options?.generateMigrations ?? true
712
+ timestamp: options?.timestamp
1192
713
  };
1193
714
  }
1194
715
  function laravelPlugin(options) {
1195
716
  const resolved = resolveOptions(options);
1196
717
  return {
1197
718
  name: "@famgia/omnify-laravel",
1198
- version: "0.0.12",
719
+ version: "0.0.13",
1199
720
  configSchema: LARAVEL_CONFIG_SCHEMA,
1200
721
  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
- }
722
+ {
723
+ name: "laravel-migrations",
724
+ description: "Generate Laravel migration files",
725
+ generate: async (ctx) => {
726
+ const migrationOptions = {
727
+ connection: resolved.connection,
728
+ timestamp: resolved.timestamp
729
+ };
730
+ const migrations = generateMigrations(ctx.schemas, migrationOptions);
731
+ return migrations.map((migration) => ({
732
+ path: getMigrationPath(migration, resolved.migrationsPath),
733
+ content: migration.content,
734
+ type: "migration",
735
+ metadata: {
736
+ tableName: migration.tables[0],
737
+ migrationType: migration.type
738
+ }
739
+ }));
1243
740
  }
1244
- ] : []
741
+ }
1245
742
  ]
1246
743
  };
1247
744
  }