@omnifyjp/ts 5.4.0 → 5.6.0

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.
@@ -2,7 +2,7 @@
2
2
  * Generates base + editable controller classes for schemas with `options.api`.
3
3
  */
4
4
  import { toPascalCase } from './naming-helper.js';
5
- import { baseFile, userFile, resolveModularBasePath, resolveModularBaseNamespace } from './types.js';
5
+ import { baseFile, userFile, resolveModularBasePath, resolveModularBaseNamespace, resolveBaseClass, resolveEditableClass } from './types.js';
6
6
  import { buildControllerMethodAttributes, openApiControllerImports } from './openapi-generator.js';
7
7
  const DEFAULT_ACTIONS = ['index', 'store', 'show', 'update', 'destroy'];
8
8
  /** Generate controller classes for all schemas with api config. */
@@ -157,18 +157,36 @@ abstract class ${modelName}ControllerBase extends Controller
157
157
  ${methods.join('\n')}
158
158
  }
159
159
  `;
160
- return baseFile(resolveModularBasePath(config, name, 'Controllers', `${modelName}ControllerBase.php`, config.controllers.basePath), content);
160
+ // Issue #96: legacy honors flatBase (drops ControllerBase suffix + OmnifyBase/ subfolder).
161
+ const baseDescriptor = config.structure === 'modular'
162
+ ? {
163
+ className: `${modelName}ControllerBase`,
164
+ path: resolveModularBasePath(config, name, 'Controllers', '', config.controllers.basePath).replace(/\/$/, ''),
165
+ }
166
+ : resolveBaseClass(config.controllers, `${modelName}Controller`, 'Base');
167
+ const finalContent = content.replace(new RegExp(`abstract class ${modelName}ControllerBase\\b`, 'g'), `abstract class ${baseDescriptor.className}`);
168
+ return baseFile(`${baseDescriptor.path}/${baseDescriptor.className}.php`, finalContent);
161
169
  }
162
170
  function generateUserController(name, schema, config) {
163
171
  const modelName = toPascalCase(name);
164
172
  const group = schema.group ? toPascalCase(schema.group) : null;
165
- const baseNs = resolveModularBaseNamespace(config, name, 'Controllers', config.controllers.baseNamespace);
173
+ // Issue #96: editable stub may live at userEditablePath; extends-clause adapts to flatBase.
174
+ // Note: controllers traditionally nest under `Api/V1/<Group>/` regardless of userEditablePath.
175
+ const baseDescriptor = config.structure === 'modular'
176
+ ? {
177
+ className: `${modelName}ControllerBase`,
178
+ fqn: `${resolveModularBaseNamespace(config, name, 'Controllers', config.controllers.baseNamespace)}\\${modelName}ControllerBase`,
179
+ }
180
+ : resolveBaseClass(config.controllers, `${modelName}Controller`, 'Base');
181
+ const editable = config.structure === 'modular'
182
+ ? { className: `${modelName}Controller`, fileName: `${modelName}Controller.php`, namespace: config.controllers.namespace, path: config.controllers.path }
183
+ : resolveEditableClass(config.controllers, modelName, 'Controller');
166
184
  const userNs = group
167
- ? `${config.controllers.namespace}\\Api\\V1\\${group}`
168
- : `${config.controllers.namespace}\\Api\\V1`;
185
+ ? `${editable.namespace}\\Api\\V1\\${group}`
186
+ : `${editable.namespace}\\Api\\V1`;
169
187
  const userPath = group
170
- ? `${config.controllers.path}/Api/V1/${group}`
171
- : `${config.controllers.path}/Api/V1`;
188
+ ? `${editable.path}/Api/V1/${group}`
189
+ : `${editable.path}/Api/V1`;
172
190
  const content = `<?php
173
191
 
174
192
  /**
@@ -179,12 +197,12 @@ function generateUserController(name, schema, config) {
179
197
 
180
198
  namespace ${userNs};
181
199
 
182
- use ${baseNs}\\${modelName}ControllerBase;
200
+ use ${baseDescriptor.fqn};
183
201
 
184
- class ${modelName}Controller extends ${modelName}ControllerBase
202
+ class ${editable.className} extends ${baseDescriptor.className}
185
203
  {
186
204
  //
187
205
  }
188
206
  `;
189
- return userFile(`${userPath}/${modelName}Controller.php`, content);
207
+ return userFile(`${userPath}/${editable.fileName}`, content);
190
208
  }
@@ -4,7 +4,7 @@
4
4
  import { toPascalCase, toSnakeCase, toCamelCase, pluralize } from './naming-helper.js';
5
5
  import { toCast, toPhpDocType, isHiddenByDefault } from './type-mapper.js';
6
6
  import { buildRelation } from './relation-builder.js';
7
- import { baseFile, userFile, resolveModularBasePath, resolveModularBaseNamespace, resolveSharedBaseNamespace, resolveGlobalTraitNamespace, resolveGlobalEnumNamespace, } from './types.js';
7
+ import { baseFile, userFile, resolveModularBasePath, resolveModularBaseNamespace, resolveSharedBaseNamespace, resolveGlobalTraitNamespace, resolveGlobalEnumNamespace, resolveBaseClass, resolveEditableClass, } from './types.js';
8
8
  import { enumClassName } from './enum-generator.js';
9
9
  /** Generate base model and user model for all project-owned object schemas,
10
10
  * plus user models for package schemas (extending the package model). */
@@ -34,7 +34,22 @@ function generateForSchema(name, schema, reader, config) {
34
34
  }
35
35
  function generateBaseModel(name, schema, reader, config) {
36
36
  const modelName = toPascalCase(name);
37
- const baseNamespace = resolveModularBaseNamespace(config, name, 'Models', config.models.baseNamespace);
37
+ // Issue #96: in legacy structure, honor flatBase to drop the
38
+ // `BaseModel` suffix + Base/ subfolder. In modular structure, keep the
39
+ // existing per-module layout (modular's per-schema folder already
40
+ // isolates base from editable). `baseDescriptor` is the resolved
41
+ // {className, fqn, path} for the base class — `baseClass` (further
42
+ // below) is the PARENT class string (BaseModel / Authenticatable).
43
+ const baseDescriptor = config.structure === 'modular'
44
+ ? {
45
+ className: `${modelName}BaseModel`,
46
+ fqn: `${resolveModularBaseNamespace(config, name, 'Models', config.models.baseNamespace)}\\${modelName}BaseModel`,
47
+ path: resolveModularBasePath(config, name, 'Models', '', config.models.basePath).replace(/\/$/, ''),
48
+ }
49
+ : resolveBaseClass(config.models, modelName, 'BaseModel');
50
+ const baseNamespace = config.structure === 'modular'
51
+ ? resolveModularBaseNamespace(config, name, 'Models', config.models.baseNamespace)
52
+ : baseDescriptor.fqn.substring(0, baseDescriptor.fqn.lastIndexOf('\\'));
38
53
  const localesNamespace = resolveModularBaseNamespace(config, name, 'Locales', config.models.baseNamespace + '\\Locales');
39
54
  // Issue #33: HasLocalizedDisplayName is a global Omnify trait, not a per-shared module file.
40
55
  const traitsNamespace = resolveGlobalTraitNamespace(config, config.models.baseNamespace + '\\Traits');
@@ -183,16 +198,31 @@ ${casts} ];
183
198
  ${auditLogProperties}${relations}${accessors}${fileAccessors}${auditSection}${nestedSetMethod}
