@omnifyjp/ts 5.8.4 → 5.8.5

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.
@@ -111,7 +111,7 @@ function generateBaseModel(name, schema, reader, config) {
111
111
  const hidden = buildHidden(properties, expandedProperties, propertyOrder);
112
112
  const appends = buildAppends(expandedProperties);
113
113
  const casts = buildCasts(properties, expandedProperties, propertyOrder, reader, config);
114
- const relations = buildRelations(name, properties, propertyOrder, modelNamespace, reader);
114
+ const relations = buildRelations(name, properties, propertyOrder, modelNamespace, reader, config);
115
115
  const accessors = buildAccessors(expandedProperties);
116
116
  const fileAccessors = hasFiles ? buildFileAccessors(properties, propertyOrder, modelNamespace) : '';
117
117
  const auditSection = buildAuditSection(options, reader, modelNamespace);
@@ -578,7 +578,42 @@ function buildCasts(properties, expandedProperties, propertyOrder, reader, confi
578
578
  return '';
579
579
  return casts.map(c => ` ${c}`).join('\n') + '\n';
580
580
  }
581
- function buildRelations(schemaName, properties, propertyOrder, modelNamespace, reader) {
581
+ /**
582
+ * Issue #98 v5.8.6: resolve the FQCN namespace of a related Model
583
+ * for inline `belongsTo / hasMany / belongsToMany / morphTo` references.
584
+ * The namespace must match the TARGET's actual file location, not the
585
+ * source schema's. Three knobs:
586
+ * 1. Package schemas — return the package's namespace verbatim
587
+ * (already handled by reader.resolveModelNamespace).
588
+ * 2. Pivot schemas — always nest under `Pivot/` regardless of any
589
+ * group / userEditableGroupByFolder setting.
590
+ * 3. Group nesting — only when `userEditableGroupByFolder: true`
591
+ * (matches where the editable lives so the relation resolves to
592
+ * the user's customizable class). Default off → flat FQCN
593
+ * matches the Laravel-canonical flat editable layout.
594
+ *
595
+ * Pre-fix every relation emitted `\${modelNamespace}\${target}::class`
596
+ * (flat FQCN) regardless of where the target's file actually lived.
597
+ * For grouped projects this dispatched to a non-existent class at
598
+ * runtime — `ErrorException: include(... no such file)`.
599
+ */
600
+ function resolveRelatedModelNamespace(target, modelNamespace, config, reader) {
601
+ const baseNs = reader.resolveModelNamespace(target, modelNamespace);
602
+ // Package schemas — leave as-is.
603
+ if (baseNs !== modelNamespace)
604
+ return baseNs;
605
+ const targetSchema = reader.getSchema(target);
606
+ if (!targetSchema)
607
+ return baseNs;
608
+ if (targetSchema.kind === 'pivot') {
609
+ return `${baseNs}\\Pivot`;
610
+ }
611
+ if (config.models.userEditableGroupByFolder && targetSchema.group) {
612
+ return `${baseNs}\\${toPascalCase(targetSchema.group)}`;
613
+ }
614
+ return baseNs;
615
+ }
616
+ function buildRelations(schemaName, properties, propertyOrder, modelNamespace, reader, config) {
582
617
  const methods = [];
583
618
  const sourceTableName = reader.getTableName(schemaName);
584
619
  // Track method names already declared on this model so reverse-relation
@@ -591,9 +626,11 @@ function buildRelations(schemaName, properties, propertyOrder, modelNamespace, r
591
626
  const prop = properties[propName];
592
627
  if (!prop || prop['type'] !== 'Association')
593
628
  continue;
594
- // Resolve namespace per-target (package schemas use their own namespace)
629
+ // Resolve namespace per-target (package schemas use their own namespace).
630
+ // Issue #98 v5.8.6: also nest by target's group / Pivot/ so the
631
+ // FQCN matches the target file's actual location.
595
632
  const target = prop['target'] ?? '';
596
- const ns = target ? reader.resolveModelNamespace(target, modelNamespace) : modelNamespace;
633
+ const ns = target ? resolveRelatedModelNamespace(target, modelNamespace, config, reader) : modelNamespace;
597
634
  const targetTableName = target ? reader.getTableName(target) : '';
598
635
  // For ManyToMany, look up the explicit `kind: pivot` schema (the
599
636
  // sorted PascalCase concat of source + target — auto-created on
@@ -623,7 +660,7 @@ function buildRelations(schemaName, properties, propertyOrder, modelNamespace, r
623
660
  // Auto-generate reverse HasMany/HasOne for any child schema that declares a
624
661
  // ManyToOne/OneToOne pointing at this schema, unless the user has already
625
662
  // declared a relation method with the same name. Issue #39.
626
- const inverseRelations = buildInverseRelations(schemaName, modelNamespace, reader, declaredMethods, explicitInverses);
663
+ const inverseRelations = buildInverseRelations(schemaName, modelNamespace, reader, declaredMethods, explicitInverses, config);
627
664
  if (inverseRelations) {
628
665
  methods.push(inverseRelations);
629
666
  }
@@ -666,7 +703,7 @@ const LARAVEL_RESERVED_RELATION_NAMES = new Set([
666
703
  * a unique method name, or add `mappedBy: <customName>` to the child schema
667
704
  * so the derived method name changes.
668
705
  */
669
- function buildInverseRelations(parentName, modelNamespace, reader, declaredMethods, explicitInverses) {
706
+ function buildInverseRelations(parentName, modelNamespace, reader, declaredMethods, explicitInverses, config) {
670
707
  const methods = [];
671
708
  const allSchemas = reader.getSchemas();
672
709
  // Stable iteration order — sort child names so output is deterministic
@@ -714,7 +751,11 @@ function buildInverseRelations(parentName, modelNamespace, reader, declaredMetho
714
751
  // Here we're emitting the *parent* accessor, so the child's ManyToOne
715
752
  // (or owning OneToOne) is what we react to.
716
753
  const fkColumn = `${toSnakeCase(childPropName)}_id`;
717
- const childNs = reader.resolveModelNamespace(childName, modelNamespace);
754
+ // Issue #98 v5.8.6: nest the inverse-side FQCN by the CHILD's
755
+ // group / Pivot/ so the relation resolves to the child's actual
756
+ // file location (which lives in `<childGroup>/<Child>.php` or
757
+ // `Pivot/<Child>.php`, not flat).
758
+ const childNs = resolveRelatedModelNamespace(childName, modelNamespace, config, reader);
718
759
  const fqcn = `\\${childNs}\\${childName}`;
719
760
  const returnType = isOneToOne ? 'HasOne' : 'HasMany';
720
761
  const eloquentMethod = isOneToOne ? 'hasOne' : 'hasMany';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnifyjp/ts",
3
- "version": "5.8.4",
3
+ "version": "5.8.5",
4
4
  "description": "TypeScript model type generator from Omnify schemas.json",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",