@omnifyjp/ts 5.8.40 → 5.9.1
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/generator.js +33 -5
- package/dist/php/model-generator.js +21 -6
- package/dist/php/request-generator.js +5 -2
- package/dist/php/resource-generator.d.ts +7 -4
- package/dist/php/resource-generator.js +8 -4
- package/dist/php/service-provider-generator.js +9 -2
- package/dist/php/translation-model-generator.js +15 -3
- package/package.json +1 -1
package/dist/generator.js
CHANGED
|
@@ -333,15 +333,43 @@ function generateI18nFile(options) {
|
|
|
333
333
|
/** Generate index.ts re-exports. */
|
|
334
334
|
function generateIndexFile(schemas, schemaEnums, pluginEnums, typeAliases, hasFiles = false) {
|
|
335
335
|
const parts = [generateBaseHeader()];
|
|
336
|
-
// Common types
|
|
336
|
+
// Common types.
|
|
337
|
+
// A generator-owned common type can collide with a user model schema of the
|
|
338
|
+
// same name (e.g. a `Locale` entity vs the `Locale` locale-code union). The
|
|
339
|
+
// model is the user's explicit schema and stays canonical (keeps the bare
|
|
340
|
+
// name in the model section below); the common type is re-exported under an
|
|
341
|
+
// alias here so the barrel never emits a duplicate identifier (TS2300).
|
|
337
342
|
parts.push(`// Common Types\n`);
|
|
343
|
+
const modelNames = new Set(Object.values(schemas)
|
|
344
|
+
.filter((s) => s.kind !== 'enum' && s.options?.hidden !== true)
|
|
345
|
+
.map((s) => s.name));
|
|
346
|
+
// Preferred, human-readable aliases for the known common types. Any other
|
|
347
|
+
// collision falls back to a `Common<Name>` alias.
|
|
348
|
+
const COMMON_TYPE_ALIASES = {
|
|
349
|
+
Locale: 'LocaleCode',
|
|
350
|
+
LocaleMap: 'LocaleStringMap',
|
|
351
|
+
DateTimeString: 'CommonDateTimeString',
|
|
352
|
+
DateString: 'CommonDateString',
|
|
353
|
+
OmnifyFile: 'OmnifyFileType',
|
|
354
|
+
};
|
|
355
|
+
const commonTypeNames = hasFiles
|
|
356
|
+
? ['LocaleMap', 'Locale', 'DateTimeString', 'DateString', 'OmnifyFile']
|
|
357
|
+
: ['LocaleMap', 'Locale', 'DateTimeString', 'DateString'];
|
|
358
|
+
const commonTypeExports = commonTypeNames.map((name) => {
|
|
359
|
+
if (!modelNames.has(name)) {
|
|
360
|
+
return name;
|
|
361
|
+
}
|
|
362
|
+
const alias = COMMON_TYPE_ALIASES[name] ?? `Common${name}`;
|
|
363
|
+
// eslint-disable-next-line no-console
|
|
364
|
+
console.warn(`[omnify-ts] Common type "${name}" collides with model schema "${name}"; ` +
|
|
365
|
+
`re-exporting the common type from index.ts as "${alias}". ` +
|
|
366
|
+
`The "${name}" model keeps the canonical name.`);
|
|
367
|
+
return `${name} as ${alias}`;
|
|
368
|
+
});
|
|
369
|
+
parts.push(`export type { ${commonTypeExports.join(', ')} } from './common';\n`);
|
|
338
370
|
if (hasFiles) {
|
|
339
|
-
parts.push(`export type { LocaleMap, Locale, DateTimeString, DateString, OmnifyFile } from './common';\n`);
|
|
340
371
|
parts.push(`export { OmnifyFileSchema } from './common';\n`);
|
|
341
372
|
}
|
|
342
|
-
else {
|
|
343
|
-
parts.push(`export type { LocaleMap, Locale, DateTimeString, DateString } from './common';\n`);
|
|
344
|
-
}
|
|
345
373
|
// I18n
|
|
346
374
|
parts.push(`// i18n (Internationalization)\n`);
|
|
347
375
|
parts.push(`export {\n`);
|
|
@@ -77,6 +77,19 @@ function generateBaseModel(name, schema, reader, config) {
|
|
|
77
77
|
const expandedProperties = reader.getExpandedProperties(name);
|
|
78
78
|
const propertyOrder = reader.getPropertyOrder(name);
|
|
79
79
|
const tableName = reader.getTableName(name);
|
|
80
|
+
// Multi-database routing: a schema may declare a top-level `connection:`
|
|
81
|
+
// (matching an omnify.yaml connections key + a Laravel connection). Emit the
|
|
82
|
+
// matching `$connection` so the model resolves to the right database. The
|
|
83
|
+
// implicit `default` connection is left unset so Laravel uses its default.
|
|
84
|
+
const connectionName = schema['connection'];
|
|
85
|
+
const connectionSection = connectionName && connectionName !== 'default'
|
|
86
|
+
? `
|
|
87
|
+
/**
|
|
88
|
+
* The database connection for the model.
|
|
89
|
+
*/
|
|
90
|
+
protected $connection = '${connectionName}';
|
|
91
|
+
`
|
|
92
|
+
: '';
|
|
80
93
|
const isAuthenticatable = options['authenticatable'] ?? false;
|
|
81
94
|
const hasSoftDelete = options.softDelete ?? false;
|
|
82
95
|
const hasTimestamps = options.timestamps ?? false;
|
|
@@ -172,7 +185,7 @@ ${imports}
|
|
|
172
185
|
${docProperties} */
|
|
173
186
|
class ${modelName}BaseModel extends ${baseClass}${implementsClause}
|
|
174
187
|
{
|
|
175
|
-
${traits} /**
|
|
188
|
+
${traits}${connectionSection} /**
|
|
176
189
|
* The table associated with the model.
|
|
177
190
|
*/
|
|
178
191
|
protected $table = '${tableName}';
|
|
@@ -373,12 +386,14 @@ function buildImports(baseNamespace, modelName, hasSoftDelete, isAuthenticatable
|
|
|
373
386
|
}
|
|
374
387
|
}
|
|
375
388
|
if (hasAuditLog) {
|
|
376
|
-
// HasOmnifyAuditLog is a
|
|
377
|
-
// audit-trait-generator.ts
|
|
378
|
-
//
|
|
379
|
-
//
|
|
389
|
+
// HasOmnifyAuditLog is a GLOBAL Omnify trait emitted by
|
|
390
|
+
// audit-trait-generator.ts at `config.models.baseNamespace\Traits`
|
|
391
|
+
// (e.g. App\Models\Omnify\Base\Traits). The import here must resolve to
|
|
392
|
+
// that SAME global namespace — using the per-model (group) `baseNamespace`
|
|
393
|
+
// (e.g. ...\Base\Logistics) yields `Base\Logistics\Traits\HasOmnifyAuditLog`
|
|
394
|
+
// which does not exist → "Trait not found" fatal on every model load.
|
|
380
395
|
const auditTraitsNs = config
|
|
381
|
-
? resolveGlobalTraitNamespace(config, baseNamespace + '\\Traits')
|
|
396
|
+
? resolveGlobalTraitNamespace(config, config.models.baseNamespace + '\\Traits')
|
|
382
397
|
: (traitsNamespace || baseNamespace + '\\Traits');
|
|
383
398
|
lines.push(`use ${auditTraitsNs}\\HasOmnifyAuditLog;`);
|
|
384
399
|
}
|
|
@@ -195,7 +195,7 @@ namespace ${baseNamespace};
|
|
|
195
195
|
use Illuminate\\Foundation\\Http\\FormRequest;${ruleImport}
|
|
196
196
|
use ${localesClass};
|
|
197
197
|
|
|
198
|
-
|
|
198
|
+
class ${modelName}${action}RequestBase extends FormRequest
|
|
199
199
|
{
|
|
200
200
|
/**
|
|
201
201
|
* Determine if the user is authorized to make this request.
|
|
@@ -277,7 +277,10 @@ ${attributeKeysList}
|
|
|
277
277
|
const nested = nestByGroup({ path: raw.path, namespace: '' }, schema.group);
|
|
278
278
|
baseDescriptor = { className: raw.className, path: nested.path };
|
|
279
279
|
}
|
|
280
|
-
|
|
280
|
+
// Issue #114: the request base is the class controllers inject directly
|
|
281
|
+
// (#101) — so it must be CONCRETE, not abstract (an abstract FormRequest is
|
|
282
|
+
// not container-resolvable → BindingResolutionException / HTTP 500).
|
|
283
|
+
const finalContent = content.replace(new RegExp(`class ${modelName}${action}RequestBase\\b`, 'g'), `class ${baseDescriptor.className}`);
|
|
281
284
|
return baseFile(`${baseDescriptor.path}/${baseDescriptor.className}.php`, finalContent);
|
|
282
285
|
}
|
|
283
286
|
function generateUserRequest(name, schema, config, action) {
|
|
@@ -5,9 +5,12 @@ import { SchemaReader } from './schema-reader.js';
|
|
|
5
5
|
import type { GeneratedFile, PhpConfig } from './types.js';
|
|
6
6
|
/** Generate Resource classes for all project-owned visible object schemas.
|
|
7
7
|
*
|
|
8
|
-
* Issue #101 v5.8.23
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* Issue #101 v5.8.23 emitted ONLY the base — but child resources embed a
|
|
9
|
+
* parent relation via `new \App\Http\Resources\<Parent>Resource(...)` (the
|
|
10
|
+
* editable sibling). With the sibling gone, any loaded relation fatals with a
|
|
11
|
+
* "class not found" Error (issue #114). So the editable sibling is re-emitted
|
|
12
|
+
* as a create-if-missing user file (`overwrite: false`): written once, never
|
|
13
|
+
* regenerated (so it is not the scaffolding noise #101 removed), and the
|
|
14
|
+
* cross-resource reference always resolves.
|
|
12
15
|
*/
|
|
13
16
|
export declare function generateResources(reader: SchemaReader, config: PhpConfig): GeneratedFile[];
|
|
@@ -6,10 +6,13 @@ import { isHiddenByDefault, toResourceExpression } from './type-mapper.js';
|
|
|
6
6
|
import { baseFile, userFile, resolveModularBasePath, resolveModularBaseNamespace, resolveBaseClass, resolveEditableClass, nestByGroup, nestEditableByGroup } from './types.js';
|
|
7
7
|
/** Generate Resource classes for all project-owned visible object schemas.
|
|
8
8
|
*
|
|
9
|
-
* Issue #101 v5.8.23
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* Issue #101 v5.8.23 emitted ONLY the base — but child resources embed a
|
|
10
|
+
* parent relation via `new \App\Http\Resources\<Parent>Resource(...)` (the
|
|
11
|
+
* editable sibling). With the sibling gone, any loaded relation fatals with a
|
|
12
|
+
* "class not found" Error (issue #114). So the editable sibling is re-emitted
|
|
13
|
+
* as a create-if-missing user file (`overwrite: false`): written once, never
|
|
14
|
+
* regenerated (so it is not the scaffolding noise #101 removed), and the
|
|
15
|
+
* cross-resource reference always resolves.
|
|
13
16
|
*/
|
|
14
17
|
export function generateResources(reader, config) {
|
|
15
18
|
const files = [];
|
|
@@ -17,6 +20,7 @@ export function generateResources(reader, config) {
|
|
|
17
20
|
if (schema.kind === 'extend')
|
|
18
21
|
continue;
|
|
19
22
|
files.push(generateBaseResource(name, schema, reader, config));
|
|
23
|
+
files.push(generateUserResource(name, schema, config));
|
|
20
24
|
}
|
|
21
25
|
return files;
|
|
22
26
|
}
|
|
@@ -89,8 +89,15 @@ class OmnifyServiceProvider extends ServiceProvider
|
|
|
89
89
|
*/
|
|
90
90
|
public function boot(): void
|
|
91
91
|
{
|
|
92
|
-
// Load Omnify migrations
|
|
93
|
-
|
|
92
|
+
// Load Omnify migrations: the default-connection directory plus every
|
|
93
|
+
// per-connection subdirectory (multi-database setups route each domain's
|
|
94
|
+
// migrations into its own subfolder; those migrations target their
|
|
95
|
+
// connection via Schema::connection(), so a single migrate run suffices).
|
|
96
|
+
$omnifyMigrations = database_path('migrations/omnify');
|
|
97
|
+
$this->loadMigrationsFrom($omnifyMigrations);
|
|
98
|
+
foreach (glob($omnifyMigrations.'/*', GLOB_ONLYDIR) as $connectionDir) {
|
|
99
|
+
$this->loadMigrationsFrom($connectionDir);
|
|
100
|
+
}
|
|
94
101
|
${packageMigrationsBlock}
|
|
95
102
|
// Register morph map for polymorphic relationships
|
|
96
103
|
Relation::enforceMorphMap([
|
|
@@ -17,7 +17,9 @@ export function generateTranslationModels(reader, config) {
|
|
|
17
17
|
const translatableFields = reader.getTranslatableFieldDetails(name);
|
|
18
18
|
if (translatableFields.length === 0)
|
|
19
19
|
continue;
|
|
20
|
-
|
|
20
|
+
// A translation table co-locates with its parent — same connection/database.
|
|
21
|
+
const connectionName = reader.getSchema(name)?.['connection'];
|
|
22
|
+
files.push(generateTranslationBaseModel(name, translatableFields, enforceLanguageFk, config, connectionName));
|
|
21
23
|
files.push(generateTranslationUserModel(name, config));
|
|
22
24
|
}
|
|
23
25
|
return files;
|
|
@@ -53,9 +55,19 @@ function castFor(type) {
|
|
|
53
55
|
return undefined;
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
|
-
function generateTranslationBaseModel(name, translatableFields, enforceLanguageFk, config) {
|
|
58
|
+
function generateTranslationBaseModel(name, translatableFields, enforceLanguageFk, config, connectionName) {
|
|
57
59
|
const modelName = toPascalCase(name);
|
|
58
60
|
const modelSnake = toSnakeCase(name);
|
|
61
|
+
// Multi-database routing: follow the parent schema's connection so the
|
|
62
|
+
// `*_translations` table resolves to the same database as its parent.
|
|
63
|
+
const connectionSection = connectionName && connectionName !== 'default'
|
|
64
|
+
? `
|
|
65
|
+
/**
|
|
66
|
+
* The database connection for the model.
|
|
67
|
+
*/
|
|
68
|
+
protected $connection = '${connectionName}';
|
|
69
|
+
`
|
|
70
|
+
: '';
|
|
59
71
|
// Issue #98 v5.8.2: consolidate every Translation model under one
|
|
60
72
|
// dedicated `Translation/` subfolder + sub-namespace. Reporter's
|
|
61
73
|
// rationale: 39 translation models flat at the top of `Models/`
|
|
@@ -123,7 +135,7 @@ use Illuminate\\Database\\Eloquent\\Model;
|
|
|
123
135
|
*/
|
|
124
136
|
class ${baseClassName} extends Model
|
|
125
137
|
{
|
|
126
|
-
/**
|
|
138
|
+
${connectionSection} /**
|
|
127
139
|
* The table associated with the model.
|
|
128
140
|
*/
|
|
129
141
|
protected $table = '${tableName}';
|