184
199
  }
185
200
  `;
186
- return baseFile(resolveModularBasePath(config, name, 'Models', `${modelName}BaseModel.php`, config.models.basePath), content);
201
+ // Replace placeholder class name so the file matches resolved className
202
+ // (issue #96: flatBase emits `<Schema>` instead of `<Schema>BaseModel`).
203
+ const finalContent = content.replace(new RegExp(`class ${modelName}BaseModel `, 'g'), `class ${baseDescriptor.className} `).replace(new RegExp(`\\* ${modelName}BaseModel`, 'g'), `* ${baseDescriptor.className}`);
204
+ // Modular preserves per-module path; legacy honors flatBase via baseDescriptor.path.
205
+ const filePath = config.structure === 'modular'
206
+ ? resolveModularBasePath(config, name, 'Models', `${modelName}BaseModel.php`, config.models.basePath)
207
+ : `${baseDescriptor.path}/${baseDescriptor.className}.php`;
208
+ return baseFile(filePath, finalContent);
187
209
  }
188
210
  function generateUserModel(name, config, hasNestedSet = false) {
189
211
  const modelName = toPascalCase(name);
190
- const modelNamespace = config.models.namespace;
191
- const baseNamespace = resolveModularBaseNamespace(config, name, 'Models', config.models.baseNamespace);
212
+ // Issue #96: editable stub may live at a different path/namespace
213
+ // than the base (e.g. `app/Models/<Name>.php` while base is at
214
+ // `app/Omnify/Models/<Name>.php`). resolveEditableClass +
215
+ // resolveBaseClass keep the extends-clause + use-import in sync.
216
+ const editable = config.structure === 'modular'
217
+ ? { fileName: `${modelName}.php`, namespace: config.models.namespace, path: config.models.path, fqn: `${config.models.namespace}\\${modelName}`, className: modelName }
218
+ : resolveEditableClass(config.models, modelName);
219
+ const base = config.structure === 'modular'
220
+ ? { className: `${modelName}BaseModel`, fqn: `${resolveModularBaseNamespace(config, name, 'Models', config.models.baseNamespace)}\\${modelName}BaseModel` }
221
+ : resolveBaseClass(config.models, modelName, 'BaseModel');
192
222
  const factoryNamespace = config.factories.namespace;
193
223
  const nestedSetNamespace = config.nestedset.namespace;
194
224
  const imports = [
195
- `use ${baseNamespace}\\${modelName}BaseModel;`,
225
+ `use ${base.fqn};`,
196
226
  `use ${factoryNamespace}\\${modelName}Factory;`,
197
227
  `use Illuminate\\Database\\Eloquent\\Factories\\HasFactory;`,
198
228
  ];
@@ -211,14 +241,14 @@ function generateUserModel(name, config, hasNestedSet = false) {
211
241
  * SAFE TO EDIT - This file is never overwritten by Omnify.
212
242
  */
213
243
 
214
- namespace ${modelNamespace};
244
+ namespace ${editable.namespace};
215
245
 
216
246
  ${imports.join('\n')}
217
247
 
218
248
  /**
219
249
  * ${modelName} — add project-specific model logic here.
220
250
  */
221
- class ${modelName} extends ${modelName}BaseModel
251
+ class ${modelName} extends ${base.className}
222
252
  {
223
253
  ${traits.join('\n')}
224
254
 
@@ -233,7 +263,7 @@ ${traits.join('\n')}
233
263
  //
234
264
  }
235
265
  `;
236
- return userFile(`${config.models.path}/${modelName}.php`, content);
266
+ return userFile(`${editable.path}/${editable.fileName}`, content);
237
267
  }
238
268
  function buildImports(baseNamespace, modelName, hasSoftDelete, isAuthenticatable, hasTranslatable, properties, needsUuidTrait = false, needsUlidTrait = false, hasNestedSet = false, nestedSetNamespace = 'Aimeos\\Nestedset', hasFiles = false, modelNamespace = '', localesNamespace = '', traitsNamespace = '', sharedModelsNamespace = '', config, hasAuditLog = false) {
239
269
  const lines = [];
@@ -5,7 +5,7 @@
5
5
  * Only generates for schemas that have `policies` defined.
6
6
  */
7
7
  import { toPascalCase, toSnakeCase, toCamelCase } from './naming-helper.js';
8
- import { baseFile, userFile, resolveModularBasePath, resolveModularBaseNamespace } from './types.js';
8
+ import { baseFile, userFile, resolveModularBasePath, resolveModularBaseNamespace, resolveBaseClass, resolveEditableClass } from './types.js';
9
9
  // ============================================================================
10
10
  // Action mapping: Omnify → Laravel
11
11
  // ============================================================================
@@ -89,17 +89,33 @@ class ${modelName}PolicyBase
89
89
  ${methods.join('\n')}${cidrHelper}
90
90
  }
