@omnifyjp/ts 1.0.3 → 1.1.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/php/index.js +2 -0
- package/dist/php/model-generator.js +24 -6
- package/dist/php/schema-reader.d.ts +2 -0
- package/dist/php/schema-reader.js +16 -0
- package/dist/php/translation-model-generator.d.ts +13 -0
- package/dist/php/translation-model-generator.js +92 -0
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
package/dist/php/index.js
CHANGED
|
@@ -20,6 +20,7 @@ import { generateRequests } from './request-generator.js';
|
|
|
20
20
|
import { generateResources } from './resource-generator.js';
|
|
21
21
|
import { generateFactories } from './factory-generator.js';
|
|
22
22
|
import { generateServiceProvider } from './service-provider-generator.js';
|
|
23
|
+
import { generateTranslationModels } from './translation-model-generator.js';
|
|
23
24
|
export { derivePhpConfig } from './types.js';
|
|
24
25
|
/** Generate all PHP files from schemas.json data. */
|
|
25
26
|
export function generatePhp(data, overrides) {
|
|
@@ -33,6 +34,7 @@ export function generatePhp(data, overrides) {
|
|
|
33
34
|
// Per-schema files
|
|
34
35
|
files.push(...generateLocales(reader, config));
|
|
35
36
|
files.push(...generateModels(reader, config));
|
|
37
|
+
files.push(...generateTranslationModels(reader, config));
|
|
36
38
|
files.push(...generateRequests(reader, config));
|
|
37
39
|
files.push(...generateResources(reader, config));
|
|
38
40
|
files.push(...generateFactories(reader, config));
|
|
@@ -40,10 +40,13 @@ function generateBaseModel(name, schema, reader, config) {
|
|
|
40
40
|
const isAuthenticatable = options['authenticatable'] ?? false;
|
|
41
41
|
const hasSoftDelete = options.softDelete ?? false;
|
|
42
42
|
const hasTimestamps = options.timestamps ?? false;
|
|
43
|
-
const
|
|
43
|
+
const translatableFields = reader.getTranslatableFields(name);
|
|
44
|
+
const hasTranslatable = translatableFields.length > 0;
|
|
45
|
+
const imports = buildImports(baseNamespace, modelName, hasSoftDelete, isAuthenticatable, hasTranslatable, properties);
|
|
44
46
|
const docProperties = buildDocProperties(properties, expandedProperties, propertyOrder);
|
|
45
47
|
const baseClass = isAuthenticatable ? 'Authenticatable' : 'BaseModel';
|
|
46
|
-
const
|
|
48
|
+
const implementsClause = hasTranslatable ? ' implements TranslatableContract' : '';
|
|
49
|
+
const traits = buildTraits(hasSoftDelete, isAuthenticatable, hasTranslatable);
|
|
47
50
|
const fillable = buildFillable(properties, expandedProperties, propertyOrder);
|
|
48
51
|
const hidden = buildHidden(properties, expandedProperties, propertyOrder);
|
|
49
52
|
const appends = buildAppends(expandedProperties);
|
|
@@ -82,7 +85,7 @@ ${imports}
|
|
|
82
85
|
* ${modelName}BaseModel
|
|
83
86
|
*
|
|
84
87
|
${docProperties} */
|
|
85
|
-
class ${modelName}BaseModel extends ${baseClass}
|
|
88
|
+
class ${modelName}BaseModel extends ${baseClass}${implementsClause}
|
|
86
89
|
{
|
|
87
90
|
${traits} /**
|
|
88
91
|
* The table associated with the model.
|
|
@@ -113,7 +116,16 @@ ${keyTypeSection}
|
|
|
113
116
|
* @var array<string, array<string, string>>
|
|
114
117
|
*/
|
|
115
118
|
protected static array $localizedPropertyDisplayNames = ${modelName}Locales::PROPERTY_DISPLAY_NAMES;
|
|
116
|
-
|
|
119
|
+
${hasTranslatable ? `
|
|
120
|
+
/**
|
|
121
|
+
* The attributes that are translatable.
|
|
122
|
+
*
|
|
123
|
+
* @var array<int, string>
|
|
124
|
+
*/
|
|
125
|
+
public $translatedAttributes = [
|
|
126
|
+
${translatableFields.map(f => ` '${f}',`).join('\n')}
|
|
127
|
+
];
|
|
128
|
+
` : ''}
|
|
117
129
|
/**
|
|
118
130
|
* The attributes that are mass assignable.
|
|
119
131
|
*/
|
|
@@ -179,7 +191,7 @@ class ${modelName} extends ${modelName}BaseModel
|
|
|
179
191
|
`;
|
|
180
192
|
return userFile(`${config.models.path}/${modelName}.php`, content);
|
|
181
193
|
}
|
|
182
|
-
function buildImports(baseNamespace, modelName, hasSoftDelete, isAuthenticatable, properties) {
|
|
194
|
+
function buildImports(baseNamespace, modelName, hasSoftDelete, isAuthenticatable, hasTranslatable, properties) {
|
|
183
195
|
const lines = [];
|
|
184
196
|
if (isAuthenticatable) {
|
|
185
197
|
lines.push('use Illuminate\\Foundation\\Auth\\User as Authenticatable;');
|
|
@@ -196,6 +208,10 @@ function buildImports(baseNamespace, modelName, hasSoftDelete, isAuthenticatable
|
|
|
196
208
|
if (hasSoftDelete) {
|
|
197
209
|
lines.push('use Illuminate\\Database\\Eloquent\\SoftDeletes;');
|
|
198
210
|
}
|
|
211
|
+
if (hasTranslatable) {
|
|
212
|
+
lines.push('use Astrotomic\\Translatable\\Contracts\\Translatable as TranslatableContract;');
|
|
213
|
+
lines.push('use Astrotomic\\Translatable\\Translatable;');
|
|
214
|
+
}
|
|
199
215
|
return lines.join('\n') + '\n';
|
|
200
216
|
}
|
|
201
217
|
function buildDocProperties(properties, expandedProperties, propertyOrder) {
|
|
@@ -232,13 +248,15 @@ function buildDocProperties(properties, expandedProperties, propertyOrder) {
|
|
|
232
248
|
}
|
|
233
249
|
return lines.length === 0 ? '' : lines.join('\n') + '\n';
|
|
234
250
|
}
|
|
235
|
-
function buildTraits(hasSoftDelete, isAuthenticatable) {
|
|
251
|
+
function buildTraits(hasSoftDelete, isAuthenticatable, hasTranslatable) {
|
|
236
252
|
const lines = [];
|
|
237
253
|
lines.push(' use HasLocalizedDisplayName;');
|
|
238
254
|
if (isAuthenticatable)
|
|
239
255
|
lines.push(' use Notifiable;');
|
|
240
256
|
if (hasSoftDelete)
|
|
241
257
|
lines.push(' use SoftDeletes;');
|
|
258
|
+
if (hasTranslatable)
|
|
259
|
+
lines.push(' use Translatable;');
|
|
242
260
|
return lines.join('\n') + '\n';
|
|
243
261
|
}
|
|
244
262
|
function buildFillable(properties, expandedProperties, propertyOrder) {
|
|
@@ -47,4 +47,6 @@ export declare class SchemaReader {
|
|
|
47
47
|
getExpandedProperties(schemaName: string): Record<string, ExpandedProperty>;
|
|
48
48
|
getPropertyOrder(schemaName: string): string[];
|
|
49
49
|
getTableName(schemaName: string): string;
|
|
50
|
+
/** Get translatable field names (snake_case) for a schema. */
|
|
51
|
+
getTranslatableFields(schemaName: string): string[];
|
|
50
52
|
}
|
|
@@ -158,4 +158,20 @@ export class SchemaReader {
|
|
|
158
158
|
const schema = this.getSchema(schemaName);
|
|
159
159
|
return schema?.tableName ?? '';
|
|
160
160
|
}
|
|
161
|
+
/** Get translatable field names (snake_case) for a schema. */
|
|
162
|
+
getTranslatableFields(schemaName) {
|
|
163
|
+
const schema = this.getSchema(schemaName);
|
|
164
|
+
if (!schema?.properties)
|
|
165
|
+
return [];
|
|
166
|
+
const fields = [];
|
|
167
|
+
const propertyOrder = this.getPropertyOrder(schemaName);
|
|
168
|
+
for (const propName of propertyOrder) {
|
|
169
|
+
const prop = schema.properties[propName];
|
|
170
|
+
if (prop?.translatable) {
|
|
171
|
+
// Convert to snake_case
|
|
172
|
+
fields.push(propName.replace(/([A-Z])/g, (_, c, i) => (i > 0 ? '_' : '') + c.toLowerCase()));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return fields;
|
|
176
|
+
}
|
|
161
177
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates {ModelName}TranslationBaseModel and {ModelName}Translation
|
|
3
|
+
* for schemas that have translatable properties.
|
|
4
|
+
*
|
|
5
|
+
* Follows Astrotomic/laravel-translatable convention:
|
|
6
|
+
* - Translation model class: {ModelName}Translation
|
|
7
|
+
* - $timestamps = false
|
|
8
|
+
* - $fillable = [translatable field names]
|
|
9
|
+
*/
|
|
10
|
+
import { SchemaReader } from './schema-reader.js';
|
|
11
|
+
import type { GeneratedFile, PhpConfig } from './types.js';
|
|
12
|
+
/** Generate translation model files for all project schemas with translatable fields. */
|
|
13
|
+
export declare function generateTranslationModels(reader: SchemaReader, config: PhpConfig): GeneratedFile[];
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates {ModelName}TranslationBaseModel and {ModelName}Translation
|
|
3
|
+
* for schemas that have translatable properties.
|
|
4
|
+
*
|
|
5
|
+
* Follows Astrotomic/laravel-translatable convention:
|
|
6
|
+
* - Translation model class: {ModelName}Translation
|
|
7
|
+
* - $timestamps = false
|
|
8
|
+
* - $fillable = [translatable field names]
|
|
9
|
+
*/
|
|
10
|
+
import { toPascalCase, toSnakeCase } from './naming-helper.js';
|
|
11
|
+
import { baseFile, userFile } from './types.js';
|
|
12
|
+
/** Generate translation model files for all project schemas with translatable fields. */
|
|
13
|
+
export function generateTranslationModels(reader, config) {
|
|
14
|
+
const files = [];
|
|
15
|
+
for (const [name] of Object.entries(reader.getProjectObjectSchemas())) {
|
|
16
|
+
const translatableFields = reader.getTranslatableFields(name);
|
|
17
|
+
if (translatableFields.length === 0)
|
|
18
|
+
continue;
|
|
19
|
+
files.push(generateTranslationBaseModel(name, translatableFields, config));
|
|
20
|
+
files.push(generateTranslationUserModel(name, config));
|
|
21
|
+
}
|
|
22
|
+
return files;
|
|
23
|
+
}
|
|
24
|
+
function generateTranslationBaseModel(name, translatableFields, config) {
|
|
25
|
+
const modelName = toPascalCase(name);
|
|
26
|
+
const modelSnake = toSnakeCase(name);
|
|
27
|
+
const baseNamespace = config.models.baseNamespace;
|
|
28
|
+
const tableName = `${modelSnake}_translations`;
|
|
29
|
+
const fillableLines = translatableFields
|
|
30
|
+
.map(f => ` '${f}',`)
|
|
31
|
+
.join('\n');
|
|
32
|
+
const content = `<?php
|
|
33
|
+
|
|
34
|
+
namespace ${baseNamespace};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* DO NOT EDIT - This file is auto-generated by Omnify.
|
|
38
|
+
* Any changes will be overwritten on next generation.
|
|
39
|
+
*
|
|
40
|
+
* @generated by omnify
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
use Illuminate\\Database\\Eloquent\\Model;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* ${modelName}TranslationBaseModel
|
|
47
|
+
*/
|
|
48
|
+
class ${modelName}TranslationBaseModel extends Model
|
|
49
|
+
{
|
|
50
|
+
/**
|
|
51
|
+
* The table associated with the model.
|
|
52
|
+
*/
|
|
53
|
+
protected $table = '${tableName}';
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Indicates if the model should be timestamped.
|
|
57
|
+
*/
|
|
58
|
+
public $timestamps = false;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The attributes that are mass assignable.
|
|
62
|
+
*/
|
|
63
|
+
protected $fillable = [
|
|
64
|
+
${fillableLines}
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
`;
|
|
68
|
+
return baseFile(`${config.models.basePath}/${modelName}TranslationBaseModel.php`, content);
|
|
69
|
+
}
|
|
70
|
+
function generateTranslationUserModel(name, config) {
|
|
71
|
+
const modelName = toPascalCase(name);
|
|
72
|
+
const modelNamespace = config.models.namespace;
|
|
73
|
+
const baseNamespace = config.models.baseNamespace;
|
|
74
|
+
const content = `<?php
|
|
75
|
+
|
|
76
|
+
namespace ${modelNamespace};
|
|
77
|
+
|
|
78
|
+
use ${baseNamespace}\\${modelName}TranslationBaseModel;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* ${modelName}Translation Model
|
|
82
|
+
*
|
|
83
|
+
* This file is generated once and can be customized.
|
|
84
|
+
* Add your custom methods and logic here.
|
|
85
|
+
*/
|
|
86
|
+
class ${modelName}Translation extends ${modelName}TranslationBaseModel
|
|
87
|
+
{
|
|
88
|
+
// Add your custom methods here
|
|
89
|
+
}
|
|
90
|
+
`;
|
|
91
|
+
return userFile(`${config.models.path}/${modelName}Translation.php`, content);
|
|
92
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -144,6 +144,7 @@ export interface PropertyDefinition {
|
|
|
144
144
|
readonly nullable?: boolean;
|
|
145
145
|
readonly unique?: boolean;
|
|
146
146
|
readonly primary?: boolean;
|
|
147
|
+
readonly translatable?: boolean;
|
|
147
148
|
readonly default?: unknown;
|
|
148
149
|
readonly length?: number;
|
|
149
150
|
readonly minLength?: number;
|