@omnifyjp/ts 3.21.2 → 3.22.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
|
@@ -26,6 +26,7 @@ import { generateFileModels } from './file-model-generator.js';
|
|
|
26
26
|
import { generateFileTrait } from './file-trait-generator.js';
|
|
27
27
|
import { generateFileCleanup } from './file-cleanup-generator.js';
|
|
28
28
|
import { generateSchemaConfig } from './schema-config-generator.js';
|
|
29
|
+
import { generateTranslatableConfig } from './translatable-config-generator.js';
|
|
29
30
|
import { baseFile } from './types.js';
|
|
30
31
|
import { generateControllers } from './controller-generator.js';
|
|
31
32
|
import { generateServices } from './service-generator.js';
|
|
@@ -73,6 +74,12 @@ export function generatePhp(data, overrides) {
|
|
|
73
74
|
}
|
|
74
75
|
// Issue #34: every `kind: enum` schema becomes a global PHP enum class.
|
|
75
76
|
files.push(...generateEnums(reader, config));
|
|
77
|
+
// Astrotomic translatable config (only when at least one schema has
|
|
78
|
+
// translatable fields). Closes the silent footgun where the vendor
|
|
79
|
+
// default config shipped with Astrotomic only supports ['en', 'fr', 'es']
|
|
80
|
+
// and the generator's flat `attr:locale` form would be dropped for any
|
|
81
|
+
// locale outside that list.
|
|
82
|
+
files.push(...generateTranslatableConfig(reader, config));
|
|
76
83
|
// Per-schema files
|
|
77
84
|
files.push(...generateLocales(reader, config));
|
|
78
85
|
files.push(...generateModels(reader, config));
|
|
@@ -524,11 +524,42 @@ function buildRelations(schemaName, properties, propertyOrder, modelNamespace, r
|
|
|
524
524
|
}
|
|
525
525
|
return methods.join('\n');
|
|
526
526
|
}
|
|
527
|
+
/**
|
|
528
|
+
* Method names that belong to Laravel trait authors and will break PHP's
|
|
529
|
+
* method-declaration rules if a generated relation shadows them. Caught in
|
|
530
|
+
* practice when `NotificationExtend.yaml` added a reverse relation called
|
|
531
|
+
* `notifications()` on User, which collides with `Notifiable::notifications()`
|
|
532
|
+
* — the class fails to load with a "Declaration must be compatible" fatal.
|
|
533
|
+
*
|
|
534
|
+
* Keep this tight — only names we've actually seen collide in shipped
|
|
535
|
+
* Laravel traits. False positives here would silently drop valid relations,
|
|
536
|
+
* so err on the side of under-reserving.
|
|
537
|
+
*/
|
|
538
|
+
const LARAVEL_RESERVED_RELATION_NAMES = new Set([
|
|
539
|
+
// Illuminate\Notifications\Notifiable
|
|
540
|
+
'notifications',
|
|
541
|
+
'readNotifications',
|
|
542
|
+
'unreadNotifications',
|
|
543
|
+
// Laravel Sanctum / Passport
|
|
544
|
+
'tokens',
|
|
545
|
+
// Laravel Scout (rare but would conflict on searchable models)
|
|
546
|
+
'searchableAs',
|
|
547
|
+
// Spatie Permission (common enough to pre-reserve)
|
|
548
|
+
'roles',
|
|
549
|
+
'permissions',
|
|
550
|
+
]);
|
|
527
551
|
/**
|
|
528
552
|
* Discover child schemas that point at `parentName` via ManyToOne/OneToOne and
|
|
529
553
|
* generate the corresponding HasMany/HasOne accessor on the parent. Skips any
|
|
530
554
|
* inverse relation whose derived method name collides with a user-declared
|
|
531
555
|
* relation. Issue #39.
|
|
556
|
+
*
|
|
557
|
+
* Also skips + warns when the derived method name collides with a well-known
|
|
558
|
+
* Laravel trait method (e.g. Notifiable::notifications), since silently
|
|
559
|
+
* shadowing those produces a PHP fatal at class load time. Users who need
|
|
560
|
+
* the relation should declare it explicitly in the editable {Name}.php with
|
|
561
|
+
* a unique method name, or add `mappedBy: <customName>` to the child schema
|
|
562
|
+
* so the derived method name changes.
|
|
532
563
|
*/
|
|
533
564
|
function buildInverseRelations(parentName, modelNamespace, reader, declaredMethods, explicitInverses) {
|
|
534
565
|
const methods = [];
|
|
@@ -561,6 +592,17 @@ function buildInverseRelations(parentName, modelNamespace, reader, declaredMetho
|
|
|
561
592
|
: toCamelCase(pluralize(childName));
|
|
562
593
|
if (declaredMethods.has(methodName))
|
|
563
594
|
continue;
|
|
595
|
+
// Reserved-name collision guard: Laravel trait methods like
|
|
596
|
+
// Notifiable::notifications() cannot be safely shadowed. Skip + warn.
|
|
597
|
+
if (LARAVEL_RESERVED_RELATION_NAMES.has(methodName)) {
|
|
598
|
+
console.warn(`[omnify-ts] ${parentName}: skipping auto-generated inverse relation ` +
|
|
599
|
+
`'${methodName}()' from ${childName}.${childPropName} — name collides ` +
|
|
600
|
+
`with a Laravel trait method (e.g. Notifiable::${methodName}). ` +
|
|
601
|
+
`Fix: add 'mappedBy: <customName>' to ${childName}.${childPropName} ` +
|
|
602
|
+
`in your schema so the derived method name changes, or declare the ` +
|
|
603
|
+
`relation manually in the editable ${parentName}.php with a unique name.`);
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
564
606
|
declaredMethods.add(methodName);
|
|
565
607
|
// OneToOne with mappedBy is the reverse side already — skip; it would
|
|
566
608
|
// generate a child-side accessor, not a parent-side one.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates `config/translatable.php` from the project's omnify locale config.
|
|
3
|
+
*
|
|
4
|
+
* Addresses a gap caught while writing the #75–#79 service base E2E tests
|
|
5
|
+
* in l12: Astrotomic's vendor default config only ships `['en', 'fr', 'es']`
|
|
6
|
+
* as supported locales. Consumers using `ja` / `vi` / `ko` / etc. hit a
|
|
7
|
+
* silent footgun — `Translatable::fill(['title:ja' => '...'])` drops the key
|
|
8
|
+
* because `getLocalesHelper()->has('ja')` returns false, producing NULL
|
|
9
|
+
* translations at runtime with no error.
|
|
10
|
+
*
|
|
11
|
+
* This generator emits a ready-to-commit `config/translatable.php` wired to
|
|
12
|
+
* the locales declared in `omnify.yaml` under `locale.locales`. It's only
|
|
13
|
+
* written when the project actually has a schema with translatable fields
|
|
14
|
+
* (no point in rewriting the config if nothing would consume it).
|
|
15
|
+
*
|
|
16
|
+
* The file is marked `overwrite: true` — it's a base file in Omnify's sense:
|
|
17
|
+
* when locales change in omnify.yaml, the config should follow automatically.
|
|
18
|
+
* Consumers that need per-project overrides can copy it to a different name
|
|
19
|
+
* or extend it via Laravel's config merging.
|
|
20
|
+
*/
|
|
21
|
+
import type { SchemaReader } from './schema-reader.js';
|
|
22
|
+
import type { GeneratedFile, PhpConfig } from './types.js';
|
|
23
|
+
export declare function generateTranslatableConfig(reader: SchemaReader, _config: PhpConfig): GeneratedFile[];
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates `config/translatable.php` from the project's omnify locale config.
|
|
3
|
+
*
|
|
4
|
+
* Addresses a gap caught while writing the #75–#79 service base E2E tests
|
|
5
|
+
* in l12: Astrotomic's vendor default config only ships `['en', 'fr', 'es']`
|
|
6
|
+
* as supported locales. Consumers using `ja` / `vi` / `ko` / etc. hit a
|
|
7
|
+
* silent footgun — `Translatable::fill(['title:ja' => '...'])` drops the key
|
|
8
|
+
* because `getLocalesHelper()->has('ja')` returns false, producing NULL
|
|
9
|
+
* translations at runtime with no error.
|
|
10
|
+
*
|
|
11
|
+
* This generator emits a ready-to-commit `config/translatable.php` wired to
|
|
12
|
+
* the locales declared in `omnify.yaml` under `locale.locales`. It's only
|
|
13
|
+
* written when the project actually has a schema with translatable fields
|
|
14
|
+
* (no point in rewriting the config if nothing would consume it).
|
|
15
|
+
*
|
|
16
|
+
* The file is marked `overwrite: true` — it's a base file in Omnify's sense:
|
|
17
|
+
* when locales change in omnify.yaml, the config should follow automatically.
|
|
18
|
+
* Consumers that need per-project overrides can copy it to a different name
|
|
19
|
+
* or extend it via Laravel's config merging.
|
|
20
|
+
*/
|
|
21
|
+
import { baseFile } from './types.js';
|
|
22
|
+
export function generateTranslatableConfig(reader, _config) {
|
|
23
|
+
// Only emit when at least one schema has translatable fields — otherwise
|
|
24
|
+
// the file would just be dead weight in projects that don't use i18n.
|
|
25
|
+
const objectSchemas = reader.getProjectObjectSchemas();
|
|
26
|
+
let hasAnyTranslatable = false;
|
|
27
|
+
for (const name of Object.keys(objectSchemas)) {
|
|
28
|
+
if (reader.getTranslatableFields(name).length > 0) {
|
|
29
|
+
hasAnyTranslatable = true;
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (!hasAnyTranslatable) {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
const locales = reader.getLocales();
|
|
37
|
+
if (locales.length === 0) {
|
|
38
|
+
// Nothing we can honestly write — fall back to Astrotomic's own default.
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
const defaultLocale = reader.getDefaultLocale();
|
|
42
|
+
// Astrotomic has a separate fallback_locale config — prefer the omnify
|
|
43
|
+
// `fallbackLocale` if set, otherwise fall back to the same defaultLocale.
|
|
44
|
+
const fallbackLocale = reader.getLocale()?.fallbackLocale ?? defaultLocale;
|
|
45
|
+
const localesPhp = locales.map(l => ` '${l}',`).join('\n');
|
|
46
|
+
const content = `<?php
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* DO NOT EDIT - This file is auto-generated by Omnify from omnify.yaml's
|
|
50
|
+
* \`locale.locales\` config. Any manual changes will be overwritten on the
|
|
51
|
+
* next \`omnify generate\`.
|
|
52
|
+
*
|
|
53
|
+
* Consumers that need per-project overrides should use Laravel's config
|
|
54
|
+
* merging or a separate config file.
|
|
55
|
+
*
|
|
56
|
+
* @generated by omnify
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
return [
|
|
60
|
+
|
|
61
|
+
/*
|
|
62
|
+
|--------------------------------------------------------------------------
|
|
63
|
+
| Application Locales
|
|
64
|
+
|--------------------------------------------------------------------------
|
|
65
|
+
|
|
|
66
|
+
| Emitted from \`locale.locales\` in omnify.yaml. Adding or removing
|
|
67
|
+
| locales here without editing omnify.yaml first will be overwritten
|
|
68
|
+
| on the next generation.
|
|
69
|
+
|
|
|
70
|
+
*/
|
|
71
|
+
'locales' => [
|
|
72
|
+
${localesPhp}
|
|
73
|
+
],
|
|
74
|
+
|
|
75
|
+
/*
|
|
76
|
+
|--------------------------------------------------------------------------
|
|
77
|
+
| Locale separator
|
|
78
|
+
|--------------------------------------------------------------------------
|
|
79
|
+
*/
|
|
80
|
+
'locale_separator' => '-',
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
|--------------------------------------------------------------------------
|
|
84
|
+
| Default locale
|
|
85
|
+
|--------------------------------------------------------------------------
|
|
86
|
+
*/
|
|
87
|
+
'default_locale' => '${defaultLocale}',
|
|
88
|
+
|
|
89
|
+
/*
|
|
90
|
+
|--------------------------------------------------------------------------
|
|
91
|
+
| Translator
|
|
92
|
+
|--------------------------------------------------------------------------
|
|
93
|
+
*/
|
|
94
|
+
'translator' => null,
|
|
95
|
+
|
|
96
|
+
/*
|
|
97
|
+
|--------------------------------------------------------------------------
|
|
98
|
+
| Use fallback
|
|
99
|
+
|--------------------------------------------------------------------------
|
|
100
|
+
|
|
|
101
|
+
| Enabled so that missing translations transparently fall back to the
|
|
102
|
+
| configured fallback_locale. Without this, attributesToArray() returns
|
|
103
|
+
| NULL for untranslated attributes instead of using the fallback row —
|
|
104
|
+
| which would surface as blank dropdown labels in multi-locale projects.
|
|
105
|
+
|
|
|
106
|
+
*/
|
|
107
|
+
'use_fallback' => true,
|
|
108
|
+
|
|
109
|
+
/*
|
|
110
|
+
|--------------------------------------------------------------------------
|
|
111
|
+
| Use property fallback
|
|
112
|
+
|--------------------------------------------------------------------------
|
|
113
|
+
*/
|
|
114
|
+
'use_property_fallback' => true,
|
|
115
|
+
|
|
116
|
+
/*
|
|
117
|
+
|--------------------------------------------------------------------------
|
|
118
|
+
| Fallback locale
|
|
119
|
+
|--------------------------------------------------------------------------
|
|
120
|
+
*/
|
|
121
|
+
'fallback_locale' => '${fallbackLocale}',
|
|
122
|
+
|
|
123
|
+
/*
|
|
124
|
+
|--------------------------------------------------------------------------
|
|
125
|
+
| Translation model namespace
|
|
126
|
+
|--------------------------------------------------------------------------
|
|
127
|
+
*/
|
|
128
|
+
'translation_model_namespace' => null,
|
|
129
|
+
|
|
130
|
+
/*
|
|
131
|
+
|--------------------------------------------------------------------------
|
|
132
|
+
| Translation suffix
|
|
133
|
+
|--------------------------------------------------------------------------
|
|
134
|
+
*/
|
|
135
|
+
'translation_suffix' => 'Translation',
|
|
136
|
+
|
|
137
|
+
/*
|
|
138
|
+
|--------------------------------------------------------------------------
|
|
139
|
+
| Locale key
|
|
140
|
+
|--------------------------------------------------------------------------
|
|
141
|
+
*/
|
|
142
|
+
'locale_key' => 'locale',
|
|
143
|
+
|
|
144
|
+
/*
|
|
145
|
+
|--------------------------------------------------------------------------
|
|
146
|
+
| To array always loads translations
|
|
147
|
+
|--------------------------------------------------------------------------
|
|
148
|
+
|
|
|
149
|
+
| When true, calling toArray() on a model auto-loads its translations.
|
|
150
|
+
| Keeps paginator results self-contained for JSON API responses.
|
|
151
|
+
|
|
|
152
|
+
*/
|
|
153
|
+
'to_array_always_loads_translations' => true,
|
|
154
|
+
|
|
155
|
+
/*
|
|
156
|
+
|--------------------------------------------------------------------------
|
|
157
|
+
| Rule factory
|
|
158
|
+
|--------------------------------------------------------------------------
|
|
159
|
+
*/
|
|
160
|
+
'rule_factory' => [
|
|
161
|
+
'format' => 0, // Astrotomic\Translatable\Validation\RuleFactory::FORMAT_ARRAY
|
|
162
|
+
'prefix' => '%',
|
|
163
|
+
'suffix' => '%',
|
|
164
|
+
],
|
|
165
|
+
];
|
|
166
|
+
`;
|
|
167
|
+
return [baseFile('config/translatable.php', content)];
|
|
168
|
+
}
|