91
91
  `;
92
- return baseFile(resolveModularBasePath(config, name, 'Policies', `${modelName}PolicyBase.php`, config.policies.basePath), content);
92
+ // Issue #96: legacy honors flatBase (drops PolicyBase suffix + Base/ subfolder).
93
+ const baseDescriptor = config.structure === 'modular'
94
+ ? {
95
+ className: `${modelName}PolicyBase`,
96
+ path: resolveModularBasePath(config, name, 'Policies', '', config.policies.basePath).replace(/\/$/, ''),
97
+ }
98
+ : resolveBaseClass(config.policies, `${modelName}Policy`, 'Base');
99
+ const finalContent = content.replace(new RegExp(`class ${modelName}PolicyBase\\b`, 'g'), `class ${baseDescriptor.className}`);
100
+ return baseFile(`${baseDescriptor.path}/${baseDescriptor.className}.php`, finalContent);
93
101
  }
94
102
  function generateUserPolicyClass(name, config) {
95
103
  const modelName = toPascalCase(name);
96
- const policyNamespace = config.policies.namespace;
97
- const baseNamespace = resolveModularBaseNamespace(config, name, 'Policies', config.policies.baseNamespace);
104
+ // Issue #96: editable stub via resolveEditableClass + extends adapts to flatBase.
105
+ const baseDescriptor = config.structure === 'modular'
106
+ ? {
107
+ className: `${modelName}PolicyBase`,
108
+ fqn: `${resolveModularBaseNamespace(config, name, 'Policies', config.policies.baseNamespace)}\\${modelName}PolicyBase`,
109
+ }
110
+ : resolveBaseClass(config.policies, `${modelName}Policy`, 'Base');
111
+ const editable = config.structure === 'modular'
112
+ ? { className: `${modelName}Policy`, fileName: `${modelName}Policy.php`, namespace: config.policies.namespace, path: config.policies.path }
113
+ : resolveEditableClass(config.policies, modelName, 'Policy');
98
114
  const content = `<?php
99
115
 
100
- namespace ${policyNamespace};
116
+ namespace ${editable.namespace};
101
117
 
102
- use ${baseNamespace}\\${modelName}PolicyBase;
118
+ use ${baseDescriptor.fqn};
103
119
 
104
120
  /**
105
121
  * ${modelName} Policy
@@ -107,12 +123,12 @@ use ${baseNamespace}\\${modelName}PolicyBase;
107
123
  * This file is generated once and can be customized.
108
124
  * Add your custom authorization logic here.
109
125
  */
110
- class ${modelName}Policy extends ${modelName}PolicyBase
126
+ class ${editable.className} extends ${baseDescriptor.className}
111
127
  {
112
128
  // Add your custom policy methods here
113
129
  }
114
130
  `;
115
- return userFile(`${config.policies.path}/${modelName}Policy.php`, content);
131
+ return userFile(`${editable.path}/${editable.fileName}`, content);
116
132
  }
117
133
  // ============================================================================
118
134
  // Method body generation
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { toPascalCase, toSnakeCase, toCamelCase } from './naming-helper.js';
5
5
  import { toStoreRules, toUpdateRules, formatRules, hasRuleObject } from './type-mapper.js';
6
- import { baseFile, userFile, resolveModularBasePath, resolveModularBaseNamespace } from './types.js';
6
+ import { baseFile, userFile, resolveModularBasePath, resolveModularBaseNamespace, resolveBaseClass, resolveEditableClass } from './types.js';
7
7
  /**
8
8
  * Resolve the Laravel validation rule type ('integer', 'uuid', or 'string') for
9
9
  * a foreign key column based on the target schema's primary key type.
@@ -257,12 +257,30 @@ ${attributeKeysList}
257
257
  }
258
258
  }
259
259
  `;
260
- return baseFile(resolveModularBasePath(config, name, 'Requests', `${modelName}${action}RequestBase.php`, config.requests.basePath), content);
260
+ // Issue #96: legacy honors flatBase. Suffix is `${action}RequestBase`
261
+ // when not flat (e.g. BannerStoreRequestBase), bare `${action}Request`
262
+ // when flat (BannerStoreRequest is the base; user-editable extends it).
263
+ const baseDescriptor = config.structure === 'modular'
264
+ ? {
265
+ className: `${modelName}${action}RequestBase`,
266
+ path: resolveModularBasePath(config, name, 'Requests', '', config.requests.basePath).replace(/\/$/, ''),
267
+ }
268
+ : resolveBaseClass(config.requests, `${modelName}${action}Request`, 'Base');
269
+ const finalContent = content.replace(new RegExp(`class ${modelName}${action}RequestBase\\b`, 'g'), `class ${baseDescriptor.className}`).replace(new RegExp(`abstract class ${modelName}${action}RequestBase\\b`, 'g'), `abstract class ${baseDescriptor.className}`);
270
+ return baseFile(`${baseDescriptor.path}/${baseDescriptor.className}.php`, finalContent);
261
271
  }
262
272
  function generateUserRequest(name, config, action) {
263
273
  const modelName = toPascalCase(name);
264
- const requestNamespace = config.requests.namespace;
265
- const baseNamespace = resolveModularBaseNamespace(config, name, 'Requests', config.requests.baseNamespace);
274
+ // Issue #96: editable stub may live at userEditablePath; extends-clause adapts to flatBase.
275
+ const baseDescriptor = config.structure === 'modular'
276
+ ? {
277
+ className: `${modelName}${action}RequestBase`,
278
+ fqn: `${resolveModularBaseNamespace(config, name, 'Requests', config.requests.baseNamespace)}\\${modelName}${action}RequestBase`,
279
+ }
280
+ : resolveBaseClass(config.requests, `${modelName}${action}Request`, 'Base');
281
+ const editable = config.structure === 'modular'
282
+ ? { className: `${modelName}${action}Request`, fileName: `${modelName}${action}Request.php`, namespace: config.requests.namespace, path: config.requests.path }
283
+ : resolveEditableClass(config.requests, modelName, `${action}Request`);
266
284
  const content = `<?php
267
285
 
268
286
  /**
@@ -271,9 +289,9 @@ function generateUserRequest(name, config, action) {
271
289
  * SAFE TO EDIT - This file is never overwritten by Omnify.
272
290
  */
273
291
 
274
- namespace ${requestNamespace};
292
+ namespace ${editable.namespace};
275
293
 
276
- use ${baseNamespace}\\${modelName}${action}RequestBase;
294
+ use ${baseDescriptor.fqn};
277
295
 
278
296
  /**
279
297
  * ${modelName}${action}Request — add project-specific authorization and validation here.
@@ -283,10 +301,10 @@ use ${baseNamespace}\\${modelName}${action}RequestBase;
283
301
  * - rules(): array (returns schemaRules() — override to add custom rules)
284
302
  * - attributes(): array (returns schemaAttributes() — override to rename fields)
285
303
  */
286
- class ${modelName}${action}Request extends ${modelName}${action}RequestBase
304
+ class ${editable.className} extends ${baseDescriptor.className}
287
305
  {
288
306
  //
289
307
  }
290
308
  `;
291
- return userFile(`${config.requests.path}/${modelName}${action}Request.php`, content);
309
+ return userFile(`${editable.path}/${editable.fileName}`, content);
292
310
  }
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { toPascalCase, toSnakeCase, toCamelCase } from './naming-helper.js';
5
5
  import { isHiddenByDefault, toResourceExpression } from './type-mapper.js';
