@famgia/omnify-laravel 0.0.79 → 0.0.81

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.
@@ -2262,7 +2262,8 @@ function resolveOptions2(options) {
2262
2262
  return {
2263
2263
  modelNamespace: options?.modelNamespace ?? "App\\Models",
2264
2264
  factoryPath: options?.factoryPath ?? "database/factories",
2265
- fakerLocale: options?.fakerLocale ?? "en_US"
2265
+ fakerLocale: options?.fakerLocale ?? "en_US",
2266
+ customTypes: options?.customTypes ?? /* @__PURE__ */ new Map()
2266
2267
  };
2267
2268
  }
2268
2269
  function getStubContent2() {
@@ -2295,7 +2296,63 @@ class {{MODEL_NAME}}Factory extends Factory
2295
2296
  }
2296
2297
  `;
2297
2298
  }
2298
- function generateFakeData(propertyName, property, schema, schemas) {
2299
+ function generateJapaneseCompoundFake(propertyName, property, options) {
2300
+ const typeDef = options.customTypes.get(property.type);
2301
+ if (!typeDef || !typeDef.compound || !typeDef.expand) {
2302
+ return null;
2303
+ }
2304
+ const snakeName = toSnakeCase(propertyName);
2305
+ const lines = [];
2306
+ const jaFaker = "fake('ja_JP')";
2307
+ switch (property.type) {
2308
+ case "JapaneseName":
2309
+ lines.push(`'${snakeName}_lastname' => ${jaFaker}->lastName(),`);
2310
+ lines.push(`'${snakeName}_firstname' => ${jaFaker}->firstName(),`);
2311
+ lines.push(`'${snakeName}_kana_lastname' => ${jaFaker}->lastKanaName(),`);
2312
+ lines.push(`'${snakeName}_kana_firstname' => ${jaFaker}->firstKanaName(),`);
2313
+ break;
2314
+ case "JapaneseAddress":
2315
+ lines.push(`'${snakeName}_postal_code' => ${jaFaker}->postcode(),`);
2316
+ lines.push(`'${snakeName}_prefecture_id' => ${jaFaker}->numberBetween(1, 47),`);
2317
+ lines.push(`'${snakeName}_address1' => ${jaFaker}->city() . ${jaFaker}->ward(),`);
2318
+ lines.push(`'${snakeName}_address2' => ${jaFaker}->streetAddress(),`);
2319
+ lines.push(`'${snakeName}_address3' => ${jaFaker}->optional()->secondaryAddress(),`);
2320
+ break;
2321
+ case "JapaneseBankAccount":
2322
+ lines.push(`'${snakeName}_bank_code' => ${jaFaker}->regexify('[0-9]{4}'),`);
2323
+ lines.push(`'${snakeName}_branch_code' => ${jaFaker}->regexify('[0-9]{3}'),`);
2324
+ lines.push(`'${snakeName}_account_type' => ${jaFaker}->randomElement(['1', '2', '4']),`);
2325
+ lines.push(`'${snakeName}_account_number' => ${jaFaker}->regexify('[0-9]{7}'),`);
2326
+ lines.push(`'${snakeName}_account_holder' => ${jaFaker}->lastKanaName() . ' ' . ${jaFaker}->firstKanaName(),`);
2327
+ break;
2328
+ default:
2329
+ for (const field of typeDef.expand) {
2330
+ const suffixSnake = toSnakeCase(field.suffix);
2331
+ const fieldName = `${snakeName}_${suffixSnake}`;
2332
+ const sql = field.sql;
2333
+ if (sql?.sqlType === "TINYINT" || sql?.sqlType === "INT" || sql?.sqlType === "BIGINT") {
2334
+ lines.push(`'${fieldName}' => fake()->numberBetween(1, 100),`);
2335
+ } else {
2336
+ lines.push(`'${fieldName}' => fake()->words(2, true),`);
2337
+ }
2338
+ }
2339
+ break;
2340
+ }
2341
+ return lines;
2342
+ }
2343
+ function generateJapaneseSimpleFake(propertyName, property) {
2344
+ const snakeName = toSnakeCase(propertyName);
2345
+ const jaFaker = "fake('ja_JP')";
2346
+ switch (property.type) {
2347
+ case "JapanesePhone":
2348
+ return `'${snakeName}' => ${jaFaker}->phoneNumber(),`;
2349
+ case "JapanesePostalCode":
2350
+ return `'${snakeName}' => ${jaFaker}->postcode(),`;
2351
+ default:
2352
+ return null;
2353
+ }
2354
+ }
2355
+ function generateFakeData(propertyName, property, schema, schemas, options) {
2299
2356
  const type = property.type;
2300
2357
  if (["deleted_at", "created_at", "updated_at"].includes(propertyName)) {
2301
2358
  return null;
@@ -2303,6 +2360,10 @@ function generateFakeData(propertyName, property, schema, schemas) {
2303
2360
  if (type === "Association") {
2304
2361
  return null;
2305
2362
  }
2363
+ const japaneseFake = generateJapaneseSimpleFake(propertyName, property);
2364
+ if (japaneseFake) {
2365
+ return japaneseFake;
2366
+ }
2306
2367
  switch (type) {
2307
2368
  case "String":
2308
2369
  return generateStringFake(propertyName, property);
@@ -2483,7 +2544,12 @@ function generateFactory(schema, schemas, options, stubContent) {
2483
2544
  }
2484
2545
  continue;
2485
2546
  }
2486
- const fake = generateFakeData(propName, prop, schema, schemas);
2547
+ const compoundFakes = generateJapaneseCompoundFake(propName, prop, options);
2548
+ if (compoundFakes) {
2549
+ attributes.push(...compoundFakes);
2550
+ continue;
2551
+ }
2552
+ const fake = generateFakeData(propName, prop, schema, schemas, options);
2487
2553
  if (fake) {
2488
2554
  attributes.push(fake);
2489
2555
  }
@@ -2649,6 +2715,33 @@ function generateStoreRules(propName, propDef, schema, schemas, options) {
2649
2715
  }
2650
2716
  }
2651
2717
  break;
2718
+ default:
2719
+ const customType = options.customTypes.get(propDef.type);
2720
+ if (customType && !customType.compound) {
2721
+ if (propDef.type === "JapanesePhone") {
2722
+ rules.push("'string'");
2723
+ rules.push("'max:15'");
2724
+ rules.push("'regex:/^\\d{2,4}-\\d{2,4}-\\d{4}$/'");
2725
+ } else if (propDef.type === "JapanesePostalCode") {
2726
+ rules.push("'string'");
2727
+ rules.push("'max:8'");
2728
+ rules.push("'regex:/^\\d{3}-\\d{4}$/'");
2729
+ } else {
2730
+ const sqlType = customType.sql?.sqlType ?? "VARCHAR";
2731
+ const sqlLength = customType.sql?.length ?? 255;
2732
+ if (sqlType === "VARCHAR" || sqlType === "TEXT") {
2733
+ rules.push("'string'");
2734
+ if (sqlType === "VARCHAR") {
2735
+ rules.push(`'max:${sqlLength}'`);
2736
+ }
2737
+ } else if (sqlType === "INT" || sqlType === "TINYINT" || sqlType === "BIGINT") {
2738
+ rules.push("'integer'");
2739
+ } else if (sqlType === "DECIMAL" || sqlType === "FLOAT") {
2740
+ rules.push("'numeric'");
2741
+ }
2742
+ }
2743
+ }
2744
+ break;
2652
2745
  }
2653
2746
  if (prop.unique === true) {
2654
2747
  rules.push(`'unique:${tableName}'`);
@@ -2731,12 +2824,100 @@ function generateUpdateRules(propName, propDef, schema, schemas, options) {
2731
2824
  }
2732
2825
  }
2733
2826
  break;
2827
+ default:
2828
+ const customType = options.customTypes.get(propDef.type);
2829
+ if (customType && !customType.compound) {
2830
+ if (propDef.type === "JapanesePhone") {
2831
+ rules.push("'string'");
2832
+ rules.push("'max:15'");
2833
+ rules.push("'regex:/^\\d{2,4}-\\d{2,4}-\\d{4}$/'");
2834
+ } else if (propDef.type === "JapanesePostalCode") {
2835
+ rules.push("'string'");
2836
+ rules.push("'max:8'");
2837
+ rules.push("'regex:/^\\d{3}-\\d{4}$/'");
2838
+ } else {
2839
+ const sqlType = customType.sql?.sqlType ?? "VARCHAR";
2840
+ const sqlLength = customType.sql?.length ?? 255;
2841
+ if (sqlType === "VARCHAR" || sqlType === "TEXT") {
2842
+ rules.push("'string'");
2843
+ if (sqlType === "VARCHAR") {
2844
+ rules.push(`'max:${sqlLength}'`);
2845
+ }
2846
+ } else if (sqlType === "INT" || sqlType === "TINYINT" || sqlType === "BIGINT") {
2847
+ rules.push("'integer'");
2848
+ } else if (sqlType === "DECIMAL" || sqlType === "FLOAT") {
2849
+ rules.push("'numeric'");
2850
+ }
2851
+ }
2852
+ }
2853
+ break;
2734
2854
  }
2735
2855
  if (prop.unique === true) {
2736
2856
  rules.push(`Rule::unique('${tableName}')->ignore($this->route('${modelVar}'))`);
2737
2857
  }
2738
2858
  return rules;
2739
2859
  }
2860
+ function getCompoundFieldRules(typeName, suffix, field, fieldOverride) {
2861
+ const rules = [];
2862
+ const sql = field.sql;
2863
+ const length = fieldOverride?.length ?? sql?.length ?? 255;
2864
+ switch (typeName) {
2865
+ case "JapaneseName":
2866
+ rules.push("'string'");
2867
+ rules.push(`'max:${length}'`);
2868
+ if (suffix === "KanaLastname" || suffix === "KanaFirstname") {
2869
+ rules.push("'regex:/^[\\x{30A0}-\\x{30FF}\\x{3000}-\\x{303F}\\x{FF00}-\\x{FF9F}\\s]+$/u'");
2870
+ }
2871
+ break;
2872
+ case "JapaneseAddress":
2873
+ if (suffix === "PostalCode") {
2874
+ rules.push("'string'");
2875
+ rules.push("'max:8'");
2876
+ rules.push("'regex:/^\\d{3}-\\d{4}$/'");
2877
+ } else if (suffix === "PrefectureId") {
2878
+ rules.push("'integer'");
2879
+ rules.push("'between:1,47'");
2880
+ } else {
2881
+ rules.push("'string'");
2882
+ rules.push(`'max:${length}'`);
2883
+ }
2884
+ break;
2885
+ case "JapaneseBankAccount":
2886
+ if (suffix === "BankCode") {
2887
+ rules.push("'string'");
2888
+ rules.push("'size:4'");
2889
+ rules.push("'regex:/^\\d{4}$/'");
2890
+ } else if (suffix === "BranchCode") {
2891
+ rules.push("'string'");
2892
+ rules.push("'size:3'");
2893
+ rules.push("'regex:/^\\d{3}$/'");
2894
+ } else if (suffix === "AccountType") {
2895
+ rules.push("'string'");
2896
+ rules.push("Rule::in(['1', '2', '4'])");
2897
+ } else if (suffix === "AccountNumber") {
2898
+ rules.push("'string'");
2899
+ rules.push("'max:7'");
2900
+ rules.push("'regex:/^\\d{1,7}$/'");
2901
+ } else if (suffix === "AccountHolder") {
2902
+ rules.push("'string'");
2903
+ rules.push(`'max:${length}'`);
2904
+ rules.push("'regex:/^[\\x{30A0}-\\x{30FF}\\x{3000}-\\x{303F}\\x{FF00}-\\x{FF9F}\\s]+$/u'");
2905
+ }
2906
+ break;
2907
+ default:
2908
+ if (sql?.sqlType === "TINYINT" || sql?.sqlType === "INT" || sql?.sqlType === "BIGINT") {
2909
+ rules.push("'integer'");
2910
+ if (sql?.unsigned) {
2911
+ rules.push("'min:0'");
2912
+ }
2913
+ } else {
2914
+ rules.push("'string'");
2915
+ rules.push(`'max:${length}'`);
2916
+ }
2917
+ break;
2918
+ }
2919
+ return rules;
2920
+ }
2740
2921
  function expandCompoundTypeFields(propName, propDef, options) {
2741
2922
  const typeDef = options.customTypes.get(propDef.type);
2742
2923
  if (!typeDef || !typeDef.compound || !typeDef.expand) {
@@ -2750,18 +2931,18 @@ function expandCompoundTypeFields(propName, propDef, options) {
2750
2931
  const suffixSnake = toSnakeCase(field.suffix);
2751
2932
  const fieldName = `${snakeName}_${suffixSnake}`;
2752
2933
  const fieldOverride = prop.fields?.[field.suffix];
2753
- const fieldNullable = fieldOverride?.nullable ?? isNullable2;
2934
+ const fieldDefNullable = field.sql?.nullable ?? false;
2935
+ const fieldNullable = fieldOverride?.nullable ?? fieldDefNullable ?? isNullable2;
2754
2936
  const rules = [];
2755
2937
  if (!fieldNullable) {
2756
2938
  rules.push("'required'");
2757
2939
  } else {
2758
2940
  rules.push("'nullable'");
2759
2941
  }
2760
- rules.push("'string'");
2761
- const fieldAny = field;
2762
- const length = fieldAny.laravel?.length ?? 255;
2763
- rules.push(`'max:${length}'`);
2764
- fields.push({ fieldName, rules });
2942
+ const typeRules = getCompoundFieldRules(propDef.type, field.suffix, field, fieldOverride);
2943
+ rules.push(...typeRules);
2944
+ const needsRuleImport = rules.some((r) => r.includes("Rule::"));
2945
+ fields.push({ fieldName, rules, needsRuleImport });
2765
2946
  }
2766
2947
  return fields;
2767
2948
  }
@@ -2795,6 +2976,7 @@ function generateStoreRequestBase(schema, schemas, options) {
2795
2976
  const expandedFields = expandCompoundTypeFields(propName, propDef, options);
2796
2977
  if (expandedFields.length > 0) {
2797
2978
  for (const field of expandedFields) {
2979
+ if (field.needsRuleImport) needsRuleImport = true;
2798
2980
  rulesLines.push(` '${field.fieldName}' => [${field.rules.join(", ")}],`);
2799
2981
  fieldList.push(field.fieldName);
2800
2982
  attributeLines.push(` '${field.fieldName}' => '${escapePhpString2(field.fieldName)}',`);
@@ -2891,6 +3073,7 @@ function generateUpdateRequestBase(schema, schemas, options) {
2891
3073
  const expandedFields = expandCompoundTypeFields(propName, propDef, options);
2892
3074
  if (expandedFields.length > 0) {
2893
3075
  for (const field of expandedFields) {
3076
+ if (field.needsRuleImport) needsRuleImport = true;
2894
3077
  const updateRules = field.rules.map((r) => r === "'required'" ? "'sometimes'" : r);
2895
3078
  rulesLines.push(` '${field.fieldName}' => [${updateRules.join(", ")}],`);
2896
3079
  attributeLines.push(` '${field.fieldName}' => '${escapePhpString2(field.fieldName)}',`);
@@ -2898,7 +3081,7 @@ function generateUpdateRequestBase(schema, schemas, options) {
2898
3081
  continue;
2899
3082
  }
2900
3083
  const rules = generateUpdateRules(propName, propDef, schema, schemas, options);
2901
- if (rules.some((r) => r.includes("Rule::") || r.includes("Rule::"))) needsRuleImport = true;
3084
+ if (rules.some((r) => r.includes("Rule::"))) needsRuleImport = true;
2902
3085
  rulesLines.push(` '${snakeName}' => [${rules.join(", ")}],`);
2903
3086
  const displayName = getDisplayName(propDef.displayName, options.locale, propName);
2904
3087
  attributeLines.push(` '${snakeName}' => '${escapePhpString2(displayName)}',`);
@@ -3124,6 +3307,230 @@ function getRequestPath(request) {
3124
3307
  return request.path;
3125
3308
  }
3126
3309
 
3310
+ // src/resource/generator.ts
3311
+ import "@famgia/omnify-types";
3312
+ var DEFAULT_OPTIONS3 = {
3313
+ baseResourceNamespace: "App\\Http\\Resources\\OmnifyBase",
3314
+ resourceNamespace: "App\\Http\\Resources",
3315
+ baseResourcePath: "app/Http/Resources/OmnifyBase",
3316
+ resourcePath: "app/Http/Resources",
3317
+ customTypes: /* @__PURE__ */ new Map(),
3318
+ locale: "en"
3319
+ };
3320
+ var SKIP_FIELDS2 = /* @__PURE__ */ new Set([
3321
+ "password",
3322
+ "remember_token"
3323
+ ]);
3324
+ function resolveOptions4(options) {
3325
+ return {
3326
+ baseResourceNamespace: options?.baseResourceNamespace ?? DEFAULT_OPTIONS3.baseResourceNamespace,
3327
+ resourceNamespace: options?.resourceNamespace ?? DEFAULT_OPTIONS3.resourceNamespace,
3328
+ baseResourcePath: options?.baseResourcePath ?? DEFAULT_OPTIONS3.baseResourcePath,
3329
+ resourcePath: options?.resourcePath ?? DEFAULT_OPTIONS3.resourcePath,
3330
+ customTypes: options?.customTypes ?? /* @__PURE__ */ new Map(),
3331
+ locale: options?.locale ?? DEFAULT_OPTIONS3.locale
3332
+ };
3333
+ }
3334
+ function getModuleName2(schema) {
3335
+ if (schema.module) {
3336
+ return schema.module;
3337
+ }
3338
+ return "";
3339
+ }
3340
+ function getPropertyOutput(propName, propDef, schemas, options) {
3341
+ const snakeName = toSnakeCase(propName);
3342
+ const lines = [];
3343
+ if (SKIP_FIELDS2.has(snakeName)) {
3344
+ return lines;
3345
+ }
3346
+ if (propDef.type === "Association") {
3347
+ const assoc = propDef;
3348
+ const targetClass = assoc.target ? toPascalCase(assoc.target) : "";
3349
+ switch (assoc.relation) {
3350
+ case "ManyToOne":
3351
+ case "OneToOne":
3352
+ lines.push(` '${snakeName}_id' => $this->${snakeName}_id,`);
3353
+ lines.push(` '${snakeName}' => $this->whenLoaded('${toCamelCase(propName)}', fn() => new ${targetClass}Resource($this->${toCamelCase(propName)})),`);
3354
+ break;
3355
+ case "OneToMany":
3356
+ case "ManyToMany":
3357
+ lines.push(` '${snakeName}' => $this->whenLoaded('${toCamelCase(propName)}', fn() => ${targetClass}Resource::collection($this->${toCamelCase(propName)})),`);
3358
+ break;
3359
+ case "MorphTo":
3360
+ lines.push(` '${snakeName}_type' => $this->${snakeName}_type,`);
3361
+ lines.push(` '${snakeName}_id' => $this->${snakeName}_id,`);
3362
+ lines.push(` '${snakeName}' => $this->whenLoaded('${toCamelCase(propName)}'),`);
3363
+ break;
3364
+ case "MorphOne":
3365
+ case "MorphMany":
3366
+ lines.push(` '${snakeName}' => $this->whenLoaded('${toCamelCase(propName)}', fn() => ${targetClass}Resource::collection($this->${toCamelCase(propName)})),`);
3367
+ break;
3368
+ }
3369
+ return lines;
3370
+ }
3371
+ const typeDef = options.customTypes.get(propDef.type);
3372
+ if (typeDef?.compound && typeDef.expand) {
3373
+ for (const field of typeDef.expand) {
3374
+ const suffixSnake = toSnakeCase(field.suffix);
3375
+ const fieldName = `${snakeName}_${suffixSnake}`;
3376
+ lines.push(` '${fieldName}' => $this->${fieldName},`);
3377
+ }
3378
+ if (typeDef.accessors) {
3379
+ for (const accessor of typeDef.accessors) {
3380
+ const accessorName = `${snakeName}_${toSnakeCase(accessor.name)}`;
3381
+ lines.push(` '${accessorName}' => $this->${accessorName},`);
3382
+ }
3383
+ }
3384
+ return lines;
3385
+ }
3386
+ lines.push(` '${snakeName}' => $this->${snakeName},`);
3387
+ return lines;
3388
+ }
3389
+ function generateResourceBase(schema, schemas, options) {
3390
+ const className = toPascalCase(schema.name);
3391
+ const module = getModuleName2(schema);
3392
+ const namespaceModule = module ? `\\${module}` : "";
3393
+ const namespace = `${options.baseResourceNamespace}${namespaceModule}`;
3394
+ const properties = schema.properties ?? {};
3395
+ const outputLines = [];
3396
+ const imports = /* @__PURE__ */ new Set();
3397
+ if (schema.options?.id !== false) {
3398
+ outputLines.push(` 'id' => $this->id,`);
3399
+ }
3400
+ for (const [propName, propDef] of Object.entries(properties)) {
3401
+ const lines = getPropertyOutput(propName, propDef, schemas, options);
3402
+ outputLines.push(...lines);
3403
+ if (propDef.type === "Association") {
3404
+ const assoc = propDef;
3405
+ if (assoc.target) {
3406
+ const targetModule = getModuleName2(schemas[assoc.target] ?? schema);
3407
+ const targetModuleNs = targetModule ? `\\${targetModule}` : "";
3408
+ imports.add(`use ${options.resourceNamespace}${targetModuleNs}\\${toPascalCase(assoc.target)}Resource;`);
3409
+ }
3410
+ }
3411
+ }
3412
+ if (schema.options?.timestamps !== false) {
3413
+ outputLines.push(` 'created_at' => $this->created_at?->toISOString(),`);
3414
+ outputLines.push(` 'updated_at' => $this->updated_at?->toISOString(),`);
3415
+ }
3416
+ if (schema.options?.softDelete) {
3417
+ outputLines.push(` 'deleted_at' => $this->deleted_at?->toISOString(),`);
3418
+ }
3419
+ const importLines = Array.from(imports).sort().join("\n");
3420
+ const importBlock = importLines ? `
3421
+ ${importLines}` : "";
3422
+ const content = `<?php
3423
+
3424
+ /**
3425
+ * AUTO-GENERATED BY OMNIFY - DO NOT EDIT!
3426
+ *
3427
+ * This file is generated from Omnify schema: ${schema.name}
3428
+ * Re-run \`npx omnify generate\` to update.
3429
+ *
3430
+ * @generated
3431
+ */
3432
+
3433
+ namespace ${namespace};
3434
+
3435
+ use Illuminate\\Http\\Request;
3436
+ use Illuminate\\Http\\Resources\\Json\\JsonResource;${importBlock}
3437
+
3438
+ class ${className}ResourceBase extends JsonResource
3439
+ {
3440
+ /**
3441
+ * Transform the resource into an array.
3442
+ *
3443
+ * @return array<string, mixed>
3444
+ */
3445
+ protected function schemaArray(Request $request): array
3446
+ {
3447
+ return [
3448
+ ${outputLines.join("\n")}
3449
+ ];
3450
+ }
3451
+ }
3452
+ `;
3453
+ const modulePath = module ? `/${module}` : "";
3454
+ return {
3455
+ path: `${options.baseResourcePath}${modulePath}/${className}ResourceBase.php`,
3456
+ content,
3457
+ type: "base",
3458
+ overwrite: true,
3459
+ schemaName: schema.name,
3460
+ module
3461
+ };
3462
+ }
3463
+ function generateResource(schema, options) {
3464
+ const className = toPascalCase(schema.name);
3465
+ const module = getModuleName2(schema);
3466
+ const namespaceModule = module ? `\\${module}` : "";
3467
+ const namespace = `${options.resourceNamespace}${namespaceModule}`;
3468
+ const baseNamespace = `${options.baseResourceNamespace}${namespaceModule}`;
3469
+ const content = `<?php
3470
+
3471
+ /**
3472
+ * ${className} Resource
3473
+ *
3474
+ * SAFE TO EDIT - This file is never overwritten by Omnify.
3475
+ */
3476
+
3477
+ namespace ${namespace};
3478
+
3479
+ use Illuminate\\Http\\Request;
3480
+ use ${baseNamespace}\\${className}ResourceBase;
3481
+
3482
+ class ${className}Resource extends ${className}ResourceBase
3483
+ {
3484
+ /**
3485
+ * Transform the resource into an array.
3486
+ *
3487
+ * @return array<string, mixed>
3488
+ */
3489
+ public function toArray(Request $request): array
3490
+ {
3491
+ return array_merge($this->schemaArray($request), [
3492
+ // Custom fields here
3493
+ ]);
3494
+ }
3495
+
3496
+ /**
3497
+ * Get additional data that should be returned with the resource array.
3498
+ *
3499
+ * @return array<string, mixed>
3500
+ */
3501
+ public function with(Request $request): array
3502
+ {
3503
+ return [
3504
+ // Additional metadata here
3505
+ ];
3506
+ }
3507
+ }
3508
+ `;
3509
+ const modulePath = module ? `/${module}` : "";
3510
+ return {
3511
+ path: `${options.resourcePath}${modulePath}/${className}Resource.php`,
3512
+ content,
3513
+ type: "user",
3514
+ overwrite: false,
3515
+ schemaName: schema.name,
3516
+ module
3517
+ };
3518
+ }
3519
+ function generateResources(schemas, options) {
3520
+ const resolved = resolveOptions4(options);
3521
+ const resources = [];
3522
+ for (const schema of Object.values(schemas)) {
3523
+ if (schema.kind === "enum") continue;
3524
+ if (schema.options?.hidden === true) continue;
3525
+ resources.push(generateResourceBase(schema, schemas, resolved));
3526
+ resources.push(generateResource(schema, resolved));
3527
+ }
3528
+ return resources;
3529
+ }
3530
+ function getResourcePath(resource) {
3531
+ return resource.path;
3532
+ }
3533
+
3127
3534
  // src/plugin.ts
3128
3535
  function getExistingMigrationTables(migrationsDir) {
3129
3536
  const existingTables = /* @__PURE__ */ new Set();
@@ -3232,10 +3639,34 @@ var LARAVEL_CONFIG_SCHEMA = {
3232
3639
  description: "Generate Laravel FormRequest classes for validation",
3233
3640
  default: false,
3234
3641
  group: "options"
3642
+ },
3643
+ {
3644
+ key: "resourcesPath",
3645
+ type: "path",
3646
+ label: "Resources Path",
3647
+ description: "Directory for user-editable API Resource files",
3648
+ default: "app/Http/Resources",
3649
+ group: "output"
3650
+ },
3651
+ {
3652
+ key: "baseResourcesPath",
3653
+ type: "path",
3654
+ label: "Base Resources Path",
3655
+ description: "Directory for auto-generated base API Resource files",
3656
+ default: "app/Http/Resources/OmnifyBase",
3657
+ group: "output"
3658
+ },
3659
+ {
3660
+ key: "generateResources",
3661
+ type: "boolean",
3662
+ label: "Generate Resources",
3663
+ description: "Generate Laravel API Resource classes",
3664
+ default: false,
3665
+ group: "options"
3235
3666
  }
3236
3667
  ]
3237
3668
  };
3238
- function resolveOptions4(options) {
3669
+ function resolveOptions5(options) {
3239
3670
  return {
3240
3671
  migrationsPath: options?.migrationsPath ?? "database/migrations/omnify",
3241
3672
  modelsPath: options?.modelsPath ?? "app/Models",
@@ -3253,11 +3684,16 @@ function resolveOptions4(options) {
3253
3684
  baseRequestsPath: options?.baseRequestsPath ?? "app/Http/Requests/OmnifyBase",
3254
3685
  requestNamespace: options?.requestNamespace ?? "App\\Http\\Requests",
3255
3686
  baseRequestNamespace: options?.baseRequestNamespace ?? "App\\Http\\Requests\\OmnifyBase",
3256
- generateRequests: options?.generateRequests ?? false
3687
+ generateRequests: options?.generateRequests ?? false,
3688
+ resourcesPath: options?.resourcesPath ?? "app/Http/Resources",
3689
+ baseResourcesPath: options?.baseResourcesPath ?? "app/Http/Resources/OmnifyBase",
3690
+ resourceNamespace: options?.resourceNamespace ?? "App\\Http\\Resources",
3691
+ baseResourceNamespace: options?.baseResourceNamespace ?? "App\\Http\\Resources\\OmnifyBase",
3692
+ generateResources: options?.generateResources ?? false
3257
3693
  };
3258
3694
  }
3259
3695
  function laravelPlugin(options) {
3260
- const resolved = resolveOptions4(options);
3696
+ const resolved = resolveOptions5(options);
3261
3697
  const migrationGenerator = {
3262
3698
  name: "laravel-migrations",
3263
3699
  description: "Generate Laravel migration files",
@@ -3413,7 +3849,8 @@ function laravelPlugin(options) {
3413
3849
  const factoryOptions = {
3414
3850
  modelNamespace: resolved.modelNamespace,
3415
3851
  factoryPath: resolved.factoriesPath,
3416
- fakerLocale: resolved.fakerLocale
3852
+ fakerLocale: resolved.fakerLocale,
3853
+ customTypes: ctx.customTypes
3417
3854
  };
3418
3855
  const factories = generateFactories(ctx.schemas, factoryOptions);
3419
3856
  return factories.map((factory) => ({
@@ -3456,6 +3893,32 @@ function laravelPlugin(options) {
3456
3893
  }));
3457
3894
  }
3458
3895
  };
3896
+ const resourceGenerator = {
3897
+ name: "laravel-resources",
3898
+ description: "Generate Laravel API Resource classes",
3899
+ generate: async (ctx) => {
3900
+ const resourceOptions = {
3901
+ resourceNamespace: resolved.resourceNamespace,
3902
+ baseResourceNamespace: resolved.baseResourceNamespace,
3903
+ resourcePath: resolved.resourcesPath,
3904
+ baseResourcePath: resolved.baseResourcesPath,
3905
+ customTypes: ctx.customTypes
3906
+ };
3907
+ const resources = generateResources(ctx.schemas, resourceOptions);
3908
+ return resources.map((resource) => ({
3909
+ path: getResourcePath(resource),
3910
+ content: resource.content,
3911
+ type: "other",
3912
+ // Skip writing user resources if they already exist
3913
+ skipIfExists: !resource.overwrite,
3914
+ metadata: {
3915
+ resourceType: resource.type,
3916
+ schemaName: resource.schemaName,
3917
+ module: resource.module
3918
+ }
3919
+ }));
3920
+ }
3921
+ };
3459
3922
  const generators = [migrationGenerator];
3460
3923
  if (resolved.generateModels) {
3461
3924
  generators.push(modelGenerator);
@@ -3466,6 +3929,9 @@ function laravelPlugin(options) {
3466
3929
  if (resolved.generateRequests) {
3467
3930
  generators.push(requestGenerator);
3468
3931
  }
3932
+ if (resolved.generateResources) {
3933
+ generators.push(resourceGenerator);
3934
+ }
3469
3935
  return {
3470
3936
  name: "@famgia/omnify-laravel",
3471
3937
  version: "0.0.14",
@@ -3501,4 +3967,4 @@ export {
3501
3967
  getFactoryPath,
3502
3968
  laravelPlugin
3503
3969
  };
3504
- //# sourceMappingURL=chunk-6QYGCK3D.js.map
3970
+ //# sourceMappingURL=chunk-WFEVU3LX.js.map