@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 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 imports = buildImports(baseNamespace, modelName, hasSoftDelete, isAuthenticatable, properties);
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 traits = buildTraits(hasSoftDelete, isAuthenticatable);
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnifyjp/ts",
3
- "version": "1.0.3",
3
+ "version": "1.1.1",
4
4
  "description": "TypeScript model type generator from Omnify schemas.json",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",