6
- import { baseFile, userFile, resolveModularBasePath, resolveModularBaseNamespace } from './types.js';
6
+ import { baseFile, userFile, resolveModularBasePath, resolveModularBaseNamespace, resolveBaseClass, resolveEditableClass } from './types.js';
7
7
  /** Generate Resource classes for all project-owned visible object schemas. */
8
8
  export function generateResources(reader, config) {
9
9
  const files = [];
@@ -119,12 +119,30 @@ ${fieldsContent}
119
119
  }
120
120
  }
121
121
  `;
122
- return baseFile(resolveModularBasePath(config, name, 'Resources', `${modelName}ResourceBase.php`, config.resources.basePath), content);
122
+ // Issue #96: legacy honors flatBase (drops ResourceBase suffix +
123
+ // OmnifyBase/ subfolder); modular keeps the per-module path.
124
+ const baseDescriptor = config.structure === 'modular'
125
+ ? {
126
+ className: `${modelName}ResourceBase`,
127
+ path: resolveModularBasePath(config, name, 'Resources', '', config.resources.basePath).replace(/\/$/, ''),
128
+ }
129
+ : resolveBaseClass(config.resources, `${modelName}Resource`, 'Base');
130
+ const finalContent = content.replace(new RegExp(`class ${modelName}ResourceBase\\b`, 'g'), `class ${baseDescriptor.className}`);
131
+ return baseFile(`${baseDescriptor.path}/${baseDescriptor.className}.php`, finalContent);
123
132
  }
124
133
  function generateUserResource(name, config) {
125
134
  const modelName = toPascalCase(name);
126
- const resourceNamespace = config.resources.namespace;
127
- const baseNamespace = resolveModularBaseNamespace(config, name, 'Resources', config.resources.baseNamespace);
135
+ // Issue #96: editable stub may live at userEditablePath; extends-clause
136
+ // adapts to flatBase too.
137
+ const baseDescriptor = config.structure === 'modular'
138
+ ? {
139
+ className: `${modelName}ResourceBase`,
140
+ fqn: `${resolveModularBaseNamespace(config, name, 'Resources', config.resources.baseNamespace)}\\${modelName}ResourceBase`,
141
+ }
142
+ : resolveBaseClass(config.resources, `${modelName}Resource`, 'Base');
143
+ const editable = config.structure === 'modular'
144
+ ? { className: `${modelName}Resource`, fileName: `${modelName}Resource.php`, namespace: config.resources.namespace, path: config.resources.path }
145
+ : resolveEditableClass(config.resources, modelName, 'Resource');
128
146
  const content = `<?php
129
147
 
130
148
  /**
@@ -133,9 +151,9 @@ function generateUserResource(name, config) {
133
151
  * SAFE TO EDIT - This file is never overwritten by Omnify.
134
152
  */
135
153
 
136
- namespace ${resourceNamespace};
154
+ namespace ${editable.namespace};
137
155
 
138
- use ${baseNamespace}\\${modelName}ResourceBase;
156
+ use ${baseDescriptor.fqn};
139
157
 
140
158
  /**
141
159
  * ${modelName}Resource — add project-specific serialization here.
@@ -143,12 +161,12 @@ use ${baseNamespace}\\${modelName}ResourceBase;
143
161
  * Inherited from base:
144
162
  * - toArray(Request \\$request): array (returns schemaArray(\\$request) — override to add fields)
145
163
  */
146
- class ${modelName}Resource extends ${modelName}ResourceBase
164
+ class ${editable.className} extends ${baseDescriptor.className}
147
165
  {
148
166
  //
149
167
  }
150
168
  `;
151
- return userFile(`${config.resources.path}/${modelName}Resource.php`, content);
169
+ return userFile(`${editable.path}/${editable.fileName}`, content);
152
170
  }
153
171
  function addAssociationFields(propName, prop, fields, resourceNamespace, modelNamespace, reader) {
154
172
  const relation = prop['relation'] ?? '';
@@ -13,7 +13,7 @@
13
13
  * eagerCount}` keys are deprecated and emit warnings at generate time.
14
14
  */
15
15
  import { toPascalCase, toSnakeCase } from './naming-helper.js';
16
- import { baseFile, userFile, resolveModularBasePath, resolveModularBaseNamespace } from './types.js';
16
+ import { baseFile, userFile, resolveModularBasePath, resolveModularBaseNamespace, resolveBaseClass, resolveEditableClass } from './types.js';
17
17
  // ============================================================================
18
18
  // Public entry point
19
19
  // ============================================================================
@@ -593,7 +593,17 @@ class ${modelName}ServiceBase
593
593
  ${sections.join('\n')}
594
594
  }
595
595
  `;
596
- return baseFile(resolveModularBasePath(config, name, 'Services', `${modelName}ServiceBase.php`, config.services.basePath), content);
596
+ // Issue #96: legacy structure honors flatBase (drops `ServiceBase`
597
+ // suffix + OmnifyBase/ subfolder); modular keeps the per-module path.
598
+ const baseDescriptor = config.structure === 'modular'
599
+ ? {
600
+ className: `${modelName}ServiceBase`,
601
+ fileName: `${modelName}ServiceBase.php`,
602
+ path: resolveModularBasePath(config, name, 'Services', '', config.services.basePath).replace(/\/$/, ''),
603
+ }
604
+ : resolveBaseClass(config.services, `${modelName}Service`, 'Base');
605
+ const finalContent = content.replace(new RegExp(`class ${modelName}ServiceBase\\b`, 'g'), `class ${baseDescriptor.className}`);
606
+ return baseFile(`${baseDescriptor.path}/${baseDescriptor.fileName}`, finalContent);
597
607
  }
598
608
  // ============================================================================
599
609
  // Method builders
@@ -1739,13 +1749,21 @@ function buildFlushTranslationsMethod(modelName) {
1739
1749
  function generateUserService(name, schema, config) {
1740
1750
  const modelName = toPascalCase(name);
1741
1751
  const group = schema.group ? toPascalCase(schema.group) : null;
1742
- const baseNs = resolveModularBaseNamespace(config, name, 'Services', config.services.baseNamespace);
1743
- const userNs = group
1744
- ? `${config.services.namespace}\\${group}`
1745
- : config.services.namespace;
1746
- const userPath = group
1747
- ? `${config.services.path}/${group}`
1748
- : config.services.path;
1752
+ // Issue #96: route editable stub via resolveEditableClass +
1753
+ // resolveBaseClass so userEditablePath / userEditableNamespace and
1754
+ // flatBase (drops ServiceBase suffix) are honored. Group nesting
1755
+ // (`<userPath>/<Group>/<Schema>Service.php`) preserved.
1756
+ const baseDescriptor = config.structure === 'modular'
1757
+ ? {
1758
+ className: `${modelName}ServiceBase`,
1759
+ fqn: `${resolveModularBaseNamespace(config, name, 'Services', config.services.baseNamespace)}\\${modelName}ServiceBase`,
1760
+ }
1761
+ : resolveBaseClass(config.services, `${modelName}Service`, 'Base');
1762
+ const editable = config.structure === 'modular'
1763
+ ? { className: `${modelName}Service`, fileName: `${modelName}Service.php`, namespace: config.services.namespace, path: config.services.path }
1764
+ : resolveEditableClass(config.services, modelName, 'Service');
1765
+ const userNs = group ? `${editable.namespace}\\${group}` : editable.namespace;
1766
+ const userPath = group ? `${editable.path}/${group}` : editable.path;
1749
1767
  const content = `<?php
