@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.
package/dist/index.cjs CHANGED
@@ -2308,7 +2308,8 @@ function resolveOptions2(options) {
2308
2308
  return {
2309
2309
  modelNamespace: options?.modelNamespace ?? "App\\Models",
2310
2310
  factoryPath: options?.factoryPath ?? "database/factories",
2311
- fakerLocale: options?.fakerLocale ?? "en_US"
2311
+ fakerLocale: options?.fakerLocale ?? "en_US",
2312
+ customTypes: options?.customTypes ?? /* @__PURE__ */ new Map()
2312
2313
  };
2313
2314
  }
2314
2315
  function getStubContent2() {
@@ -2341,7 +2342,63 @@ class {{MODEL_NAME}}Factory extends Factory
2341
2342
  }
2342
2343
  `;
2343
2344
  }
2344
- function generateFakeData(propertyName, property, schema, schemas) {
2345
+ function generateJapaneseCompoundFake(propertyName, property, options) {
2346
+ const typeDef = options.customTypes.get(property.type);
2347
+ if (!typeDef || !typeDef.compound || !typeDef.expand) {
2348
+ return null;
2349
+ }
2350
+ const snakeName = toSnakeCase(propertyName);
2351
+ const lines = [];
2352
+ const jaFaker = "fake('ja_JP')";
2353
+ switch (property.type) {
2354
+ case "JapaneseName":
2355
+ lines.push(`'${snakeName}_lastname' => ${jaFaker}->lastName(),`);
2356
+ lines.push(`'${snakeName}_firstname' => ${jaFaker}->firstName(),`);
2357
+ lines.push(`'${snakeName}_kana_lastname' => ${jaFaker}->lastKanaName(),`);
2358
+ lines.push(`'${snakeName}_kana_firstname' => ${jaFaker}->firstKanaName(),`);
2359
+ break;
2360
+ case "JapaneseAddress":
2361
+ lines.push(`'${snakeName}_postal_code' => ${jaFaker}->postcode(),`);
2362
+ lines.push(`'${snakeName}_prefecture_id' => ${jaFaker}->numberBetween(1, 47),`);
2363
+ lines.push(`'${snakeName}_address1' => ${jaFaker}->city() . ${jaFaker}->ward(),`);
2364
+ lines.push(`'${snakeName}_address2' => ${jaFaker}->streetAddress(),`);
2365
+ lines.push(`'${snakeName}_address3' => ${jaFaker}->optional()->secondaryAddress(),`);
2366
+ break;
2367
+ case "JapaneseBankAccount":
2368
+ lines.push(`'${snakeName}_bank_code' => ${jaFaker}->regexify('[0-9]{4}'),`);
2369
+ lines.push(`'${snakeName}_branch_code' => ${jaFaker}->regexify('[0-9]{3}'),`);
2370
+ lines.push(`'${snakeName}_account_type' => ${jaFaker}->randomElement(['1', '2', '4']),`);
2371
+ lines.push(`'${snakeName}_account_number' => ${jaFaker}->regexify('[0-9]{7}'),`);
2372
+ lines.push(`'${snakeName}_account_holder' => ${jaFaker}->lastKanaName() . ' ' . ${jaFaker}->firstKanaName(),`);
2373
+ break;
2374
+ default:
2375
+ for (const field of typeDef.expand) {
2376
+ const suffixSnake = toSnakeCase(field.suffix);
2377
+ const fieldName = `${snakeName}_${suffixSnake}`;
2378
+ const sql = field.sql;
2379
+ if (sql?.sqlType === "TINYINT" || sql?.sqlType === "INT" || sql?.sqlType === "BIGINT") {
2380
+ lines.push(`'${fieldName}' => fake()->numberBetween(1, 100),`);
2381
+ } else {
2382
+ lines.push(`'${fieldName}' => fake()->words(2, true),`);
2383
+ }
2384
+ }
2385
+ break;
2386
+ }
2387
+ return lines;
2388
+ }
2389
+ function generateJapaneseSimpleFake(propertyName, property) {
2390
+ const snakeName = toSnakeCase(propertyName);
2391
+ const jaFaker = "fake('ja_JP')";
2392
+ switch (property.type) {
2393
+ case "JapanesePhone":
2394
+ return `'${snakeName}' => ${jaFaker}->phoneNumber(),`;
2395
+ case "JapanesePostalCode":
2396
+ return `'${snakeName}' => ${jaFaker}->postcode(),`;
2397
+ default:
2398
+ return null;
2399
+ }
2400
+ }
2401
+ function generateFakeData(propertyName, property, schema, schemas, options) {
2345
2402
  const type = property.type;
2346
2403
  if (["deleted_at", "created_at", "updated_at"].includes(propertyName)) {
2347
2404
  return null;
@@ -2349,6 +2406,10 @@ function generateFakeData(propertyName, property, schema, schemas) {
2349
2406
  if (type === "Association") {
2350
2407
  return null;
2351
2408
  }
2409
+ const japaneseFake = generateJapaneseSimpleFake(propertyName, property);
2410
+ if (japaneseFake) {
2411
+ return japaneseFake;
2412
+ }
2352
2413
  switch (type) {
2353
2414
  case "String":
2354
2415
  return generateStringFake(propertyName, property);
@@ -2529,7 +2590,12 @@ function generateFactory(schema, schemas, options, stubContent) {
2529
2590
  }
2530
2591
  continue;
2531
2592
  }
2532
- const fake = generateFakeData(propName, prop, schema, schemas);
2593
+ const compoundFakes = generateJapaneseCompoundFake(propName, prop, options);
2594
+ if (compoundFakes) {
2595
+ attributes.push(...compoundFakes);
2596
+ continue;
2597
+ }
2598
+ const fake = generateFakeData(propName, prop, schema, schemas, options);
2533
2599
  if (fake) {
2534
2600
  attributes.push(fake);
2535
2601
  }
@@ -2699,6 +2765,33 @@ function generateStoreRules(propName, propDef, schema, schemas, options) {
2699
2765
  }
2700
2766
  }
2701
2767
  break;
2768
+ default:
2769
+ const customType = options.customTypes.get(propDef.type);
2770
+ if (customType && !customType.compound) {
2771
+ if (propDef.type === "JapanesePhone") {
2772
+ rules.push("'string'");
2773
+ rules.push("'max:15'");
2774
+ rules.push("'regex:/^\\d{2,4}-\\d{2,4}-\\d{4}$/'");
2775
+ } else if (propDef.type === "JapanesePostalCode") {
2776
+ rules.push("'string'");
2777
+ rules.push("'max:8'");
2778
+ rules.push("'regex:/^\\d{3}-\\d{4}$/'");
2779
+ } else {
2780
+ const sqlType = customType.sql?.sqlType ?? "VARCHAR";
2781
+ const sqlLength = customType.sql?.length ?? 255;
2782
+ if (sqlType === "VARCHAR" || sqlType === "TEXT") {
2783
+ rules.push("'string'");
2784
+ if (sqlType === "VARCHAR") {
2785
+ rules.push(`'max:${sqlLength}'`);
2786
+ }
2787
+ } else if (sqlType === "INT" || sqlType === "TINYINT" || sqlType === "BIGINT") {
2788
+ rules.push("'integer'");
2789
+ } else if (sqlType === "DECIMAL" || sqlType === "FLOAT") {
2790
+ rules.push("'numeric'");
2791
+ }
2792
+ }
2793
+ }
2794
+ break;
2702
2795
  }
2703
2796
  if (prop.unique === true) {
2704
2797
  rules.push(`'unique:${tableName}'`);
@@ -2781,12 +2874,100 @@ function generateUpdateRules(propName, propDef, schema, schemas, options) {
2781
2874
  }
2782
2875
  }
2783
2876
  break;
2877
+ default:
2878
+ const customType = options.customTypes.get(propDef.type);
2879
+ if (customType && !customType.compound) {
2880
+ if (propDef.type === "JapanesePhone") {
2881
+ rules.push("'string'");
2882
+ rules.push("'max:15'");
2883
+ rules.push("'regex:/^\\d{2,4}-\\d{2,4}-\\d{4}$/'");
2884
+ } else if (propDef.type === "JapanesePostalCode") {
2885
+ rules.push("'string'");
2886
+ rules.push("'max:8'");
2887
+ rules.push("'regex:/^\\d{3}-\\d{4}$/'");
2888
+ } else {
2889
+ const sqlType = customType.sql?.sqlType ?? "VARCHAR";
2890
+ const sqlLength = customType.sql?.length ?? 255;
2891
+ if (sqlType === "VARCHAR" || sqlType === "TEXT") {
2892
+ rules.push("'string'");
2893
+ if (sqlType === "VARCHAR") {
2894
+ rules.push(`'max:${sqlLength}'`);
2895
+ }
2896
+ } else if (sqlType === "INT" || sqlType === "TINYINT" || sqlType === "BIGINT") {
2897
+ rules.push("'integer'");
2898
+ } else if (sqlType === "DECIMAL" || sqlType === "FLOAT") {
2899
+ rules.push("'numeric'");
2900
+ }
2901
+ }
2902
+ }
2903
+ break;
2784
2904
  }
2785
2905
  if (prop.unique === true) {
2786
2906
  rules.push(`Rule::unique('${tableName}')->ignore($this->route('${modelVar}'))`);
2787
2907
  }
2788
2908
  return rules;
2789
2909
  }
2910
+ function getCompoundFieldRules(typeName, suffix, field, fieldOverride) {
2911
+ const rules = [];
2912
+ const sql = field.sql;
2913
+ const length = fieldOverride?.length ?? sql?.length ?? 255;
2914
+ switch (typeName) {
2915
+ case "JapaneseName":
2916
+ rules.push("'string'");
2917
+ rules.push(`'max:${length}'`);
2918
+ if (suffix === "KanaLastname" || suffix === "KanaFirstname") {
2919
+ rules.push("'regex:/^[\\x{30A0}-\\x{30FF}\\x{3000}-\\x{303F}\\x{FF00}-\\x{FF9F}\\s]+$/u'");
2920
+ }
2921
+ break;
2922
+ case "JapaneseAddress":
2923
+ if (suffix === "PostalCode") {
2924
+ rules.push("'string'");
2925
+ rules.push("'max:8'");
2926
+ rules.push("'regex:/^\\d{3}-\\d{4}$/'");
2927
+ } else if (suffix === "PrefectureId") {
2928
+ rules.push("'integer'");
2929
+ rules.push("'between:1,47'");
2930
+ } else {
2931
+ rules.push("'string'");
2932
+ rules.push(`'max:${length}'`);
2933
+ }
2934
+ break;
2935
+ case "JapaneseBankAccount":
2936
+ if (suffix === "BankCode") {
2937
+ rules.push("'string'");
2938
+ rules.push("'size:4'");
2939
+ rules.push("'regex:/^\\d{4}$/'");
2940
+ } else if (suffix === "BranchCode") {
2941
+ rules.push("'string'");
2942
+ rules.push("'size:3'");
2943
+ rules.push("'regex:/^\\d{3}$/'");
2944
+ } else if (suffix === "AccountType") {
2945
+ rules.push("'string'");
2946
+ rules.push("Rule::in(['1', '2', '4'])");
2947
+ } else if (suffix === "AccountNumber") {
2948
+ rules.push("'string'");
2949
+ rules.push("'max:7'");
2950
+ rules.push("'regex:/^\\d{1,7}$/'");
2951
+ } else if (suffix === "AccountHolder") {
2952
+ rules.push("'string'");
2953
+ rules.push(`'max:${length}'`);
2954
+ rules.push("'regex:/^[\\x{30A0}-\\x{30FF}\\x{3000}-\\x{303F}\\x{FF00}-\\x{FF9F}\\s]+$/u'");
2955
+ }
2956
+ break;
2957
+ default:
2958
+ if (sql?.sqlType === "TINYINT" || sql?.sqlType === "INT" || sql?.sqlType === "BIGINT") {
2959
+ rules.push("'integer'");
2960
+ if (sql?.unsigned) {
2961
+ rules.push("'min:0'");
2962
+ }
2963
+ } else {
2964
+ rules.push("'string'");
2965
+ rules.push(`'max:${length}'`);
2966
+ }
2967
+ break;
2968
+ }
2969
+ return rules;
2970
+ }
2790
2971
  function expandCompoundTypeFields(propName, propDef, options) {
2791
2972
  const typeDef = options.customTypes.get(propDef.type);
2792
2973
  if (!typeDef || !typeDef.compound || !typeDef.expand) {
@@ -2800,18 +2981,18 @@ function expandCompoundTypeFields(propName, propDef, options) {
2800
2981
  const suffixSnake = toSnakeCase(field.suffix);
2801
2982
  const fieldName = `${snakeName}_${suffixSnake}`;
2802
2983
  const fieldOverride = prop.fields?.[field.suffix];
2803
- const fieldNullable = fieldOverride?.nullable ?? isNullable2;
2984
+ const fieldDefNullable = field.sql?.nullable ?? false;
2985
+ const fieldNullable = fieldOverride?.nullable ?? fieldDefNullable ?? isNullable2;
2804
2986
  const rules = [];
2805
2987
  if (!fieldNullable) {
2806
2988
  rules.push("'required'");
2807
2989
  } else {
2808
2990
  rules.push("'nullable'");
2809
2991
  }
2810
- rules.push("'string'");
2811
- const fieldAny = field;
2812
- const length = fieldAny.laravel?.length ?? 255;
2813
- rules.push(`'max:${length}'`);
2814
- fields.push({ fieldName, rules });
2992
+ const typeRules = getCompoundFieldRules(propDef.type, field.suffix, field, fieldOverride);
2993
+ rules.push(...typeRules);
2994
+ const needsRuleImport = rules.some((r) => r.includes("Rule::"));
2995
+ fields.push({ fieldName, rules, needsRuleImport });
2815
2996
  }
2816
2997
  return fields;
2817
2998
  }
@@ -2845,6 +3026,7 @@ function generateStoreRequestBase(schema, schemas, options) {
2845
3026
  const expandedFields = expandCompoundTypeFields(propName, propDef, options);
2846
3027
  if (expandedFields.length > 0) {
2847
3028
  for (const field of expandedFields) {
3029
+ if (field.needsRuleImport) needsRuleImport = true;
2848
3030
  rulesLines.push(` '${field.fieldName}' => [${field.rules.join(", ")}],`);
2849
3031
  fieldList.push(field.fieldName);
2850
3032
  attributeLines.push(` '${field.fieldName}' => '${escapePhpString2(field.fieldName)}',`);
@@ -2941,6 +3123,7 @@ function generateUpdateRequestBase(schema, schemas, options) {
2941
3123
  const expandedFields = expandCompoundTypeFields(propName, propDef, options);
2942
3124
  if (expandedFields.length > 0) {
2943
3125
  for (const field of expandedFields) {
3126
+ if (field.needsRuleImport) needsRuleImport = true;
2944
3127
  const updateRules = field.rules.map((r) => r === "'required'" ? "'sometimes'" : r);
2945
3128
  rulesLines.push(` '${field.fieldName}' => [${updateRules.join(", ")}],`);
2946
3129
  attributeLines.push(` '${field.fieldName}' => '${escapePhpString2(field.fieldName)}',`);
@@ -2948,7 +3131,7 @@ function generateUpdateRequestBase(schema, schemas, options) {
2948
3131
  continue;
2949
3132
  }
2950
3133
  const rules = generateUpdateRules(propName, propDef, schema, schemas, options);
2951
- if (rules.some((r) => r.includes("Rule::") || r.includes("Rule::"))) needsRuleImport = true;
3134
+ if (rules.some((r) => r.includes("Rule::"))) needsRuleImport = true;
2952
3135
  rulesLines.push(` '${snakeName}' => [${rules.join(", ")}],`);
2953
3136
  const displayName = getDisplayName(propDef.displayName, options.locale, propName);
2954
3137
  attributeLines.push(` '${snakeName}' => '${escapePhpString2(displayName)}',`);
@@ -3174,6 +3357,230 @@ function getRequestPath(request) {
3174
3357
  return request.path;
3175
3358
  }
3176
3359
 
3360
+ // src/resource/generator.ts
3361
+ var import_omnify_types4 = require("@famgia/omnify-types");
3362
+ var DEFAULT_OPTIONS3 = {
3363
+ baseResourceNamespace: "App\\Http\\Resources\\OmnifyBase",
3364
+ resourceNamespace: "App\\Http\\Resources",
3365
+ baseResourcePath: "app/Http/Resources/OmnifyBase",
3366
+ resourcePath: "app/Http/Resources",
3367
+ customTypes: /* @__PURE__ */ new Map(),
3368
+ locale: "en"
3369
+ };
3370
+ var SKIP_FIELDS2 = /* @__PURE__ */ new Set([
3371
+ "password",
3372
+ "remember_token"
3373
+ ]);
3374
+ function resolveOptions4(options) {
3375
+ return {
3376
+ baseResourceNamespace: options?.baseResourceNamespace ?? DEFAULT_OPTIONS3.baseResourceNamespace,
3377
+ resourceNamespace: options?.resourceNamespace ?? DEFAULT_OPTIONS3.resourceNamespace,
3378
+ baseResourcePath: options?.baseResourcePath ?? DEFAULT_OPTIONS3.baseResourcePath,
3379
+ resourcePath: options?.resourcePath ?? DEFAULT_OPTIONS3.resourcePath,
3380
+ customTypes: options?.customTypes ?? /* @__PURE__ */ new Map(),
3381
+ locale: options?.locale ?? DEFAULT_OPTIONS3.locale
3382
+ };
3383
+ }
3384
+ function getModuleName2(schema) {
3385
+ if (schema.module) {
3386
+ return schema.module;
3387
+ }
3388
+ return "";
3389
+ }
3390
+ function getPropertyOutput(propName, propDef, schemas, options) {
3391
+ const snakeName = toSnakeCase(propName);
3392
+ const lines = [];
3393
+ if (SKIP_FIELDS2.has(snakeName)) {
3394
+ return lines;
3395
+ }
3396
+ if (propDef.type === "Association") {
3397
+ const assoc = propDef;
3398
+ const targetClass = assoc.target ? toPascalCase(assoc.target) : "";
3399
+ switch (assoc.relation) {
3400
+ case "ManyToOne":
3401
+ case "OneToOne":
3402
+ lines.push(` '${snakeName}_id' => $this->${snakeName}_id,`);
3403
+ lines.push(` '${snakeName}' => $this->whenLoaded('${toCamelCase(propName)}', fn() => new ${targetClass}Resource($this->${toCamelCase(propName)})),`);
3404
+ break;
3405
+ case "OneToMany":
3406
+ case "ManyToMany":
3407
+ lines.push(` '${snakeName}' => $this->whenLoaded('${toCamelCase(propName)}', fn() => ${targetClass}Resource::collection($this->${toCamelCase(propName)})),`);
3408
+ break;
3409
+ case "MorphTo":
3410
+ lines.push(` '${snakeName}_type' => $this->${snakeName}_type,`);
3411
+ lines.push(` '${snakeName}_id' => $this->${snakeName}_id,`);
3412
+ lines.push(` '${snakeName}' => $this->whenLoaded('${toCamelCase(propName)}'),`);
3413
+ break;
3414
+ case "MorphOne":
3415
+ case "MorphMany":
3416
+ lines.push(` '${snakeName}' => $this->whenLoaded('${toCamelCase(propName)}', fn() => ${targetClass}Resource::collection($this->${toCamelCase(propName)})),`);
3417
+ break;
3418
+ }
3419
+ return lines;
3420
+ }
3421
+ const typeDef = options.customTypes.get(propDef.type);
3422
+ if (typeDef?.compound && typeDef.expand) {
3423
+ for (const field of typeDef.expand) {
3424
+ const suffixSnake = toSnakeCase(field.suffix);
3425
+ const fieldName = `${snakeName}_${suffixSnake}`;
3426
+ lines.push(` '${fieldName}' => $this->${fieldName},`);
3427
+ }
3428
+ if (typeDef.accessors) {
3429
+ for (const accessor of typeDef.accessors) {
3430
+ const accessorName = `${snakeName}_${toSnakeCase(accessor.name)}`;
3431
+ lines.push(` '${accessorName}' => $this->${accessorName},`);
3432
+ }
3433
+ }
3434
+ return lines;
3435
+ }
3436
+ lines.push(` '${snakeName}' => $this->${snakeName},`);
3437
+ return lines;
3438
+ }
3439
+ function generateResourceBase(schema, schemas, options) {
3440
+ const className = toPascalCase(schema.name);
3441
+ const module2 = getModuleName2(schema);
3442
+ const namespaceModule = module2 ? `\\${module2}` : "";
3443
+ const namespace = `${options.baseResourceNamespace}${namespaceModule}`;
3444
+ const properties = schema.properties ?? {};
3445
+ const outputLines = [];
3446
+ const imports = /* @__PURE__ */ new Set();
3447
+ if (schema.options?.id !== false) {
3448
+ outputLines.push(` 'id' => $this->id,`);
3449
+ }
3450
+ for (const [propName, propDef] of Object.entries(properties)) {
3451
+ const lines = getPropertyOutput(propName, propDef, schemas, options);
3452
+ outputLines.push(...lines);
3453
+ if (propDef.type === "Association") {
3454
+ const assoc = propDef;
3455
+ if (assoc.target) {
3456
+ const targetModule = getModuleName2(schemas[assoc.target] ?? schema);
3457
+ const targetModuleNs = targetModule ? `\\${targetModule}` : "";
3458
+ imports.add(`use ${options.resourceNamespace}${targetModuleNs}\\${toPascalCase(assoc.target)}Resource;`);
3459
+ }
3460
+ }
3461
+ }
3462
+ if (schema.options?.timestamps !== false) {
3463
+ outputLines.push(` 'created_at' => $this->created_at?->toISOString(),`);
3464
+ outputLines.push(` 'updated_at' => $this->updated_at?->toISOString(),`);
3465
+ }
3466
+ if (schema.options?.softDelete) {
3467
+ outputLines.push(` 'deleted_at' => $this->deleted_at?->toISOString(),`);
3468
+ }
3469
+ const importLines = Array.from(imports).sort().join("\n");
3470
+ const importBlock = importLines ? `
3471
+ ${importLines}` : "";
3472
+ const content = `<?php
3473
+
3474
+ /**
3475
+ * AUTO-GENERATED BY OMNIFY - DO NOT EDIT!
3476
+ *
3477
+ * This file is generated from Omnify schema: ${schema.name}
3478
+ * Re-run \`npx omnify generate\` to update.
3479
+ *
3480
+ * @generated
3481
+ */
3482
+
3483
+ namespace ${namespace};
3484
+
3485
+ use Illuminate\\Http\\Request;
3486
+ use Illuminate\\Http\\Resources\\Json\\JsonResource;${importBlock}
3487
+
3488
+ class ${className}ResourceBase extends JsonResource
3489
+ {
3490
+ /**
3491
+ * Transform the resource into an array.
3492
+ *
3493
+ * @return array<string, mixed>
3494
+ */
3495
+ protected function schemaArray(Request $request): array
3496
+ {
3497
+ return [
3498
+ ${outputLines.join("\n")}
3499
+ ];
3500
+ }
3501
+ }
3502
+ `;
3503
+ const modulePath = module2 ? `/${module2}` : "";
3504
+ return {
3505
+ path: `${options.baseResourcePath}${modulePath}/${className}ResourceBase.php`,
3506
+ content,
3507
+ type: "base",
3508
+ overwrite: true,
3509
+ schemaName: schema.name,
3510
+ module: module2
3511
+ };
3512
+ }
3513
+ function generateResource(schema, options) {
3514
+ const className = toPascalCase(schema.name);
3515
+ const module2 = getModuleName2(schema);
3516
+ const namespaceModule = module2 ? `\\${module2}` : "";
3517
+ const namespace = `${options.resourceNamespace}${namespaceModule}`;
3518
+ const baseNamespace = `${options.baseResourceNamespace}${namespaceModule}`;
3519
+ const content = `<?php
3520
+
3521
+ /**
3522
+ * ${className} Resource
3523
+ *
3524
+ * SAFE TO EDIT - This file is never overwritten by Omnify.
3525
+ */
3526
+
3527
+ namespace ${namespace};
3528
+
3529
+ use Illuminate\\Http\\Request;
3530
+ use ${baseNamespace}\\${className}ResourceBase;
3531
+
3532
+ class ${className}Resource extends ${className}ResourceBase
3533
+ {
3534
+ /**
3535
+ * Transform the resource into an array.
3536
+ *
3537
+ * @return array<string, mixed>
3538
+ */
3539
+ public function toArray(Request $request): array
3540
+ {
3541
+ return array_merge($this->schemaArray($request), [
3542
+ // Custom fields here
3543
+ ]);
3544
+ }
3545
+
3546
+ /**
3547
+ * Get additional data that should be returned with the resource array.
3548
+ *
3549
+ * @return array<string, mixed>
3550
+ */
3551
+ public function with(Request $request): array
3552
+ {
3553
+ return [
3554
+ // Additional metadata here
3555
+ ];
3556
+ }
3557
+ }
3558
+ `;
3559
+ const modulePath = module2 ? `/${module2}` : "";
3560
+ return {
3561
+ path: `${options.resourcePath}${modulePath}/${className}Resource.php`,
3562
+ content,
3563
+ type: "user",
3564
+ overwrite: false,
3565
+ schemaName: schema.name,
3566
+ module: module2
3567
+ };
3568
+ }
3569
+ function generateResources(schemas, options) {
3570
+ const resolved = resolveOptions4(options);
3571
+ const resources = [];
3572
+ for (const schema of Object.values(schemas)) {
3573
+ if (schema.kind === "enum") continue;
3574
+ if (schema.options?.hidden === true) continue;
3575
+ resources.push(generateResourceBase(schema, schemas, resolved));
3576
+ resources.push(generateResource(schema, resolved));
3577
+ }
3578
+ return resources;
3579
+ }
3580
+ function getResourcePath(resource) {
3581
+ return resource.path;
3582
+ }
3583
+
3177
3584
  // src/plugin.ts
3178
3585
  function getExistingMigrationTables(migrationsDir) {
3179
3586
  const existingTables = /* @__PURE__ */ new Set();
@@ -3282,10 +3689,34 @@ var LARAVEL_CONFIG_SCHEMA = {
3282
3689
  description: "Generate Laravel FormRequest classes for validation",
3283
3690
  default: false,
3284
3691
  group: "options"
3692
+ },
3693
+ {
3694
+ key: "resourcesPath",
3695
+ type: "path",
3696
+ label: "Resources Path",
3697
+ description: "Directory for user-editable API Resource files",
3698
+ default: "app/Http/Resources",
3699
+ group: "output"
3700
+ },
3701
+ {
3702
+ key: "baseResourcesPath",
3703
+ type: "path",
3704
+ label: "Base Resources Path",
3705
+ description: "Directory for auto-generated base API Resource files",
3706
+ default: "app/Http/Resources/OmnifyBase",
3707
+ group: "output"
3708
+ },
3709
+ {
3710
+ key: "generateResources",
3711
+ type: "boolean",
3712
+ label: "Generate Resources",
3713
+ description: "Generate Laravel API Resource classes",
3714
+ default: false,
3715
+ group: "options"
3285
3716
  }
3286
3717
  ]
3287
3718
  };
3288
- function resolveOptions4(options) {
3719
+ function resolveOptions5(options) {
3289
3720
  return {
3290
3721
  migrationsPath: options?.migrationsPath ?? "database/migrations/omnify",
3291
3722
  modelsPath: options?.modelsPath ?? "app/Models",
@@ -3303,11 +3734,16 @@ function resolveOptions4(options) {
3303
3734
  baseRequestsPath: options?.baseRequestsPath ?? "app/Http/Requests/OmnifyBase",
3304
3735
  requestNamespace: options?.requestNamespace ?? "App\\Http\\Requests",
3305
3736
  baseRequestNamespace: options?.baseRequestNamespace ?? "App\\Http\\Requests\\OmnifyBase",
3306
- generateRequests: options?.generateRequests ?? false
3737
+ generateRequests: options?.generateRequests ?? false,
3738
+ resourcesPath: options?.resourcesPath ?? "app/Http/Resources",
3739
+ baseResourcesPath: options?.baseResourcesPath ?? "app/Http/Resources/OmnifyBase",
3740
+ resourceNamespace: options?.resourceNamespace ?? "App\\Http\\Resources",
3741
+ baseResourceNamespace: options?.baseResourceNamespace ?? "App\\Http\\Resources\\OmnifyBase",
3742
+ generateResources: options?.generateResources ?? false
3307
3743
  };
3308
3744
  }
3309
3745
  function laravelPlugin(options) {
3310
- const resolved = resolveOptions4(options);
3746
+ const resolved = resolveOptions5(options);
3311
3747
  const migrationGenerator = {
3312
3748
  name: "laravel-migrations",
3313
3749
  description: "Generate Laravel migration files",
@@ -3463,7 +3899,8 @@ function laravelPlugin(options) {
3463
3899
  const factoryOptions = {
3464
3900
  modelNamespace: resolved.modelNamespace,
3465
3901
  factoryPath: resolved.factoriesPath,
3466
- fakerLocale: resolved.fakerLocale
3902
+ fakerLocale: resolved.fakerLocale,
3903
+ customTypes: ctx.customTypes
3467
3904
  };
3468
3905
  const factories = generateFactories(ctx.schemas, factoryOptions);
3469
3906
  return factories.map((factory) => ({
@@ -3506,6 +3943,32 @@ function laravelPlugin(options) {
3506
3943
  }));
3507
3944
  }
3508
3945
  };
3946
+ const resourceGenerator = {
3947
+ name: "laravel-resources",
3948
+ description: "Generate Laravel API Resource classes",
3949
+ generate: async (ctx) => {
3950
+ const resourceOptions = {
3951
+ resourceNamespace: resolved.resourceNamespace,
3952
+ baseResourceNamespace: resolved.baseResourceNamespace,
3953
+ resourcePath: resolved.resourcesPath,
3954
+ baseResourcePath: resolved.baseResourcesPath,
3955
+ customTypes: ctx.customTypes
3956
+ };
3957
+ const resources = generateResources(ctx.schemas, resourceOptions);
3958
+ return resources.map((resource) => ({
3959
+ path: getResourcePath(resource),
3960
+ content: resource.content,
3961
+ type: "other",
3962
+ // Skip writing user resources if they already exist
3963
+ skipIfExists: !resource.overwrite,
3964
+ metadata: {
3965
+ resourceType: resource.type,
3966
+ schemaName: resource.schemaName,
3967
+ module: resource.module
3968
+ }
3969
+ }));
3970
+ }
3971
+ };
3509
3972
  const generators = [migrationGenerator];
3510
3973
  if (resolved.generateModels) {
3511
3974
  generators.push(modelGenerator);
@@ -3516,6 +3979,9 @@ function laravelPlugin(options) {
3516
3979
  if (resolved.generateRequests) {
3517
3980
  generators.push(requestGenerator);
3518
3981
  }
3982
+ if (resolved.generateResources) {
3983
+ generators.push(resourceGenerator);
3984
+ }
3519
3985
  return {
3520
3986
  name: "@famgia/omnify-laravel",
3521
3987
  version: "0.0.14",