@omnifyjp/ts 1.2.6 → 1.3.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/cli.js +1 -0
- package/dist/php/model-generator.js +78 -11
- package/dist/php/types.d.ts +8 -0
- package/dist/php/types.js +4 -0
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -23,9 +23,12 @@ export function generateModels(reader, config) {
|
|
|
23
23
|
return files;
|
|
24
24
|
}
|
|
25
25
|
function generateForSchema(name, schema, reader, config) {
|
|
26
|
+
const properties = (schema.properties ?? {});
|
|
27
|
+
const options = schema.options ?? {};
|
|
28
|
+
const hasNestedSet = detectNestedSet(options, properties);
|
|
26
29
|
return [
|
|
27
30
|
generateBaseModel(name, schema, reader, config),
|
|
28
|
-
generateUserModel(name, config),
|
|
31
|
+
generateUserModel(name, config, hasNestedSet),
|
|
29
32
|
];
|
|
30
33
|
}
|
|
31
34
|
function generateBaseModel(name, schema, reader, config) {
|
|
@@ -40,6 +43,9 @@ function generateBaseModel(name, schema, reader, config) {
|
|
|
40
43
|
const isAuthenticatable = options['authenticatable'] ?? false;
|
|
41
44
|
const hasSoftDelete = options.softDelete ?? false;
|
|
42
45
|
const hasTimestamps = options.timestamps ?? false;
|
|
46
|
+
// NodeTrait is added to the user-editable Model, not BaseModel
|
|
47
|
+
const hasNestedSet = false;
|
|
48
|
+
const nestedSetParentColumn = null;
|
|
43
49
|
const translatableFields = reader.getTranslatableFields(name);
|
|
44
50
|
const hasTranslatable = translatableFields.length > 0;
|
|
45
51
|
const primaryKey = options['primaryKey'] ?? 'id';
|
|
@@ -48,17 +54,18 @@ function generateBaseModel(name, schema, reader, config) {
|
|
|
48
54
|
const isCompositeKey = primaryKey.includes(',');
|
|
49
55
|
const needsUuidTrait = !isCompositeKey && idType === 'Uuid';
|
|
50
56
|
const needsUlidTrait = !isCompositeKey && idType === 'Ulid';
|
|
51
|
-
const imports = buildImports(baseNamespace, modelName, hasSoftDelete, isAuthenticatable, hasTranslatable, properties, needsUuidTrait, needsUlidTrait);
|
|
57
|
+
const imports = buildImports(baseNamespace, modelName, hasSoftDelete, isAuthenticatable, hasTranslatable, properties, needsUuidTrait, needsUlidTrait, hasNestedSet, config.nestedset.namespace);
|
|
52
58
|
const docProperties = buildDocProperties(properties, expandedProperties, propertyOrder);
|
|
53
59
|
const baseClass = isAuthenticatable ? 'Authenticatable' : 'BaseModel';
|
|
54
60
|
const implementsClause = hasTranslatable ? ' implements TranslatableContract' : '';
|
|
55
|
-
const traits = buildTraits(hasSoftDelete, isAuthenticatable, hasTranslatable, needsUuidTrait, needsUlidTrait);
|
|
61
|
+
const traits = buildTraits(hasSoftDelete, isAuthenticatable, hasTranslatable, needsUuidTrait, needsUlidTrait, hasNestedSet);
|
|
56
62
|
const fillable = buildFillable(properties, expandedProperties, propertyOrder);
|
|
57
63
|
const hidden = buildHidden(properties, expandedProperties, propertyOrder);
|
|
58
64
|
const appends = buildAppends(expandedProperties);
|
|
59
65
|
const casts = buildCasts(properties, expandedProperties, propertyOrder);
|
|
60
66
|
const relations = buildRelations(name, properties, propertyOrder, modelNamespace, reader);
|
|
61
67
|
const accessors = buildAccessors(expandedProperties);
|
|
68
|
+
const nestedSetMethod = buildNestedSetParentIdMethod(nestedSetParentColumn);
|
|
62
69
|
let keyTypeSection = '';
|
|
63
70
|
if (idType === 'Uuid' || idType === 'Ulid' || idType === 'String') {
|
|
64
71
|
keyTypeSection = `
|
|
@@ -155,16 +162,29 @@ ${appends} ];
|
|
|
155
162
|
return [
|
|
156
163
|
${casts} ];
|
|
157
164
|
}
|
|
158
|
-
${relations}${accessors}
|
|
165
|
+
${relations}${accessors}${nestedSetMethod}
|
|
159
166
|
}
|
|
160
167
|
`;
|
|
161
168
|
return baseFile(`${config.models.basePath}/${modelName}BaseModel.php`, content);
|
|
162
169
|
}
|
|
163
|
-
function generateUserModel(name, config) {
|
|
170
|
+
function generateUserModel(name, config, hasNestedSet = false) {
|
|
164
171
|
const modelName = toPascalCase(name);
|
|
165
172
|
const modelNamespace = config.models.namespace;
|
|
166
173
|
const baseNamespace = config.models.baseNamespace;
|
|
167
174
|
const factoryNamespace = config.factories.namespace;
|
|
175
|
+
const nestedSetNamespace = config.nestedset.namespace;
|
|
176
|
+
const imports = [
|
|
177
|
+
`use ${baseNamespace}\\${modelName}BaseModel;`,
|
|
178
|
+
`use ${factoryNamespace}\\${modelName}Factory;`,
|
|
179
|
+
`use Illuminate\\Database\\Eloquent\\Factories\\HasFactory;`,
|
|
180
|
+
];
|
|
181
|
+
if (hasNestedSet) {
|
|
182
|
+
imports.push(`use ${nestedSetNamespace}\\NodeTrait;`);
|
|
183
|
+
}
|
|
184
|
+
const traits = [' use HasFactory;'];
|
|
185
|
+
if (hasNestedSet) {
|
|
186
|
+
traits.push(' use NodeTrait;');
|
|
187
|
+
}
|
|
168
188
|
const content = `<?php
|
|
169
189
|
|
|
170
190
|
/**
|
|
@@ -175,16 +195,14 @@ function generateUserModel(name, config) {
|
|
|
175
195
|
|
|
176
196
|
namespace ${modelNamespace};
|
|
177
197
|
|
|
178
|
-
|
|
179
|
-
use ${factoryNamespace}\\${modelName}Factory;
|
|
180
|
-
use Illuminate\\Database\\Eloquent\\Factories\\HasFactory;
|
|
198
|
+
${imports.join('\n')}
|
|
181
199
|
|
|
182
200
|
/**
|
|
183
201
|
* ${modelName} — add project-specific model logic here.
|
|
184
202
|
*/
|
|
185
203
|
class ${modelName} extends ${modelName}BaseModel
|
|
186
204
|
{
|
|
187
|
-
|
|
205
|
+
${traits.join('\n')}
|
|
188
206
|
|
|
189
207
|
/**
|
|
190
208
|
* Create a new factory instance for the model.
|
|
@@ -199,7 +217,7 @@ class ${modelName} extends ${modelName}BaseModel
|
|
|
199
217
|
`;
|
|
200
218
|
return userFile(`${config.models.path}/${modelName}.php`, content);
|
|
201
219
|
}
|
|
202
|
-
function buildImports(baseNamespace, modelName, hasSoftDelete, isAuthenticatable, hasTranslatable, properties, needsUuidTrait = false, needsUlidTrait = false) {
|
|
220
|
+
function buildImports(baseNamespace, modelName, hasSoftDelete, isAuthenticatable, hasTranslatable, properties, needsUuidTrait = false, needsUlidTrait = false, hasNestedSet = false, nestedSetNamespace = 'Aimeos\\Nestedset') {
|
|
203
221
|
const lines = [];
|
|
204
222
|
if (isAuthenticatable) {
|
|
205
223
|
lines.push('use Illuminate\\Foundation\\Auth\\User as Authenticatable;');
|
|
@@ -222,6 +240,9 @@ function buildImports(baseNamespace, modelName, hasSoftDelete, isAuthenticatable
|
|
|
222
240
|
if (hasSoftDelete) {
|
|
223
241
|
lines.push('use Illuminate\\Database\\Eloquent\\SoftDeletes;');
|
|
224
242
|
}
|
|
243
|
+
if (hasNestedSet) {
|
|
244
|
+
lines.push(`use ${nestedSetNamespace}\\NodeTrait;`);
|
|
245
|
+
}
|
|
225
246
|
if (hasTranslatable) {
|
|
226
247
|
lines.push('use Astrotomic\\Translatable\\Contracts\\Translatable as TranslatableContract;');
|
|
227
248
|
lines.push('use Astrotomic\\Translatable\\Translatable;');
|
|
@@ -262,7 +283,7 @@ function buildDocProperties(properties, expandedProperties, propertyOrder) {
|
|
|
262
283
|
}
|
|
263
284
|
return lines.length === 0 ? '' : lines.join('\n') + '\n';
|
|
264
285
|
}
|
|
265
|
-
function buildTraits(hasSoftDelete, isAuthenticatable, hasTranslatable, needsUuidTrait = false, needsUlidTrait = false) {
|
|
286
|
+
function buildTraits(hasSoftDelete, isAuthenticatable, hasTranslatable, needsUuidTrait = false, needsUlidTrait = false, hasNestedSet = false) {
|
|
266
287
|
const lines = [];
|
|
267
288
|
lines.push(' use HasLocalizedDisplayName;');
|
|
268
289
|
if (needsUuidTrait)
|
|
@@ -271,6 +292,8 @@ function buildTraits(hasSoftDelete, isAuthenticatable, hasTranslatable, needsUui
|
|
|
271
292
|
lines.push(' use HasUlids;');
|
|
272
293
|
if (isAuthenticatable)
|
|
273
294
|
lines.push(' use Notifiable;');
|
|
295
|
+
if (hasNestedSet)
|
|
296
|
+
lines.push(' use NodeTrait;');
|
|
274
297
|
if (hasSoftDelete)
|
|
275
298
|
lines.push(' use SoftDeletes;');
|
|
276
299
|
if (hasTranslatable)
|
|
@@ -455,6 +478,50 @@ class ${modelName} extends Package${modelName}
|
|
|
455
478
|
`;
|
|
456
479
|
return userFile(`${config.models.path}/${modelName}.php`, content);
|
|
457
480
|
}
|
|
481
|
+
/**
|
|
482
|
+
* Detect whether a schema uses nested set (tree structure).
|
|
483
|
+
* Checks both the explicit `nestedSet: true` option and the presence of
|
|
484
|
+
* nested set columns (_lft, _rgt, parent_id / _parent_id) in properties.
|
|
485
|
+
*/
|
|
486
|
+
function detectNestedSet(options, properties) {
|
|
487
|
+
if (options['nestedSet'] === true)
|
|
488
|
+
return true;
|
|
489
|
+
const propNames = Object.keys(properties);
|
|
490
|
+
const hasLft = propNames.some(p => p === '_lft' || p === 'lft');
|
|
491
|
+
const hasRgt = propNames.some(p => p === '_rgt' || p === 'rgt');
|
|
492
|
+
const hasParent = propNames.some(p => p === 'parent_id' || p === '_parent_id' || p === 'parentId' || p === 'parent');
|
|
493
|
+
return hasLft && hasRgt && hasParent;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Detect the parent ID column name for nested set models.
|
|
497
|
+
* Returns the column name if it differs from the default 'parent_id', or null.
|
|
498
|
+
*/
|
|
499
|
+
function detectNestedSetParentColumn(properties) {
|
|
500
|
+
const propNames = Object.keys(properties);
|
|
501
|
+
// Check for non-standard parent_id column names
|
|
502
|
+
if (propNames.includes('_parent_id'))
|
|
503
|
+
return '_parent_id';
|
|
504
|
+
if (propNames.includes('parent_id') || propNames.includes('parentId') || propNames.includes('parent'))
|
|
505
|
+
return null;
|
|
506
|
+
return null;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Build the getParentIdName() method override for nested set models
|
|
510
|
+
* that use a non-standard parent_id column name.
|
|
511
|
+
*/
|
|
512
|
+
function buildNestedSetParentIdMethod(parentColumn) {
|
|
513
|
+
if (!parentColumn)
|
|
514
|
+
return '';
|
|
515
|
+
return `
|
|
516
|
+
/**
|
|
517
|
+
* Get the column name for the parent ID.
|
|
518
|
+
*/
|
|
519
|
+
public function getParentIdName(): string
|
|
520
|
+
{
|
|
521
|
+
return '${parentColumn}';
|
|
522
|
+
}
|
|
523
|
+
`;
|
|
524
|
+
}
|
|
458
525
|
function fullNameAccessor(prefix, suffix, fields, separator) {
|
|
459
526
|
const methodName = 'get' + toPascalCase(prefix) + suffix + 'Attribute';
|
|
460
527
|
const fieldAccess = fields.map(f => `$this->${f}`).join(', ');
|
package/dist/php/types.d.ts
CHANGED
|
@@ -17,6 +17,10 @@ export interface LaravelPathOverride {
|
|
|
17
17
|
path?: string;
|
|
18
18
|
namespace?: string;
|
|
19
19
|
}
|
|
20
|
+
/** Nested set package configuration. */
|
|
21
|
+
export interface NestedSetOverride {
|
|
22
|
+
namespace?: string;
|
|
23
|
+
}
|
|
20
24
|
/** Overrides from codegen.laravel YAML config (all optional). */
|
|
21
25
|
export interface LaravelCodegenOverrides {
|
|
22
26
|
model?: LaravelPathOverride;
|
|
@@ -25,6 +29,7 @@ export interface LaravelCodegenOverrides {
|
|
|
25
29
|
factory?: LaravelPathOverride;
|
|
26
30
|
provider?: LaravelPathOverride;
|
|
27
31
|
policy?: LaravelPathOverride;
|
|
32
|
+
nestedset?: NestedSetOverride;
|
|
28
33
|
}
|
|
29
34
|
/** PHP codegen configuration (resolved with defaults). */
|
|
30
35
|
export interface PhpConfig {
|
|
@@ -60,6 +65,9 @@ export interface PhpConfig {
|
|
|
60
65
|
path: string;
|
|
61
66
|
basePath: string;
|
|
62
67
|
};
|
|
68
|
+
nestedset: {
|
|
69
|
+
namespace: string;
|
|
70
|
+
};
|
|
63
71
|
}
|
|
64
72
|
/**
|
|
65
73
|
* Derive full PHP config from optional overrides.
|
package/dist/php/types.js
CHANGED
|
@@ -40,6 +40,7 @@ export function derivePhpConfig(overrides) {
|
|
|
40
40
|
const providerNs = overrides?.provider?.namespace ?? pathToNamespace(providerPath);
|
|
41
41
|
const policyPath = overrides?.policy?.path ?? DEFAULT_POLICY_PATH;
|
|
42
42
|
const policyNs = overrides?.policy?.namespace ?? pathToNamespace(policyPath);
|
|
43
|
+
const nestedsetNs = overrides?.nestedset?.namespace ?? 'Aimeos\\Nestedset';
|
|
43
44
|
return {
|
|
44
45
|
models: {
|
|
45
46
|
namespace: modelNs,
|
|
@@ -73,5 +74,8 @@ export function derivePhpConfig(overrides) {
|
|
|
73
74
|
path: policyPath,
|
|
74
75
|
basePath: `${policyPath}/Base`,
|
|
75
76
|
},
|
|
77
|
+
nestedset: {
|
|
78
|
+
namespace: nestedsetNs,
|
|
79
|
+
},
|
|
76
80
|
};
|
|
77
81
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -87,6 +87,7 @@ export interface SchemaOptions {
|
|
|
87
87
|
readonly timestamps?: boolean;
|
|
88
88
|
readonly softDelete?: boolean;
|
|
89
89
|
readonly hidden?: boolean;
|
|
90
|
+
readonly nestedSet?: boolean;
|
|
90
91
|
readonly tableName?: string;
|
|
91
92
|
readonly indexes?: readonly unknown[];
|
|
92
93
|
readonly unique?: readonly unknown[];
|