1750
1768
 
1751
1769
  /**
@@ -1756,12 +1774,12 @@ function generateUserService(name, schema, config) {
1756
1774
 
1757
1775
  namespace ${userNs};
1758
1776
 
1759
- use ${baseNs}\\${modelName}ServiceBase;
1777
+ use ${baseDescriptor.fqn};
1760
1778
 
1761
- class ${modelName}Service extends ${modelName}ServiceBase
1779
+ class ${editable.className} extends ${baseDescriptor.className}
1762
1780
  {
1763
1781
  //
1764
1782
  }
1765
1783
  `;
1766
- return userFile(`${userPath}/${modelName}Service.php`, content);
1784
+ return userFile(`${userPath}/${editable.fileName}`, content);
1767
1785
  }
@@ -39,23 +39,80 @@ export declare function resolveSharedBasePath(config: PhpConfig, category: BaseC
39
39
  */
40
40
  export declare function resolveSharedBaseNamespace(config: PhpConfig, category: BaseCategory, legacyNamespace: string): string;
41
41
  /**
42
- * Resolve global Omnify enum file path. Used for system enums that aren't tied
43
- * to a single user-defined schema (e.g. FileStatusEnum belongs to the Omnify
44
- * file-attachment subsystem). In modular mode these live under their own
45
- * top-level folder so they're easy to find. In legacy mode the original
46
- * `legacyPath` is preserved for backward compat.
42
+ * Resolve global Omnify enum file path. ALWAYS uses
43
+ * `config.globalEnums.path` regardless of structure mode enums are
44
+ * conceptually independent of the model tree they describe and belong
45
+ * in their own dedicated folder for discoverability. The `legacyPath`
46
+ * argument is kept for callsite compatibility but ignored.
47
+ *
48
+ * Default: `app/Omnify/Enums/`. Override via `codegen.laravel.enums.path`
49
+ * in `omnify.yaml` (e.g. set to `app/Models/Omnify` to restore the
50
+ * pre-v5.6 legacy behavior of co-locating enums with models).
51
+ *
52
+ * History: pre-v5.6, legacy structure dumped enums into the model dir
53
+ * (`app/Models/Omnify/<Name>Enum.php`), mixing them with the user
54
+ * models — confusing for code reviewers and inconsistent with modular
55
+ * mode. Fixed via dedicated dir always.
56
+ */
57
+ export declare function resolveGlobalEnumPath(config: PhpConfig, fileName: string, _legacyPath: string): string;
58
+ /**
59
+ * Resolve global Omnify enum namespace. ALWAYS uses
60
+ * `config.globalEnums.namespace`. The `legacyNamespace` argument is
61
+ * kept for callsite compatibility but ignored.
62
+ *
63
+ * Default: `App\Omnify\Enums`. Override via
64
+ * `codegen.laravel.enums.namespace` to match a custom path.
65
+ *
66
+ * History: pre-v5.6, legacy structure used the model namespace
67
+ * (`App\Models\Omnify`), forcing every model file to import enums via
68
+ * the model dir. Fixed via dedicated namespace always.
47
69
  */
48
- export declare function resolveGlobalEnumPath(config: PhpConfig, fileName: string, legacyPath: string): string;
49
- /** Resolve global Omnify enum namespace. Modular: {globalEnums.namespace}. Legacy: passthrough. */
50
- export declare function resolveGlobalEnumNamespace(config: PhpConfig, legacyNamespace: string): string;
70
+ export declare function resolveGlobalEnumNamespace(config: PhpConfig, _legacyNamespace: string): string;
51
71
  /** Resolve global Omnify trait file path (HasFiles, HasLocalizedDisplayName, ...). */
52
72
  export declare function resolveGlobalTraitPath(config: PhpConfig, fileName: string, legacyPath: string): string;
53
73
  /** Resolve global Omnify trait namespace. */
54
74
  export declare function resolveGlobalTraitNamespace(config: PhpConfig, legacyNamespace: string): string;
55
- /** Per-target path and namespace override from codegen.laravel config. */
75
+ /**
76
+ * Per-target path and namespace override from codegen.laravel config.
77
+ *
78
+ * Two evolutions in v5.4+ (issue #96): split base / user-editable paths
79
+ * and `flatBase` to drop the `Base/` subfolder + `*Base*` suffix when
80
+ * the team has already isolated generated code under its own root
81
+ * (e.g. `app/Omnify/`).
82
+ *
83
+ * Backwards-compat: if `userEditablePath` / `userEditableNamespace` /
84
+ * `flatBase` are absent, the existing two-tier layout (base + editable
85
+ * in the same dir, base under `Base/` subfolder with `*Base*` suffix)
86
+ * stays exactly as before. No project needs to change config to keep
87
+ * working.
88
+ */
56
89
  export interface LaravelPathOverride {
90
+ /** Path for BASE (auto-generated, regenerated) classes. */
57
91
  path?: string;
92
+ /** Namespace for BASE (auto-generated) classes. */
58
93
  namespace?: string;
94
+ /**
95
+ * Path for USER-EDITABLE stubs (omnify writes once, then never touches).
96
+ * When set, base files write under `path` and editable stubs under
97
+ * `userEditablePath`. When unset, editable stubs share `path` (legacy
98
+ * behavior). Issue #96.
99
+ */
100
+ userEditablePath?: string;
101
+ /**
102
+ * Namespace for USER-EDITABLE stubs. When set, the editable stub uses
103
+ * this namespace and `extends \{baseNs}\{Class}`. When unset, the
104
+ * editable stub shares the base namespace (legacy). Issue #96.
105
+ */
106
+ userEditableNamespace?: string;
107
+ /**
108
+ * `flatBase: true` drops the `Base/` (or `OmnifyBase/`) subfolder AND
109
+ * the `*BaseModel` / `*RequestBase` / etc. class suffix. Base files
110
+ * land directly under `path` with the bare schema name as the class.
111
+ * The user-editable stub then `extends \{path-namespace}\{Schema}` —
112
+ * one less indirection. Issue #96. Recommended when `path` already
113
+ * isolates generated code (e.g. `app/Omnify/Models/`).
114
+ */
115
+ flatBase?: boolean;
59
116
  }
