@omnifyjp/ts 1.3.0 → 1.3.2

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 CHANGED
@@ -54,18 +54,18 @@ function generateBaseInterfaceFile(schemaName, schemas, options) {
54
54
  if (dateImports.date)
55
55
  commonImports.push('DateString');
56
56
  if (commonImports.length > 0) {
57
- parts.push(`import type { ${commonImports.join(', ')} } from '../common.js';\n`);
57
+ parts.push(`import type { ${commonImports.join(', ')} } from '../common';\n`);
58
58
  }
59
59
  // Enum imports (schema enums + plugin enums are all in ../enum/)
60
60
  if (iface.enumDependencies && iface.enumDependencies.length > 0) {
61
61
  for (const enumName of iface.enumDependencies) {
62
- parts.push(`import { ${enumName} } from '../enum/${enumName}.js';\n`);
62
+ parts.push(`import { ${enumName} } from '../enum/${enumName}';\n`);
63
63
  }
64
64
  }
65
65
  // Dependency imports (other schema interfaces in base/)
66
66
  if (iface.dependencies && iface.dependencies.length > 0) {
67
67
  for (const dep of iface.dependencies) {
68
- parts.push(`import type { ${dep} } from './${dep}.js';\n`);
68
+ parts.push(`import type { ${dep} } from './${dep}';\n`);
69
69
  }
70
70
  parts.push('\n');
71
71
  }
@@ -170,7 +170,7 @@ function generateIndexFile(schemas, schemaEnums, pluginEnums, typeAliases) {
170
170
  const parts = [generateBaseHeader()];
171
171
  // Common types
172
172
  parts.push(`// Common Types\n`);
173
- parts.push(`export type { LocaleMap, Locale, DateTimeString, DateString } from './common.js';\n\n`);
173
+ parts.push(`export type { LocaleMap, Locale, DateTimeString, DateString } from './common';\n\n`);
174
174
  // I18n
175
175
  parts.push(`// i18n (Internationalization)\n`);
176
176
  parts.push(`export {\n`);
@@ -180,7 +180,7 @@ function generateIndexFile(schemas, schemaEnums, pluginEnums, typeAliases) {
180
180
  parts.push(` validationMessages,\n`);
181
181
  parts.push(` getMessage,\n`);
182
182
  parts.push(` getMessages,\n`);
183
- parts.push(`} from './i18n.js';\n\n`);
183
+ parts.push(`} from './i18n';\n\n`);
184
184
  // Schema enums
185
185
  if (schemaEnums.length > 0) {
186
186
  parts.push(`// Schema Enums\n`);
@@ -191,7 +191,7 @@ function generateIndexFile(schemas, schemaEnums, pluginEnums, typeAliases) {
191
191
  parts.push(` is${enumDef.name},\n`);
192
192
  parts.push(` get${enumDef.name}Label,\n`);
193
193
  parts.push(` get${enumDef.name}Extra,\n`);
194
- parts.push(`} from './enum/${enumDef.name}.js';\n`);
194
+ parts.push(`} from './enum/${enumDef.name}';\n`);
195
195
  }
196
196
  parts.push('\n');
197
197
  }
@@ -205,7 +205,7 @@ function generateIndexFile(schemas, schemaEnums, pluginEnums, typeAliases) {
205
205
  parts.push(` is${enumDef.name},\n`);
206
206
  parts.push(` get${enumDef.name}Label,\n`);
207
207
  parts.push(` get${enumDef.name}Extra,\n`);
208
- parts.push(`} from './enum/${enumDef.name}.js';\n`);
208
+ parts.push(`} from './enum/${enumDef.name}';\n`);
209
209
  }
210
210
  parts.push('\n');
211
211
  }
@@ -219,7 +219,7 @@ function generateIndexFile(schemas, schemaEnums, pluginEnums, typeAliases) {
219
219
  parts.push(` is${alias.name},\n`);
220
220
  parts.push(` get${alias.name}Label,\n`);
221
221
  parts.push(` get${alias.name}Extra,\n`);
222
- parts.push(`} from './enum/${alias.name}.js';\n`);
222
+ parts.push(`} from './enum/${alias.name}';\n`);
223
223
  }
224
224
  parts.push('\n');
225
225
  }
@@ -231,7 +231,7 @@ function generateIndexFile(schemas, schemaEnums, pluginEnums, typeAliases) {
231
231
  if (schema.options?.hidden === true)
232
232
  continue;
233
233
  const lowerName = schema.name.charAt(0).toLowerCase() + schema.name.slice(1);
234
- parts.push(`export type { ${schema.name}, ${schema.name}Create, ${schema.name}Update } from './${schema.name}.js';\n`);
234
+ parts.push(`export type { ${schema.name}, ${schema.name}Create, ${schema.name}Update } from './${schema.name}';\n`);
235
235
  parts.push(`export {\n`);
236
236
  parts.push(` ${lowerName}Schemas,\n`);
237
237
  parts.push(` ${lowerName}CreateSchema,\n`);
@@ -240,7 +240,7 @@ function generateIndexFile(schemas, schemaEnums, pluginEnums, typeAliases) {
240
240
  parts.push(` get${schema.name}Label,\n`);
241
241
  parts.push(` get${schema.name}FieldLabel,\n`);
242
242
  parts.push(` get${schema.name}FieldPlaceholder,\n`);
243
- parts.push(`} from './${schema.name}.js';\n`);
243
+ parts.push(`} from './${schema.name}';\n`);
244
244
  }
245
245
  return {
246
246
  filePath: 'index.ts',
@@ -80,7 +80,7 @@ export function generateI18nFileContent(options) {
80
80
  }
81
81
  }
82
82
  const messagesJson = JSON.stringify(filteredMessages, null, 2);
83
- return `import type { LocaleMap } from './common.js';
83
+ return `import type { LocaleMap } from './common';
84
84
 
85
85
  /**
86
86
  * Default locale for this project.
@@ -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,7 +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;
43
- const hasNestedSet = options['nestedSet'] ?? false;
46
+ // NodeTrait is added to the user-editable Model, not BaseModel
47
+ const hasNestedSet = false;
48
+ const nestedSetParentColumn = null;
44
49
  const translatableFields = reader.getTranslatableFields(name);
45
50
  const hasTranslatable = translatableFields.length > 0;
46
51
  const primaryKey = options['primaryKey'] ?? 'id';
@@ -60,6 +65,7 @@ function generateBaseModel(name, schema, reader, config) {
60
65
  const casts = buildCasts(properties, expandedProperties, propertyOrder);
61
66
  const relations = buildRelations(name, properties, propertyOrder, modelNamespace, reader);
62
67
  const accessors = buildAccessors(expandedProperties);
68
+ const nestedSetMethod = buildNestedSetParentIdMethod(nestedSetParentColumn);
63
69
  let keyTypeSection = '';
64
70
  if (idType === 'Uuid' || idType === 'Ulid' || idType === 'String') {
65
71
  keyTypeSection = `
@@ -156,16 +162,29 @@ ${appends} ];
156
162
  return [
157
163
  ${casts} ];
158
164
  }
159
- ${relations}${accessors}
165
+ ${relations}${accessors}${nestedSetMethod}
160
166
  }
161
167
  `;
162
168
  return baseFile(`${config.models.basePath}/${modelName}BaseModel.php`, content);
163
169
  }
164
- function generateUserModel(name, config) {
170
+ function generateUserModel(name, config, hasNestedSet = false) {
165
171
  const modelName = toPascalCase(name);
166
172
  const modelNamespace = config.models.namespace;
167
173
  const baseNamespace = config.models.baseNamespace;
168
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
+ }
169
188
  const content = `<?php
170
189
 
171
190
  /**
@@ -176,16 +195,14 @@ function generateUserModel(name, config) {
176
195
 
177
196
  namespace ${modelNamespace};
178
197
 
179
- use ${baseNamespace}\\${modelName}BaseModel;
180
- use ${factoryNamespace}\\${modelName}Factory;
181
- use Illuminate\\Database\\Eloquent\\Factories\\HasFactory;
198
+ ${imports.join('\n')}
182
199
 
183
200
  /**
184
201
  * ${modelName} — add project-specific model logic here.
185
202
  */
186
203
  class ${modelName} extends ${modelName}BaseModel
187
204
  {
188
- use HasFactory;
205
+ ${traits.join('\n')}
189
206
 
190
207
  /**
191
208
  * Create a new factory instance for the model.
@@ -461,6 +478,50 @@ class ${modelName} extends Package${modelName}
461
478
  `;
462
479
  return userFile(`${config.models.path}/${modelName}.php`, content);
463
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
+ }
464
525
  function fullNameAccessor(prefix, suffix, fields, separator) {
465
526
  const methodName = 'get' + toPascalCase(prefix) + suffix + 'Attribute';
466
527
  const fieldAccess = fields.map(f => `$this->${f}`).join(', ');
@@ -489,7 +489,7 @@ export function formatZodModelFile(schemaName) {
489
489
  */
490
490
 
491
491
  import { z } from 'zod';
492
- import type { ${schemaName} as ${schemaName}Base } from './base/${schemaName}.js';
492
+ import type { ${schemaName} as ${schemaName}Base } from './base/${schemaName}';
493
493
  import {
494
494
  base${schemaName}Schemas,
495
495
  base${schemaName}CreateSchema,
@@ -498,7 +498,7 @@ import {
498
498
  get${schemaName}Label,
499
499
  get${schemaName}FieldLabel,
500
500
  get${schemaName}FieldPlaceholder,
501
- } from './base/${schemaName}.js';
501
+ } from './base/${schemaName}';
502
502
 
503
503
  // ============================================================================
504
504
  // Types (extend or re-export)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnifyjp/ts",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "TypeScript model type generator from Omnify schemas.json",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",