@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/{chunk-6QYGCK3D.js → chunk-WFEVU3LX.js} +481 -15
- package/dist/chunk-WFEVU3LX.js.map +1 -0
- package/dist/index.cjs +480 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/plugin.cjs +480 -14
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.d.cts +25 -0
- package/dist/plugin.d.ts +25 -0
- package/dist/plugin.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-6QYGCK3D.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -354,6 +354,8 @@ interface FactoryGeneratorOptions {
|
|
|
354
354
|
factoryPath?: string;
|
|
355
355
|
/** Faker locale */
|
|
356
356
|
fakerLocale?: string;
|
|
357
|
+
/** Custom types registered by plugins */
|
|
358
|
+
customTypes?: ReadonlyMap<string, CustomTypeDefinition>;
|
|
357
359
|
}
|
|
358
360
|
/**
|
|
359
361
|
* Generated factory output.
|
package/dist/index.d.ts
CHANGED
|
@@ -354,6 +354,8 @@ interface FactoryGeneratorOptions {
|
|
|
354
354
|
factoryPath?: string;
|
|
355
355
|
/** Faker locale */
|
|
356
356
|
fakerLocale?: string;
|
|
357
|
+
/** Custom types registered by plugins */
|
|
358
|
+
customTypes?: ReadonlyMap<string, CustomTypeDefinition>;
|
|
357
359
|
}
|
|
358
360
|
/**
|
|
359
361
|
* Generated factory output.
|
package/dist/index.js
CHANGED
package/dist/plugin.cjs
CHANGED
|
@@ -2237,7 +2237,8 @@ function resolveOptions2(options) {
|
|
|
2237
2237
|
return {
|
|
2238
2238
|
modelNamespace: options?.modelNamespace ?? "App\\Models",
|
|
2239
2239
|
factoryPath: options?.factoryPath ?? "database/factories",
|
|
2240
|
-
fakerLocale: options?.fakerLocale ?? "en_US"
|
|
2240
|
+
fakerLocale: options?.fakerLocale ?? "en_US",
|
|
2241
|
+
customTypes: options?.customTypes ?? /* @__PURE__ */ new Map()
|
|
2241
2242
|
};
|
|
2242
2243
|
}
|
|
2243
2244
|
function getStubContent2() {
|
|
@@ -2270,7 +2271,63 @@ class {{MODEL_NAME}}Factory extends Factory
|
|
|
2270
2271
|
}
|
|
2271
2272
|
`;
|
|
2272
2273
|
}
|
|
2273
|
-
function
|
|
2274
|
+
function generateJapaneseCompoundFake(propertyName, property, options) {
|
|
2275
|
+
const typeDef = options.customTypes.get(property.type);
|
|
2276
|
+
if (!typeDef || !typeDef.compound || !typeDef.expand) {
|
|
2277
|
+
return null;
|
|
2278
|
+
}
|
|
2279
|
+
const snakeName = toSnakeCase(propertyName);
|
|
2280
|
+
const lines = [];
|
|
2281
|
+
const jaFaker = "fake('ja_JP')";
|
|
2282
|
+
switch (property.type) {
|
|
2283
|
+
case "JapaneseName":
|
|
2284
|
+
lines.push(`'${snakeName}_lastname' => ${jaFaker}->lastName(),`);
|
|
2285
|
+
lines.push(`'${snakeName}_firstname' => ${jaFaker}->firstName(),`);
|
|
2286
|
+
lines.push(`'${snakeName}_kana_lastname' => ${jaFaker}->lastKanaName(),`);
|
|
2287
|
+
lines.push(`'${snakeName}_kana_firstname' => ${jaFaker}->firstKanaName(),`);
|
|
2288
|
+
break;
|
|
2289
|
+
case "JapaneseAddress":
|
|
2290
|
+
lines.push(`'${snakeName}_postal_code' => ${jaFaker}->postcode(),`);
|
|
2291
|
+
lines.push(`'${snakeName}_prefecture_id' => ${jaFaker}->numberBetween(1, 47),`);
|
|
2292
|
+
lines.push(`'${snakeName}_address1' => ${jaFaker}->city() . ${jaFaker}->ward(),`);
|
|
2293
|
+
lines.push(`'${snakeName}_address2' => ${jaFaker}->streetAddress(),`);
|
|
2294
|
+
lines.push(`'${snakeName}_address3' => ${jaFaker}->optional()->secondaryAddress(),`);
|
|
2295
|
+
break;
|
|
2296
|
+
case "JapaneseBankAccount":
|
|
2297
|
+
lines.push(`'${snakeName}_bank_code' => ${jaFaker}->regexify('[0-9]{4}'),`);
|
|
2298
|
+
lines.push(`'${snakeName}_branch_code' => ${jaFaker}->regexify('[0-9]{3}'),`);
|
|
2299
|
+
lines.push(`'${snakeName}_account_type' => ${jaFaker}->randomElement(['1', '2', '4']),`);
|
|
2300
|
+
lines.push(`'${snakeName}_account_number' => ${jaFaker}->regexify('[0-9]{7}'),`);
|
|
2301
|
+
lines.push(`'${snakeName}_account_holder' => ${jaFaker}->lastKanaName() . ' ' . ${jaFaker}->firstKanaName(),`);
|
|
2302
|
+
break;
|
|
2303
|
+
default:
|
|
2304
|
+
for (const field of typeDef.expand) {
|
|
2305
|
+
const suffixSnake = toSnakeCase(field.suffix);
|
|
2306
|
+
const fieldName = `${snakeName}_${suffixSnake}`;
|
|
2307
|
+
const sql = field.sql;
|
|
2308
|
+
if (sql?.sqlType === "TINYINT" || sql?.sqlType === "INT" || sql?.sqlType === "BIGINT") {
|
|
2309
|
+
lines.push(`'${fieldName}' => fake()->numberBetween(1, 100),`);
|
|
2310
|
+
} else {
|
|
2311
|
+
lines.push(`'${fieldName}' => fake()->words(2, true),`);
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
break;
|
|
2315
|
+
}
|
|
2316
|
+
return lines;
|
|
2317
|
+
}
|
|
2318
|
+
function generateJapaneseSimpleFake(propertyName, property) {
|
|
2319
|
+
const snakeName = toSnakeCase(propertyName);
|
|
2320
|
+
const jaFaker = "fake('ja_JP')";
|
|
2321
|
+
switch (property.type) {
|
|
2322
|
+
case "JapanesePhone":
|
|
2323
|
+
return `'${snakeName}' => ${jaFaker}->phoneNumber(),`;
|
|
2324
|
+
case "JapanesePostalCode":
|
|
2325
|
+
return `'${snakeName}' => ${jaFaker}->postcode(),`;
|
|
2326
|
+
default:
|
|
2327
|
+
return null;
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
function generateFakeData(propertyName, property, schema, schemas, options) {
|
|
2274
2331
|
const type = property.type;
|
|
2275
2332
|
if (["deleted_at", "created_at", "updated_at"].includes(propertyName)) {
|
|
2276
2333
|
return null;
|
|
@@ -2278,6 +2335,10 @@ function generateFakeData(propertyName, property, schema, schemas) {
|
|
|
2278
2335
|
if (type === "Association") {
|
|
2279
2336
|
return null;
|
|
2280
2337
|
}
|
|
2338
|
+
const japaneseFake = generateJapaneseSimpleFake(propertyName, property);
|
|
2339
|
+
if (japaneseFake) {
|
|
2340
|
+
return japaneseFake;
|
|
2341
|
+
}
|
|
2281
2342
|
switch (type) {
|
|
2282
2343
|
case "String":
|
|
2283
2344
|
return generateStringFake(propertyName, property);
|
|
@@ -2458,7 +2519,12 @@ function generateFactory(schema, schemas, options, stubContent) {
|
|
|
2458
2519
|
}
|
|
2459
2520
|
continue;
|
|
2460
2521
|
}
|
|
2461
|
-
const
|
|
2522
|
+
const compoundFakes = generateJapaneseCompoundFake(propName, prop, options);
|
|
2523
|
+
if (compoundFakes) {
|
|
2524
|
+
attributes.push(...compoundFakes);
|
|
2525
|
+
continue;
|
|
2526
|
+
}
|
|
2527
|
+
const fake = generateFakeData(propName, prop, schema, schemas, options);
|
|
2462
2528
|
if (fake) {
|
|
2463
2529
|
attributes.push(fake);
|
|
2464
2530
|
}
|
|
@@ -2624,6 +2690,33 @@ function generateStoreRules(propName, propDef, schema, schemas, options) {
|
|
|
2624
2690
|
}
|
|
2625
2691
|
}
|
|
2626
2692
|
break;
|
|
2693
|
+
default:
|
|
2694
|
+
const customType = options.customTypes.get(propDef.type);
|
|
2695
|
+
if (customType && !customType.compound) {
|
|
2696
|
+
if (propDef.type === "JapanesePhone") {
|
|
2697
|
+
rules.push("'string'");
|
|
2698
|
+
rules.push("'max:15'");
|
|
2699
|
+
rules.push("'regex:/^\\d{2,4}-\\d{2,4}-\\d{4}$/'");
|
|
2700
|
+
} else if (propDef.type === "JapanesePostalCode") {
|
|
2701
|
+
rules.push("'string'");
|
|
2702
|
+
rules.push("'max:8'");
|
|
2703
|
+
rules.push("'regex:/^\\d{3}-\\d{4}$/'");
|
|
2704
|
+
} else {
|
|
2705
|
+
const sqlType = customType.sql?.sqlType ?? "VARCHAR";
|
|
2706
|
+
const sqlLength = customType.sql?.length ?? 255;
|
|
2707
|
+
if (sqlType === "VARCHAR" || sqlType === "TEXT") {
|
|
2708
|
+
rules.push("'string'");
|
|
2709
|
+
if (sqlType === "VARCHAR") {
|
|
2710
|
+
rules.push(`'max:${sqlLength}'`);
|
|
2711
|
+
}
|
|
2712
|
+
} else if (sqlType === "INT" || sqlType === "TINYINT" || sqlType === "BIGINT") {
|
|
2713
|
+
rules.push("'integer'");
|
|
2714
|
+
} else if (sqlType === "DECIMAL" || sqlType === "FLOAT") {
|
|
2715
|
+
rules.push("'numeric'");
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2719
|
+
break;
|
|
2627
2720
|
}
|
|
2628
2721
|
if (prop.unique === true) {
|
|
2629
2722
|
rules.push(`'unique:${tableName}'`);
|
|
@@ -2706,12 +2799,100 @@ function generateUpdateRules(propName, propDef, schema, schemas, options) {
|
|
|
2706
2799
|
}
|
|
2707
2800
|
}
|
|
2708
2801
|
break;
|
|
2802
|
+
default:
|
|
2803
|
+
const customType = options.customTypes.get(propDef.type);
|
|
2804
|
+
if (customType && !customType.compound) {
|
|
2805
|
+
if (propDef.type === "JapanesePhone") {
|
|
2806
|
+
rules.push("'string'");
|
|
2807
|
+
rules.push("'max:15'");
|
|
2808
|
+
rules.push("'regex:/^\\d{2,4}-\\d{2,4}-\\d{4}$/'");
|
|
2809
|
+
} else if (propDef.type === "JapanesePostalCode") {
|
|
2810
|
+
rules.push("'string'");
|
|
2811
|
+
rules.push("'max:8'");
|
|
2812
|
+
rules.push("'regex:/^\\d{3}-\\d{4}$/'");
|
|
2813
|
+
} else {
|
|
2814
|
+
const sqlType = customType.sql?.sqlType ?? "VARCHAR";
|
|
2815
|
+
const sqlLength = customType.sql?.length ?? 255;
|
|
2816
|
+
if (sqlType === "VARCHAR" || sqlType === "TEXT") {
|
|
2817
|
+
rules.push("'string'");
|
|
2818
|
+
if (sqlType === "VARCHAR") {
|
|
2819
|
+
rules.push(`'max:${sqlLength}'`);
|
|
2820
|
+
}
|
|
2821
|
+
} else if (sqlType === "INT" || sqlType === "TINYINT" || sqlType === "BIGINT") {
|
|
2822
|
+
rules.push("'integer'");
|
|
2823
|
+
} else if (sqlType === "DECIMAL" || sqlType === "FLOAT") {
|
|
2824
|
+
rules.push("'numeric'");
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
break;
|
|
2709
2829
|
}
|
|
2710
2830
|
if (prop.unique === true) {
|
|
2711
2831
|
rules.push(`Rule::unique('${tableName}')->ignore($this->route('${modelVar}'))`);
|
|
2712
2832
|
}
|
|
2713
2833
|
return rules;
|
|
2714
2834
|
}
|
|
2835
|
+
function getCompoundFieldRules(typeName, suffix, field, fieldOverride) {
|
|
2836
|
+
const rules = [];
|
|
2837
|
+
const sql = field.sql;
|
|
2838
|
+
const length = fieldOverride?.length ?? sql?.length ?? 255;
|
|
2839
|
+
switch (typeName) {
|
|
2840
|
+
case "JapaneseName":
|
|
2841
|
+
rules.push("'string'");
|
|
2842
|
+
rules.push(`'max:${length}'`);
|
|
2843
|
+
if (suffix === "KanaLastname" || suffix === "KanaFirstname") {
|
|
2844
|
+
rules.push("'regex:/^[\\x{30A0}-\\x{30FF}\\x{3000}-\\x{303F}\\x{FF00}-\\x{FF9F}\\s]+$/u'");
|
|
2845
|
+
}
|
|
2846
|
+
break;
|
|
2847
|
+
case "JapaneseAddress":
|
|
2848
|
+
if (suffix === "PostalCode") {
|
|
2849
|
+
rules.push("'string'");
|
|
2850
|
+
rules.push("'max:8'");
|
|
2851
|
+
rules.push("'regex:/^\\d{3}-\\d{4}$/'");
|
|
2852
|
+
} else if (suffix === "PrefectureId") {
|
|
2853
|
+
rules.push("'integer'");
|
|
2854
|
+
rules.push("'between:1,47'");
|
|
2855
|
+
} else {
|
|
2856
|
+
rules.push("'string'");
|
|
2857
|
+
rules.push(`'max:${length}'`);
|
|
2858
|
+
}
|
|
2859
|
+
break;
|
|
2860
|
+
case "JapaneseBankAccount":
|
|
2861
|
+
if (suffix === "BankCode") {
|
|
2862
|
+
rules.push("'string'");
|
|
2863
|
+
rules.push("'size:4'");
|
|
2864
|
+
rules.push("'regex:/^\\d{4}$/'");
|
|
2865
|
+
} else if (suffix === "BranchCode") {
|
|
2866
|
+
rules.push("'string'");
|
|
2867
|
+
rules.push("'size:3'");
|
|
2868
|
+
rules.push("'regex:/^\\d{3}$/'");
|
|
2869
|
+
} else if (suffix === "AccountType") {
|
|
2870
|
+
rules.push("'string'");
|
|
2871
|
+
rules.push("Rule::in(['1', '2', '4'])");
|
|
2872
|
+
} else if (suffix === "AccountNumber") {
|
|
2873
|
+
rules.push("'string'");
|
|
2874
|
+
rules.push("'max:7'");
|
|
2875
|
+
rules.push("'regex:/^\\d{1,7}$/'");
|
|
2876
|
+
} else if (suffix === "AccountHolder") {
|
|
2877
|
+
rules.push("'string'");
|
|
2878
|
+
rules.push(`'max:${length}'`);
|
|
2879
|
+
rules.push("'regex:/^[\\x{30A0}-\\x{30FF}\\x{3000}-\\x{303F}\\x{FF00}-\\x{FF9F}\\s]+$/u'");
|
|
2880
|
+
}
|
|
2881
|
+
break;
|
|
2882
|
+
default:
|
|
2883
|
+
if (sql?.sqlType === "TINYINT" || sql?.sqlType === "INT" || sql?.sqlType === "BIGINT") {
|
|
2884
|
+
rules.push("'integer'");
|
|
2885
|
+
if (sql?.unsigned) {
|
|
2886
|
+
rules.push("'min:0'");
|
|
2887
|
+
}
|
|
2888
|
+
} else {
|
|
2889
|
+
rules.push("'string'");
|
|
2890
|
+
rules.push(`'max:${length}'`);
|
|
2891
|
+
}
|
|
2892
|
+
break;
|
|
2893
|
+
}
|
|
2894
|
+
return rules;
|
|
2895
|
+
}
|
|
2715
2896
|
function expandCompoundTypeFields(propName, propDef, options) {
|
|
2716
2897
|
const typeDef = options.customTypes.get(propDef.type);
|
|
2717
2898
|
if (!typeDef || !typeDef.compound || !typeDef.expand) {
|
|
@@ -2725,18 +2906,18 @@ function expandCompoundTypeFields(propName, propDef, options) {
|
|
|
2725
2906
|
const suffixSnake = toSnakeCase(field.suffix);
|
|
2726
2907
|
const fieldName = `${snakeName}_${suffixSnake}`;
|
|
2727
2908
|
const fieldOverride = prop.fields?.[field.suffix];
|
|
2728
|
-
const
|
|
2909
|
+
const fieldDefNullable = field.sql?.nullable ?? false;
|
|
2910
|
+
const fieldNullable = fieldOverride?.nullable ?? fieldDefNullable ?? isNullable2;
|
|
2729
2911
|
const rules = [];
|
|
2730
2912
|
if (!fieldNullable) {
|
|
2731
2913
|
rules.push("'required'");
|
|
2732
2914
|
} else {
|
|
2733
2915
|
rules.push("'nullable'");
|
|
2734
2916
|
}
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
const
|
|
2738
|
-
|
|
2739
|
-
fields.push({ fieldName, rules });
|
|
2917
|
+
const typeRules = getCompoundFieldRules(propDef.type, field.suffix, field, fieldOverride);
|
|
2918
|
+
rules.push(...typeRules);
|
|
2919
|
+
const needsRuleImport = rules.some((r) => r.includes("Rule::"));
|
|
2920
|
+
fields.push({ fieldName, rules, needsRuleImport });
|
|
2740
2921
|
}
|
|
2741
2922
|
return fields;
|
|
2742
2923
|
}
|
|
@@ -2770,6 +2951,7 @@ function generateStoreRequestBase(schema, schemas, options) {
|
|
|
2770
2951
|
const expandedFields = expandCompoundTypeFields(propName, propDef, options);
|
|
2771
2952
|
if (expandedFields.length > 0) {
|
|
2772
2953
|
for (const field of expandedFields) {
|
|
2954
|
+
if (field.needsRuleImport) needsRuleImport = true;
|
|
2773
2955
|
rulesLines.push(` '${field.fieldName}' => [${field.rules.join(", ")}],`);
|
|
2774
2956
|
fieldList.push(field.fieldName);
|
|
2775
2957
|
attributeLines.push(` '${field.fieldName}' => '${escapePhpString2(field.fieldName)}',`);
|
|
@@ -2866,6 +3048,7 @@ function generateUpdateRequestBase(schema, schemas, options) {
|
|
|
2866
3048
|
const expandedFields = expandCompoundTypeFields(propName, propDef, options);
|
|
2867
3049
|
if (expandedFields.length > 0) {
|
|
2868
3050
|
for (const field of expandedFields) {
|
|
3051
|
+
if (field.needsRuleImport) needsRuleImport = true;
|
|
2869
3052
|
const updateRules = field.rules.map((r) => r === "'required'" ? "'sometimes'" : r);
|
|
2870
3053
|
rulesLines.push(` '${field.fieldName}' => [${updateRules.join(", ")}],`);
|
|
2871
3054
|
attributeLines.push(` '${field.fieldName}' => '${escapePhpString2(field.fieldName)}',`);
|
|
@@ -2873,7 +3056,7 @@ function generateUpdateRequestBase(schema, schemas, options) {
|
|
|
2873
3056
|
continue;
|
|
2874
3057
|
}
|
|
2875
3058
|
const rules = generateUpdateRules(propName, propDef, schema, schemas, options);
|
|
2876
|
-
if (rules.some((r) => r.includes("Rule::")
|
|
3059
|
+
if (rules.some((r) => r.includes("Rule::"))) needsRuleImport = true;
|
|
2877
3060
|
rulesLines.push(` '${snakeName}' => [${rules.join(", ")}],`);
|
|
2878
3061
|
const displayName = getDisplayName(propDef.displayName, options.locale, propName);
|
|
2879
3062
|
attributeLines.push(` '${snakeName}' => '${escapePhpString2(displayName)}',`);
|
|
@@ -3099,6 +3282,230 @@ function getRequestPath(request) {
|
|
|
3099
3282
|
return request.path;
|
|
3100
3283
|
}
|
|
3101
3284
|
|
|
3285
|
+
// src/resource/generator.ts
|
|
3286
|
+
var import_omnify_types4 = require("@famgia/omnify-types");
|
|
3287
|
+
var DEFAULT_OPTIONS3 = {
|
|
3288
|
+
baseResourceNamespace: "App\\Http\\Resources\\OmnifyBase",
|
|
3289
|
+
resourceNamespace: "App\\Http\\Resources",
|
|
3290
|
+
baseResourcePath: "app/Http/Resources/OmnifyBase",
|
|
3291
|
+
resourcePath: "app/Http/Resources",
|
|
3292
|
+
customTypes: /* @__PURE__ */ new Map(),
|
|
3293
|
+
locale: "en"
|
|
3294
|
+
};
|
|
3295
|
+
var SKIP_FIELDS2 = /* @__PURE__ */ new Set([
|
|
3296
|
+
"password",
|
|
3297
|
+
"remember_token"
|
|
3298
|
+
]);
|
|
3299
|
+
function resolveOptions4(options) {
|
|
3300
|
+
return {
|
|
3301
|
+
baseResourceNamespace: options?.baseResourceNamespace ?? DEFAULT_OPTIONS3.baseResourceNamespace,
|
|
3302
|
+
resourceNamespace: options?.resourceNamespace ?? DEFAULT_OPTIONS3.resourceNamespace,
|
|
3303
|
+
baseResourcePath: options?.baseResourcePath ?? DEFAULT_OPTIONS3.baseResourcePath,
|
|
3304
|
+
resourcePath: options?.resourcePath ?? DEFAULT_OPTIONS3.resourcePath,
|
|
3305
|
+
customTypes: options?.customTypes ?? /* @__PURE__ */ new Map(),
|
|
3306
|
+
locale: options?.locale ?? DEFAULT_OPTIONS3.locale
|
|
3307
|
+
};
|
|
3308
|
+
}
|
|
3309
|
+
function getModuleName2(schema) {
|
|
3310
|
+
if (schema.module) {
|
|
3311
|
+
return schema.module;
|
|
3312
|
+
}
|
|
3313
|
+
return "";
|
|
3314
|
+
}
|
|
3315
|
+
function getPropertyOutput(propName, propDef, schemas, options) {
|
|
3316
|
+
const snakeName = toSnakeCase(propName);
|
|
3317
|
+
const lines = [];
|
|
3318
|
+
if (SKIP_FIELDS2.has(snakeName)) {
|
|
3319
|
+
return lines;
|
|
3320
|
+
}
|
|
3321
|
+
if (propDef.type === "Association") {
|
|
3322
|
+
const assoc = propDef;
|
|
3323
|
+
const targetClass = assoc.target ? toPascalCase(assoc.target) : "";
|
|
3324
|
+
switch (assoc.relation) {
|
|
3325
|
+
case "ManyToOne":
|
|
3326
|
+
case "OneToOne":
|
|
3327
|
+
lines.push(` '${snakeName}_id' => $this->${snakeName}_id,`);
|
|
3328
|
+
lines.push(` '${snakeName}' => $this->whenLoaded('${toCamelCase(propName)}', fn() => new ${targetClass}Resource($this->${toCamelCase(propName)})),`);
|
|
3329
|
+
break;
|
|
3330
|
+
case "OneToMany":
|
|
3331
|
+
case "ManyToMany":
|
|
3332
|
+
lines.push(` '${snakeName}' => $this->whenLoaded('${toCamelCase(propName)}', fn() => ${targetClass}Resource::collection($this->${toCamelCase(propName)})),`);
|
|
3333
|
+
break;
|
|
3334
|
+
case "MorphTo":
|
|
3335
|
+
lines.push(` '${snakeName}_type' => $this->${snakeName}_type,`);
|
|
3336
|
+
lines.push(` '${snakeName}_id' => $this->${snakeName}_id,`);
|
|
3337
|
+
lines.push(` '${snakeName}' => $this->whenLoaded('${toCamelCase(propName)}'),`);
|
|
3338
|
+
break;
|
|
3339
|
+
case "MorphOne":
|
|
3340
|
+
case "MorphMany":
|
|
3341
|
+
lines.push(` '${snakeName}' => $this->whenLoaded('${toCamelCase(propName)}', fn() => ${targetClass}Resource::collection($this->${toCamelCase(propName)})),`);
|
|
3342
|
+
break;
|
|
3343
|
+
}
|
|
3344
|
+
return lines;
|
|
3345
|
+
}
|
|
3346
|
+
const typeDef = options.customTypes.get(propDef.type);
|
|
3347
|
+
if (typeDef?.compound && typeDef.expand) {
|
|
3348
|
+
for (const field of typeDef.expand) {
|
|
3349
|
+
const suffixSnake = toSnakeCase(field.suffix);
|
|
3350
|
+
const fieldName = `${snakeName}_${suffixSnake}`;
|
|
3351
|
+
lines.push(` '${fieldName}' => $this->${fieldName},`);
|
|
3352
|
+
}
|
|
3353
|
+
if (typeDef.accessors) {
|
|
3354
|
+
for (const accessor of typeDef.accessors) {
|
|
3355
|
+
const accessorName = `${snakeName}_${toSnakeCase(accessor.name)}`;
|
|
3356
|
+
lines.push(` '${accessorName}' => $this->${accessorName},`);
|
|
3357
|
+
}
|
|
3358
|
+
}
|
|
3359
|
+
return lines;
|
|
3360
|
+
}
|
|
3361
|
+
lines.push(` '${snakeName}' => $this->${snakeName},`);
|
|
3362
|
+
return lines;
|
|
3363
|
+
}
|
|
3364
|
+
function generateResourceBase(schema, schemas, options) {
|
|
3365
|
+
const className = toPascalCase(schema.name);
|
|
3366
|
+
const module2 = getModuleName2(schema);
|
|
3367
|
+
const namespaceModule = module2 ? `\\${module2}` : "";
|
|
3368
|
+
const namespace = `${options.baseResourceNamespace}${namespaceModule}`;
|
|
3369
|
+
const properties = schema.properties ?? {};
|
|
3370
|
+
const outputLines = [];
|
|
3371
|
+
const imports = /* @__PURE__ */ new Set();
|
|
3372
|
+
if (schema.options?.id !== false) {
|
|
3373
|
+
outputLines.push(` 'id' => $this->id,`);
|
|
3374
|
+
}
|
|
3375
|
+
for (const [propName, propDef] of Object.entries(properties)) {
|
|
3376
|
+
const lines = getPropertyOutput(propName, propDef, schemas, options);
|
|
3377
|
+
outputLines.push(...lines);
|
|
3378
|
+
if (propDef.type === "Association") {
|
|
3379
|
+
const assoc = propDef;
|
|
3380
|
+
if (assoc.target) {
|
|
3381
|
+
const targetModule = getModuleName2(schemas[assoc.target] ?? schema);
|
|
3382
|
+
const targetModuleNs = targetModule ? `\\${targetModule}` : "";
|
|
3383
|
+
imports.add(`use ${options.resourceNamespace}${targetModuleNs}\\${toPascalCase(assoc.target)}Resource;`);
|
|
3384
|
+
}
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3387
|
+
if (schema.options?.timestamps !== false) {
|
|
3388
|
+
outputLines.push(` 'created_at' => $this->created_at?->toISOString(),`);
|
|
3389
|
+
outputLines.push(` 'updated_at' => $this->updated_at?->toISOString(),`);
|
|
3390
|
+
}
|
|
3391
|
+
if (schema.options?.softDelete) {
|
|
3392
|
+
outputLines.push(` 'deleted_at' => $this->deleted_at?->toISOString(),`);
|
|
3393
|
+
}
|
|
3394
|
+
const importLines = Array.from(imports).sort().join("\n");
|
|
3395
|
+
const importBlock = importLines ? `
|
|
3396
|
+
${importLines}` : "";
|
|
3397
|
+
const content = `<?php
|
|
3398
|
+
|
|
3399
|
+
/**
|
|
3400
|
+
* AUTO-GENERATED BY OMNIFY - DO NOT EDIT!
|
|
3401
|
+
*
|
|
3402
|
+
* This file is generated from Omnify schema: ${schema.name}
|
|
3403
|
+
* Re-run \`npx omnify generate\` to update.
|
|
3404
|
+
*
|
|
3405
|
+
* @generated
|
|
3406
|
+
*/
|
|
3407
|
+
|
|
3408
|
+
namespace ${namespace};
|
|
3409
|
+
|
|
3410
|
+
use Illuminate\\Http\\Request;
|
|
3411
|
+
use Illuminate\\Http\\Resources\\Json\\JsonResource;${importBlock}
|
|
3412
|
+
|
|
3413
|
+
class ${className}ResourceBase extends JsonResource
|
|
3414
|
+
{
|
|
3415
|
+
/**
|
|
3416
|
+
* Transform the resource into an array.
|
|
3417
|
+
*
|
|
3418
|
+
* @return array<string, mixed>
|
|
3419
|
+
*/
|
|
3420
|
+
protected function schemaArray(Request $request): array
|
|
3421
|
+
{
|
|
3422
|
+
return [
|
|
3423
|
+
${outputLines.join("\n")}
|
|
3424
|
+
];
|
|
3425
|
+
}
|
|
3426
|
+
}
|
|
3427
|
+
`;
|
|
3428
|
+
const modulePath = module2 ? `/${module2}` : "";
|
|
3429
|
+
return {
|
|
3430
|
+
path: `${options.baseResourcePath}${modulePath}/${className}ResourceBase.php`,
|
|
3431
|
+
content,
|
|
3432
|
+
type: "base",
|
|
3433
|
+
overwrite: true,
|
|
3434
|
+
schemaName: schema.name,
|
|
3435
|
+
module: module2
|
|
3436
|
+
};
|
|
3437
|
+
}
|
|
3438
|
+
function generateResource(schema, options) {
|
|
3439
|
+
const className = toPascalCase(schema.name);
|
|
3440
|
+
const module2 = getModuleName2(schema);
|
|
3441
|
+
const namespaceModule = module2 ? `\\${module2}` : "";
|
|
3442
|
+
const namespace = `${options.resourceNamespace}${namespaceModule}`;
|
|
3443
|
+
const baseNamespace = `${options.baseResourceNamespace}${namespaceModule}`;
|
|
3444
|
+
const content = `<?php
|
|
3445
|
+
|
|
3446
|
+
/**
|
|
3447
|
+
* ${className} Resource
|
|
3448
|
+
*
|
|
3449
|
+
* SAFE TO EDIT - This file is never overwritten by Omnify.
|
|
3450
|
+
*/
|
|
3451
|
+
|
|
3452
|
+
namespace ${namespace};
|
|
3453
|
+
|
|
3454
|
+
use Illuminate\\Http\\Request;
|
|
3455
|
+
use ${baseNamespace}\\${className}ResourceBase;
|
|
3456
|
+
|
|
3457
|
+
class ${className}Resource extends ${className}ResourceBase
|
|
3458
|
+
{
|
|
3459
|
+
/**
|
|
3460
|
+
* Transform the resource into an array.
|
|
3461
|
+
*
|
|
3462
|
+
* @return array<string, mixed>
|
|
3463
|
+
*/
|
|
3464
|
+
public function toArray(Request $request): array
|
|
3465
|
+
{
|
|
3466
|
+
return array_merge($this->schemaArray($request), [
|
|
3467
|
+
// Custom fields here
|
|
3468
|
+
]);
|
|
3469
|
+
}
|
|
3470
|
+
|
|
3471
|
+
/**
|
|
3472
|
+
* Get additional data that should be returned with the resource array.
|
|
3473
|
+
*
|
|
3474
|
+
* @return array<string, mixed>
|
|
3475
|
+
*/
|
|
3476
|
+
public function with(Request $request): array
|
|
3477
|
+
{
|
|
3478
|
+
return [
|
|
3479
|
+
// Additional metadata here
|
|
3480
|
+
];
|
|
3481
|
+
}
|
|
3482
|
+
}
|
|
3483
|
+
`;
|
|
3484
|
+
const modulePath = module2 ? `/${module2}` : "";
|
|
3485
|
+
return {
|
|
3486
|
+
path: `${options.resourcePath}${modulePath}/${className}Resource.php`,
|
|
3487
|
+
content,
|
|
3488
|
+
type: "user",
|
|
3489
|
+
overwrite: false,
|
|
3490
|
+
schemaName: schema.name,
|
|
3491
|
+
module: module2
|
|
3492
|
+
};
|
|
3493
|
+
}
|
|
3494
|
+
function generateResources(schemas, options) {
|
|
3495
|
+
const resolved = resolveOptions4(options);
|
|
3496
|
+
const resources = [];
|
|
3497
|
+
for (const schema of Object.values(schemas)) {
|
|
3498
|
+
if (schema.kind === "enum") continue;
|
|
3499
|
+
if (schema.options?.hidden === true) continue;
|
|
3500
|
+
resources.push(generateResourceBase(schema, schemas, resolved));
|
|
3501
|
+
resources.push(generateResource(schema, resolved));
|
|
3502
|
+
}
|
|
3503
|
+
return resources;
|
|
3504
|
+
}
|
|
3505
|
+
function getResourcePath(resource) {
|
|
3506
|
+
return resource.path;
|
|
3507
|
+
}
|
|
3508
|
+
|
|
3102
3509
|
// src/plugin.ts
|
|
3103
3510
|
function getExistingMigrationTables(migrationsDir) {
|
|
3104
3511
|
const existingTables = /* @__PURE__ */ new Set();
|
|
@@ -3207,10 +3614,34 @@ var LARAVEL_CONFIG_SCHEMA = {
|
|
|
3207
3614
|
description: "Generate Laravel FormRequest classes for validation",
|
|
3208
3615
|
default: false,
|
|
3209
3616
|
group: "options"
|
|
3617
|
+
},
|
|
3618
|
+
{
|
|
3619
|
+
key: "resourcesPath",
|
|
3620
|
+
type: "path",
|
|
3621
|
+
label: "Resources Path",
|
|
3622
|
+
description: "Directory for user-editable API Resource files",
|
|
3623
|
+
default: "app/Http/Resources",
|
|
3624
|
+
group: "output"
|
|
3625
|
+
},
|
|
3626
|
+
{
|
|
3627
|
+
key: "baseResourcesPath",
|
|
3628
|
+
type: "path",
|
|
3629
|
+
label: "Base Resources Path",
|
|
3630
|
+
description: "Directory for auto-generated base API Resource files",
|
|
3631
|
+
default: "app/Http/Resources/OmnifyBase",
|
|
3632
|
+
group: "output"
|
|
3633
|
+
},
|
|
3634
|
+
{
|
|
3635
|
+
key: "generateResources",
|
|
3636
|
+
type: "boolean",
|
|
3637
|
+
label: "Generate Resources",
|
|
3638
|
+
description: "Generate Laravel API Resource classes",
|
|
3639
|
+
default: false,
|
|
3640
|
+
group: "options"
|
|
3210
3641
|
}
|
|
3211
3642
|
]
|
|
3212
3643
|
};
|
|
3213
|
-
function
|
|
3644
|
+
function resolveOptions5(options) {
|
|
3214
3645
|
return {
|
|
3215
3646
|
migrationsPath: options?.migrationsPath ?? "database/migrations/omnify",
|
|
3216
3647
|
modelsPath: options?.modelsPath ?? "app/Models",
|
|
@@ -3228,11 +3659,16 @@ function resolveOptions4(options) {
|
|
|
3228
3659
|
baseRequestsPath: options?.baseRequestsPath ?? "app/Http/Requests/OmnifyBase",
|
|
3229
3660
|
requestNamespace: options?.requestNamespace ?? "App\\Http\\Requests",
|
|
3230
3661
|
baseRequestNamespace: options?.baseRequestNamespace ?? "App\\Http\\Requests\\OmnifyBase",
|
|
3231
|
-
generateRequests: options?.generateRequests ?? false
|
|
3662
|
+
generateRequests: options?.generateRequests ?? false,
|
|
3663
|
+
resourcesPath: options?.resourcesPath ?? "app/Http/Resources",
|
|
3664
|
+
baseResourcesPath: options?.baseResourcesPath ?? "app/Http/Resources/OmnifyBase",
|
|
3665
|
+
resourceNamespace: options?.resourceNamespace ?? "App\\Http\\Resources",
|
|
3666
|
+
baseResourceNamespace: options?.baseResourceNamespace ?? "App\\Http\\Resources\\OmnifyBase",
|
|
3667
|
+
generateResources: options?.generateResources ?? false
|
|
3232
3668
|
};
|
|
3233
3669
|
}
|
|
3234
3670
|
function laravelPlugin(options) {
|
|
3235
|
-
const resolved =
|
|
3671
|
+
const resolved = resolveOptions5(options);
|
|
3236
3672
|
const migrationGenerator = {
|
|
3237
3673
|
name: "laravel-migrations",
|
|
3238
3674
|
description: "Generate Laravel migration files",
|
|
@@ -3388,7 +3824,8 @@ function laravelPlugin(options) {
|
|
|
3388
3824
|
const factoryOptions = {
|
|
3389
3825
|
modelNamespace: resolved.modelNamespace,
|
|
3390
3826
|
factoryPath: resolved.factoriesPath,
|
|
3391
|
-
fakerLocale: resolved.fakerLocale
|
|
3827
|
+
fakerLocale: resolved.fakerLocale,
|
|
3828
|
+
customTypes: ctx.customTypes
|
|
3392
3829
|
};
|
|
3393
3830
|
const factories = generateFactories(ctx.schemas, factoryOptions);
|
|
3394
3831
|
return factories.map((factory) => ({
|
|
@@ -3431,6 +3868,32 @@ function laravelPlugin(options) {
|
|
|
3431
3868
|
}));
|
|
3432
3869
|
}
|
|
3433
3870
|
};
|
|
3871
|
+
const resourceGenerator = {
|
|
3872
|
+
name: "laravel-resources",
|
|
3873
|
+
description: "Generate Laravel API Resource classes",
|
|
3874
|
+
generate: async (ctx) => {
|
|
3875
|
+
const resourceOptions = {
|
|
3876
|
+
resourceNamespace: resolved.resourceNamespace,
|
|
3877
|
+
baseResourceNamespace: resolved.baseResourceNamespace,
|
|
3878
|
+
resourcePath: resolved.resourcesPath,
|
|
3879
|
+
baseResourcePath: resolved.baseResourcesPath,
|
|
3880
|
+
customTypes: ctx.customTypes
|
|
3881
|
+
};
|
|
3882
|
+
const resources = generateResources(ctx.schemas, resourceOptions);
|
|
3883
|
+
return resources.map((resource) => ({
|
|
3884
|
+
path: getResourcePath(resource),
|
|
3885
|
+
content: resource.content,
|
|
3886
|
+
type: "other",
|
|
3887
|
+
// Skip writing user resources if they already exist
|
|
3888
|
+
skipIfExists: !resource.overwrite,
|
|
3889
|
+
metadata: {
|
|
3890
|
+
resourceType: resource.type,
|
|
3891
|
+
schemaName: resource.schemaName,
|
|
3892
|
+
module: resource.module
|
|
3893
|
+
}
|
|
3894
|
+
}));
|
|
3895
|
+
}
|
|
3896
|
+
};
|
|
3434
3897
|
const generators = [migrationGenerator];
|
|
3435
3898
|
if (resolved.generateModels) {
|
|
3436
3899
|
generators.push(modelGenerator);
|
|
@@ -3441,6 +3904,9 @@ function laravelPlugin(options) {
|
|
|
3441
3904
|
if (resolved.generateRequests) {
|
|
3442
3905
|
generators.push(requestGenerator);
|
|
3443
3906
|
}
|
|
3907
|
+
if (resolved.generateResources) {
|
|
3908
|
+
generators.push(resourceGenerator);
|
|
3909
|
+
}
|
|
3444
3910
|
return {
|
|
3445
3911
|
name: "@famgia/omnify-laravel",
|
|
3446
3912
|
version: "0.0.14",
|