60
117
  /** Nested set package configuration. */
61
118
  export interface NestedSetOverride {
@@ -131,6 +188,44 @@ export interface LaravelCodegenOverrides {
131
188
  /** OpenAPI / Swagger codegen — opt-in. See `OpenApiOverride`. */
132
189
  openapi?: OpenApiOverride;
133
190
  }
191
+ /**
192
+ * Resolved per-layer config for layers that follow the Base + Editable
193
+ * pattern (Model, Service, Request, Resource, Policy, Controller).
194
+ * Issue #96 added `userEditablePath` / `userEditableNamespace` (split
195
+ * paths) and `flatBase` (drop Base/ subfolder + *Base* suffix).
196
+ *
197
+ * Backwards-compat: when the new fields default, `userEditablePath`
198
+ * equals `path` and `userEditableNamespace` equals `namespace` —
199
+ * editable stubs share the same dir as the base, identical to v5.3.x.
200
+ * `flatBase` defaults false — keeps the existing `*BaseModel` /
201
+ * `*RequestBase` / etc. suffix + Base/ subfolder.
202
+ */
203
+ export interface BaseEditableLayer {
204
+ /** Namespace for base classes. */
205
+ namespace: string;
206
+ /** Namespace for base classes' Base/ subfolder (or = namespace when flatBase). */
207
+ baseNamespace: string;
208
+ /** Filesystem path where base classes live. */
209
+ path: string;
210
+ /** Filesystem path for the Base/ subfolder (or = path when flatBase). */
211
+ basePath: string;
212
+ /**
213
+ * Filesystem path for user-editable stubs. Defaults to `path` (legacy:
214
+ * stubs share the dir with base). Set via `userEditablePath` override
215
+ * to relocate the editable stubs to e.g. canonical Laravel paths
216
+ * (`app/Models/`, `app/Http/Requests/`). Issue #96.
217
+ */
218
+ userEditablePath: string;
219
+ /** Namespace for user-editable stubs. Defaults to `namespace`. Issue #96. */
220
+ userEditableNamespace: string;
221
+ /**
222
+ * `true` collapses the legacy two-tier shape (base under `Base/` with
223
+ * `*Base*` suffix) into a single flat directory: base lives at `path`
224
+ * with the bare schema name as the class. The editable stub then
225
+ * extends `\{namespace}\{Schema}` (no `BaseModel` indirection). Issue #96.
226
+ */
227
+ flatBase: boolean;
228
+ }
134
229
  /** PHP codegen configuration (resolved with defaults). */
135
230
  export interface PhpConfig {
136
231
  /** Filesystem prefix applied to all generated paths. Empty when not set. */
@@ -166,24 +261,9 @@ export interface PhpConfig {
166
261
  * @deprecated use `modules.path`
167
262
  */
168
263
  modulesPath: string;
169
- models: {
170
- namespace: string;
171
- baseNamespace: string;
172
- path: string;
173
- basePath: string;
174
- };
175
- requests: {
176
- namespace: string;
177
- baseNamespace: string;
178
- path: string;
179
- basePath: string;
180
- };
181
- resources: {
182
- namespace: string;
183
- baseNamespace: string;
184
- path: string;
185
- basePath: string;
186
- };
264
+ models: BaseEditableLayer;
265
+ requests: BaseEditableLayer;
266
+ resources: BaseEditableLayer;
187
267
  factories: {
188
268
  namespace: string;
189
269
  path: string;
@@ -192,24 +272,9 @@ export interface PhpConfig {
192
272
  namespace: string;
193
273
  path: string;
194
274
  };
195
- policies: {
196
- namespace: string;
197
- baseNamespace: string;
198
- path: string;
199
- basePath: string;
200
- };
201
- controllers: {
202
- namespace: string;
203
- baseNamespace: string;
204
- path: string;
205
- basePath: string;
206
- };
207
- services: {
208
- namespace: string;
209
- baseNamespace: string;
210
- path: string;
211
- basePath: string;
212
- };
275
+ policies: BaseEditableLayer;
276
+ controllers: BaseEditableLayer;
277
+ services: BaseEditableLayer;
213
278
  routes: {
214
279
  path: string;
215
280
  };
@@ -230,6 +295,35 @@ export interface PhpConfig {
230
295
  securityScheme: string;
231
296
  };
232
297
  }
298
+ /**
299
+ * Class-name + file-name resolver for the BASE class of a layer. Returns
300
+ * the bare schema name when `layer.flatBase` is true (e.g. `Banner.php`
301
+ * with class `Banner`); returns the legacy `<Schema><Suffix>` shape
302
+ * otherwise (e.g. `BannerBaseModel.php` with class `BannerBaseModel`).
303
+ *
304
+ * Used by every Base + Editable generator (model, service, request,
305
+ * resource, policy, controller) so the flatBase semantics stay
306
+ * consistent across layers. Issue #96.
307
+ */
308
+ export declare function resolveBaseClass(layer: BaseEditableLayer, schemaName: string, baseSuffix: string): {
309
+ className: string;
310
+ fileName: string;
311
+ namespace: string;
312
+ path: string;
313
+ fqn: string;
314
+ };
315
+ /**
316
+ * Resolver for the user-editable stub of a layer. Always uses the bare
317
+ * schema name as the class (the editable stub IS the user's class) +
318
+ * `userEditablePath` / `userEditableNamespace` for location. Issue #96.
319
+ */
320
+ export declare function resolveEditableClass(layer: BaseEditableLayer, schemaName: string, classSuffix?: string): {
321
+ className: string;
322
+ fileName: string;
323
+ namespace: string;
324
+ path: string;
325
+ fqn: string;
326
+ };
233
327
  /**
234
328
  * Derive full PHP config from optional overrides.
235
329
  * All paths and namespaces fall back to sensible defaults.
package/dist/php/types.js CHANGED
@@ -54,24 +54,38 @@ export function resolveSharedBaseNamespace(config, category, legacyNamespace) {
54
54
  return legacyNamespace;
55
55
  }
56
56
  /**
57
- * Resolve global Omnify enum file path. Used for system enums that aren't tied
58
- * to a single user-defined schema (e.g. FileStatusEnum belongs to the Omnify
59
- * file-attachment subsystem). In modular mode these live under their own
60
- * top-level folder so they're easy to find. In legacy mode the original
61
- * `legacyPath` is preserved for backward compat.
57
+ * Resolve global Omnify enum file path. ALWAYS uses
58
+ * `config.globalEnums.path` regardless of structure mode enums are
59
+ * conceptually independent of the model tree they describe and belong
60
+ * in their own dedicated folder for discoverability. The `legacyPath`
61
+ * argument is kept for callsite compatibility but ignored.
62
+ *
63
+ * Default: `app/Omnify/Enums/`. Override via `codegen.laravel.enums.path`
64
+ * in `omnify.yaml` (e.g. set to `app/Models/Omnify` to restore the
65
+ * pre-v5.6 legacy behavior of co-locating enums with models).
66
+ *
67
+ * History: pre-v5.6, legacy structure dumped enums into the model dir
68
+ * (`app/Models/Omnify/<Name>Enum.php`), mixing them with the user
69
+ * models — confusing for code reviewers and inconsistent with modular
70
+ * mode. Fixed via dedicated dir always.
62
71
  */
63
- export function resolveGlobalEnumPath(config, fileName, legacyPath) {
64
- if (config.structure === 'modular') {
65
- return `${config.globalEnums.path}/${fileName}`;
66
- }
67
- return `${legacyPath}/${fileName}`;
72
+ export function resolveGlobalEnumPath(config, fileName, _legacyPath) {
73
+ return `${config.globalEnums.path}/${fileName}`;
68
74
  }
69
- /** Resolve global Omnify enum namespace. Modular: {globalEnums.namespace}. Legacy: passthrough. */
70
- export function resolveGlobalEnumNamespace(config, legacyNamespace) {
71
- if (config.structure === 'modular') {
72
- return config.globalEnums.namespace;
73
- }
74
- return legacyNamespace;
75
+ /**
76
+ * Resolve global Omnify enum namespace. ALWAYS uses
77
+ * `config.globalEnums.namespace`. The `legacyNamespace` argument is
78
+ * kept for callsite compatibility but ignored.
79
+ *
80
+ * Default: `App\Omnify\Enums`. Override via
81
+ * `codegen.laravel.enums.namespace` to match a custom path.
82
+ *
83
+ * History: pre-v5.6, legacy structure used the model namespace
84
+ * (`App\Models\Omnify`), forcing every model file to import enums via
85
+ * the model dir. Fixed via dedicated namespace always.
86
+ */
87
+ export function resolveGlobalEnumNamespace(config, _legacyNamespace) {
88
+ return config.globalEnums.namespace;
75
89
  }
76
90
  /** Resolve global Omnify trait file path (HasFiles, HasLocalizedDisplayName, ...). */
77
91
  export function resolveGlobalTraitPath(config, fileName, legacyPath) {
@@ -129,6 +143,63 @@ function resolvePathAndNamespace(rootPath, override, defaultPath, nsFromPath) {
129
143
  const namespace = hasNs ? override.namespace : nsFromPath(path);
130
144
  return { path, namespace };
131
145
  }
146
+ /**
147
+ * Build a complete BaseEditableLayer descriptor from per-layer overrides.
148
+ * Centralizes the v5.4-era defaulting rules (split paths + flatBase) so
149
+ * every layer (model, service, request, resource, policy, controller)
150
+ * resolves consistently. Issue #96.
151
+ */
152
+ function resolveBaseEditableLayer(rootPath, override, defaultPath, baseSubfolder, // "Base" for models/policies, "OmnifyBase" for the rest
153
+ nsFromPath) {
154
+ const { path, namespace } = resolvePathAndNamespace(rootPath, override, defaultPath, nsFromPath);
155
+ const flatBase = override?.flatBase ?? false;
156
+ // Base path + namespace: when flat, base lives directly at `path`;
157
+ // otherwise it nests under the conventional Base/ (or OmnifyBase/) subfolder.
158
+ const basePath = flatBase ? path : `${path}/${baseSubfolder}`;
159
+ const baseNamespace = flatBase ? namespace : `${namespace}\\${baseSubfolder}`;
160
+ // User-editable: defaults to the same dir as base (legacy behavior),
161
+ // overridable to e.g. canonical Laravel paths (`app/Models/`).
162
+ const userEditablePath = override?.userEditablePath
163
+ ? withRoot(rootPath, override.userEditablePath)
164
+ : path;
165
+ const userEditableNamespace = override?.userEditableNamespace ?? namespace;
166
+ return { namespace, baseNamespace, path, basePath, userEditablePath, userEditableNamespace, flatBase };
167
+ }
168
+ /**
169
+ * Class-name + file-name resolver for the BASE class of a layer. Returns
170
+ * the bare schema name when `layer.flatBase` is true (e.g. `Banner.php`
171
+ * with class `Banner`); returns the legacy `<Schema><Suffix>` shape
172
+ * otherwise (e.g. `BannerBaseModel.php` with class `BannerBaseModel`).
173
+ *
174
+ * Used by every Base + Editable generator (model, service, request,
175
+ * resource, policy, controller) so the flatBase semantics stay
176
+ * consistent across layers. Issue #96.
177
+ */
178
+ export function resolveBaseClass(layer, schemaName, baseSuffix) {
179
+ const className = layer.flatBase ? schemaName : `${schemaName}${baseSuffix}`;
180
+ return {
181
+ className,
182
+ fileName: `${className}.php`,
183
+ namespace: layer.baseNamespace,
184
+ path: layer.basePath,
185
+ fqn: `${layer.baseNamespace}\\${className}`,
186
+ };
187
+ }
188
+ /**
189
+ * Resolver for the user-editable stub of a layer. Always uses the bare
190
+ * schema name as the class (the editable stub IS the user's class) +
191
+ * `userEditablePath` / `userEditableNamespace` for location. Issue #96.
192
+ */
193
+ export function resolveEditableClass(layer, schemaName, classSuffix = '') {
194
+ const className = `${schemaName}${classSuffix}`;
195
+ return {
196
+ className,
197
+ fileName: `${className}.php`,
198
+ namespace: layer.userEditableNamespace,
199
+ path: layer.userEditablePath,
200
+ fqn: `${layer.userEditableNamespace}\\${className}`,
201
+ };
202
+ }
132
203
  // Default paths.
133
204
  //
134
205
  // Hybrid projects (manual team code + Omnify codegen) need Omnify-generated
@@ -189,14 +260,18 @@ export function derivePhpConfig(overrides) {
189
260
  return p;
190
261
  };
191
262
  const nsFromPath = (p) => pathToNamespace(stripRoot(p));
192
- const { path: modelPath, namespace: modelNs } = resolvePathAndNamespace(rootPath, overrides?.model, DEFAULT_MODEL_PATH, nsFromPath);
193
- const { path: requestPath, namespace: requestNs } = resolvePathAndNamespace(rootPath, overrides?.request, DEFAULT_REQUEST_PATH, nsFromPath);
194
- const { path: resourcePath, namespace: resourceNs } = resolvePathAndNamespace(rootPath, overrides?.resource, DEFAULT_RESOURCE_PATH, nsFromPath);
263
+ // Layers that follow the Base + Editable pattern (issue #96): resolve
264
+ // both layouts (`Base/` + `*Base*` suffix vs flat) and both paths
265
+ // (base + user-editable) in one place so every layer shares semantics.
266
+ const modelsLayer = resolveBaseEditableLayer(rootPath, overrides?.model, DEFAULT_MODEL_PATH, 'Base', nsFromPath);
267
+ const requestsLayer = resolveBaseEditableLayer(rootPath, overrides?.request, DEFAULT_REQUEST_PATH, 'OmnifyBase', nsFromPath);
268
+ const resourcesLayer = resolveBaseEditableLayer(rootPath, overrides?.resource, DEFAULT_RESOURCE_PATH, 'OmnifyBase', nsFromPath);
269
+ const policiesLayer = resolveBaseEditableLayer(rootPath, overrides?.policy, DEFAULT_POLICY_PATH, 'Base', nsFromPath);
270
+ const controllersLayer = resolveBaseEditableLayer(rootPath, overrides?.controller, DEFAULT_CONTROLLER_PATH, 'OmnifyBase', nsFromPath);
271
+ const servicesLayer = resolveBaseEditableLayer(rootPath, overrides?.service, DEFAULT_SERVICE_PATH, 'OmnifyBase', nsFromPath);
272
+ // Layers without a Base + Editable split (single-tier files).
195
273
  const { path: factoryPath, namespace: factoryNs } = resolvePathAndNamespace(rootPath, overrides?.factory, DEFAULT_FACTORY_PATH, nsFromPath);
196
274
  const { path: providerPath, namespace: providerNs } = resolvePathAndNamespace(rootPath, overrides?.provider, DEFAULT_PROVIDER_PATH, nsFromPath);
197
- const { path: policyPath, namespace: policyNs } = resolvePathAndNamespace(rootPath, overrides?.policy, DEFAULT_POLICY_PATH, nsFromPath);
198
- const { path: controllerPath, namespace: controllerNs } = resolvePathAndNamespace(rootPath, overrides?.controller, DEFAULT_CONTROLLER_PATH, nsFromPath);
199
- const { path: servicePath, namespace: serviceNs } = resolvePathAndNamespace(rootPath, overrides?.service, DEFAULT_SERVICE_PATH, nsFromPath);
200
275
  const { path: modulesPath, namespace: modulesNs } = resolvePathAndNamespace(rootPath, overrides?.modules, DEFAULT_MODULES_PATH, nsFromPath);
201
276
  const { path: sharedPath, namespace: sharedNs } = resolvePathAndNamespace(rootPath, overrides?.shared, DEFAULT_SHARED_PATH, nsFromPath);
202
277
  const { path: globalEnumsPath, namespace: globalEnumsNs } = resolvePathAndNamespace(rootPath, overrides?.enums, DEFAULT_GLOBAL_ENUMS_PATH, nsFromPath);
@@ -220,24 +295,9 @@ export function derivePhpConfig(overrides) {
220
295
  globalEnums: { namespace: globalEnumsNs, path: globalEnumsPath },
221
296
  globalTraits: { namespace: globalTraitsNs, path: globalTraitsPath },
222
297
  modulesPath,
223
- models: {
224
- namespace: modelNs,
225
- baseNamespace: `${modelNs}\\Base`,
226
- path: modelPath,
227
- basePath: `${modelPath}/Base`,
228
- },
229
- requests: {
230
- namespace: requestNs,
231
- baseNamespace: `${requestNs}\\OmnifyBase`,
232
- path: requestPath,
233
- basePath: `${requestPath}/OmnifyBase`,
234
- },
235
- resources: {
236
- namespace: resourceNs,
237
- baseNamespace: `${resourceNs}\\OmnifyBase`,
238
- path: resourcePath,
239
- basePath: `${resourcePath}/OmnifyBase`,
240
- },
298
+ models: modelsLayer,
299
+ requests: requestsLayer,
300
+ resources: resourcesLayer,
241
301
  factories: {
242
302
  namespace: factoryNs,
243
303
  path: factoryPath,
@@ -246,24 +306,9 @@ export function derivePhpConfig(overrides) {
246
306
  namespace: providerNs,
247
307
  path: providerPath,
248
308
  },
249
- policies: {
250
- namespace: policyNs,
251
- baseNamespace: `${policyNs}\\Base`,
252
- path: policyPath,
253
- basePath: `${policyPath}/Base`,
254
- },
255
- controllers: {
256
- namespace: controllerNs,
257
- baseNamespace: `${controllerNs}\\OmnifyBase`,
258
- path: controllerPath,
259
- basePath: `${controllerPath}/OmnifyBase`,
260
- },
261
- services: {
262
- namespace: serviceNs,
263
- baseNamespace: `${serviceNs}\\OmnifyBase`,
264
- path: servicePath,
265
- basePath: `${servicePath}/OmnifyBase`,
266
- },
309
+ policies: policiesLayer,
310
+ controllers: controllersLayer,
311
+ services: servicesLayer,
267
312
  routes: {
268
313
  path: routePath,
269
314
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnifyjp/ts",
3
- "version": "5.4.0",
3
+ "version": "5.6.0",
4
4
  "description": "TypeScript model type generator from Omnify schemas.json",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",