@omnifyjp/ts 7.2.1 → 7.3.0
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/openapi-generator.js +1 -1
- package/dist/php/request-generator.js +13 -5
- package/dist/php/resource-generator.js +44 -7
- package/dist/php/schema-reader.d.ts +5 -0
- package/dist/php/service-generator.js +13 -5
- package/dist/php/translatable-config-generator.d.ts +1 -1
- package/dist/php/translatable-config-generator.js +14 -5
- package/dist/php/translation-model-generator.d.ts +6 -0
- package/dist/php/translation-model-generator.js +11 -3
- package/dist/types.d.ts +8 -0
- package/package.json +1 -1
|
@@ -427,7 +427,7 @@ export function buildControllerMethodAttributes(config, schema, modelName, schem
|
|
|
427
427
|
parameters: [
|
|
428
428
|
new OA\\Parameter(name: 'search', in: 'query', required: false, schema: new OA\\Schema(type: 'string')),
|
|
429
429
|
new OA\\Parameter(name: 'sort', in: 'query', required: false, schema: new OA\\Schema(type: 'string')),
|
|
430
|
-
new OA\\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\\Schema(type: 'integer', default: ${schema.options?.api?.perPage ?? 15})),
|
|
430
|
+
new OA\\Parameter(name: 'per_page', in: 'query', required: false, schema: new OA\\Schema(type: 'integer', default: ${schema.options?.api?.perPage ?? 15}, minimum: 1, maximum: ${schema.options?.api?.maxPerPage ?? 100})),
|
|
431
431
|
new OA\\Parameter(name: 'page', in: 'query', required: false, schema: new OA\\Schema(type: 'integer')),
|
|
432
432
|
],
|
|
433
433
|
responses: [
|
|
@@ -68,6 +68,7 @@ function generateBaseRequest(name, schema, reader, config, action) {
|
|
|
68
68
|
const isUpdate = action === 'Update';
|
|
69
69
|
const rulesLines = [];
|
|
70
70
|
const attributeKeys = [];
|
|
71
|
+
const translatableRules = [];
|
|
71
72
|
for (const propName of propertyOrder) {
|
|
72
73
|
const prop = properties[propName];
|
|
73
74
|
if (!prop)
|
|
@@ -183,19 +184,26 @@ function generateBaseRequest(name, schema, reader, config, action) {
|
|
|
183
184
|
: formatRules(rules);
|
|
184
185
|
rulesLines.push(` '${snakeName}' => ${formattedRules},`);
|
|
185
186
|
attributeKeys.push(snakeName);
|
|
186
|
-
// Translatable:
|
|
187
|
+
// Translatable: collect locale-nested rules (Astrotomic expects {locale}.{field}).
|
|
188
|
+
// Emitted after the loop so each `<locale>` array key appears ONCE no
|
|
189
|
+
// matter how many translatable fields the schema has (#281: per-field
|
|
190
|
+
// emission produced duplicate array keys, PHPStan array.duplicateKey).
|
|
187
191
|
const isTranslatable = prop['translatable'] ?? false;
|
|
188
192
|
if (isTranslatable) {
|
|
189
|
-
const locales = reader.getLocales();
|
|
190
193
|
// Build nullable version of the same rules
|
|
191
194
|
const localeRules = rules.map(r => {
|
|
192
195
|
if (r === 'required')
|
|
193
196
|
return 'nullable';
|
|
194
197
|
return r;
|
|
195
198
|
});
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
+
translatableRules.push({ snakeName, rules: formatRules(localeRules) });
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (translatableRules.length > 0) {
|
|
203
|
+
for (const locale of reader.getLocales()) {
|
|
204
|
+
rulesLines.push(` '${locale}' => ['nullable', 'array'],`);
|
|
205
|
+
for (const t of translatableRules) {
|
|
206
|
+
rulesLines.push(` '${locale}.${t.snakeName}' => ${t.rules},`);
|
|
199
207
|
}
|
|
200
208
|
}
|
|
201
209
|
}
|
|
@@ -6,6 +6,43 @@ import { resolveTimestamps } from './timestamps.js';
|
|
|
6
6
|
import { isHiddenByDefault, toResourceExpression } from './type-mapper.js';
|
|
7
7
|
import { baseFile, userFile, resolveModularBasePath, resolveModularBaseNamespace, resolveBaseClass, resolveEditableClass, nestByGroup, nestEditableByGroup } from './types.js';
|
|
8
8
|
import { createClassImporter, renderUseBlock } from './php-style.js';
|
|
9
|
+
/**
|
|
10
|
+
* Instance members that make `$this-><name>` inside a JsonResource NOT a plain
|
|
11
|
+
* read of the model's attribute/relation (#281):
|
|
12
|
+
* - JsonResource's own public properties — `$this->with` / `$this->additional`
|
|
13
|
+
* / `$this->resource` read the resource object itself, not the model.
|
|
14
|
+
* - Eloquent Model's protected properties (Model + HasAttributes,
|
|
15
|
+
* HasRelationships, HasEvents, HidesAttributes, GuardsAttributes). Runtime
|
|
16
|
+
* reaches the attribute through __get, but via `@mixin Model` PHPStan sees a
|
|
17
|
+
* protected property (`property.protected`) — e.g. a `relations` association
|
|
18
|
+
* produced `Resource::collection($this->relations)`.
|
|
19
|
+
* For these, emit `$this->resource-><name>`, which always goes through the
|
|
20
|
+
* model's __get. Model's PUBLIC properties (exists, timestamps, incrementing, …)
|
|
21
|
+
* are not listed: they shadow the attribute on the model itself, so no
|
|
22
|
+
* resource-side spelling can reach it.
|
|
23
|
+
*/
|
|
24
|
+
const RESOURCE_RESERVED_MEMBERS = new Set([
|
|
25
|
+
// JsonResource
|
|
26
|
+
'resource', 'with', 'additional',
|
|
27
|
+
// Illuminate\Database\Eloquent\Model (protected)
|
|
28
|
+
'connection', 'table', 'primaryKey', 'keyType', 'withCount', 'perPage', 'escapeWhenCastingToString',
|
|
29
|
+
// Concerns\HasAttributes
|
|
30
|
+
'attributes', 'original', 'changes', 'previous', 'casts', 'classCastCache', 'attributeCastCache', 'dateFormat', 'appends',
|
|
31
|
+
// Concerns\HasRelationships
|
|
32
|
+
'relations', 'touches',
|
|
33
|
+
// Concerns\HasEvents
|
|
34
|
+
'dispatchesEvents', 'observables',
|
|
35
|
+
// Concerns\HidesAttributes / GuardsAttributes
|
|
36
|
+
'hidden', 'visible', 'fillable', 'guarded',
|
|
37
|
+
]);
|
|
38
|
+
/** `$this-><name>` for a model attribute/relation, collision-safe (#281). */
|
|
39
|
+
function modelMember(name) {
|
|
40
|
+
return RESOURCE_RESERVED_MEMBERS.has(name) ? `$this->resource->${name}` : `$this->${name}`;
|
|
41
|
+
}
|
|
42
|
+
/** Rewrite a `$this-><name>…` expression from toResourceExpression() collision-safe (#281). */
|
|
43
|
+
function safeResourceExpression(name, expr) {
|
|
44
|
+
return RESOURCE_RESERVED_MEMBERS.has(name) ? expr.replace(`$this->${name}`, modelMember(name)) : expr;
|
|
45
|
+
}
|
|
9
46
|
/** Generate Resource classes for all project-owned visible object schemas.
|
|
10
47
|
*
|
|
11
48
|
* Issue #101 v5.8.23 emitted ONLY the base — but child resources embed a
|
|
@@ -111,7 +148,7 @@ function generateBaseResource(name, schema, reader, config) {
|
|
|
111
148
|
for (const col of expandedProperties[propName].columns ?? []) {
|
|
112
149
|
const colName = col.name ?? '';
|
|
113
150
|
const colType = col.type ?? 'String';
|
|
114
|
-
const expr = toResourceExpression(colName, colType);
|
|
151
|
+
const expr = safeResourceExpression(colName, toResourceExpression(colName, colType));
|
|
115
152
|
fields.push(` '${colName}' => ${expr},`);
|
|
116
153
|
}
|
|
117
154
|
const sourceType = expandedProperties[propName].sourceType ?? '';
|
|
@@ -128,7 +165,7 @@ function generateBaseResource(name, schema, reader, config) {
|
|
|
128
165
|
continue;
|
|
129
166
|
}
|
|
130
167
|
const snakeName = toSnakeCase(propName);
|
|
131
|
-
const expr = toResourceExpression(snakeName, type);
|
|
168
|
+
const expr = safeResourceExpression(snakeName, toResourceExpression(snakeName, type));
|
|
132
169
|
fields.push(` '${snakeName}' => ${expr},`);
|
|
133
170
|
}
|
|
134
171
|
// Include translations for translatable models
|
|
@@ -331,7 +368,7 @@ function addAssociationFields(schemaName, propName, prop, fields, resourceNamesp
|
|
|
331
368
|
}
|
|
332
369
|
if (relation === 'ManyToOne') {
|
|
333
370
|
const snakeName = toFkColumnName(propName);
|
|
334
|
-
fields.push(` '${snakeName}' => $
|
|
371
|
+
fields.push(` '${snakeName}' => ${modelMember(snakeName)},`);
|
|
335
372
|
}
|
|
336
373
|
fields.push(` '${methodName}' => $this->whenLoaded('${methodName}'),`);
|
|
337
374
|
return;
|
|
@@ -340,18 +377,18 @@ function addAssociationFields(schemaName, propName, prop, fields, resourceNamesp
|
|
|
340
377
|
switch (relation) {
|
|
341
378
|
case 'ManyToOne': {
|
|
342
379
|
const snakeName = toFkColumnName(propName);
|
|
343
|
-
fields.push(` '${snakeName}' => $
|
|
344
|
-
fields.push(` '${methodName}' => $this->whenLoaded('${methodName}', fn () => new ${importer.ref(`${targetResNs}\\${targetResource}`)}($
|
|
380
|
+
fields.push(` '${snakeName}' => ${modelMember(snakeName)},`);
|
|
381
|
+
fields.push(` '${methodName}' => $this->whenLoaded('${methodName}', fn () => new ${importer.ref(`${targetResNs}\\${targetResource}`)}(${modelMember(methodName)})),`);
|
|
345
382
|
break;
|
|
346
383
|
}
|
|
347
384
|
case 'OneToMany':
|
|
348
385
|
case 'ManyToMany':
|
|
349
386
|
case 'MorphMany':
|
|
350
|
-
fields.push(` '${methodName}' => $this->whenLoaded('${methodName}', fn () => ${importer.ref(`${targetResNs}\\${targetResource}`)}::collection($
|
|
387
|
+
fields.push(` '${methodName}' => $this->whenLoaded('${methodName}', fn () => ${importer.ref(`${targetResNs}\\${targetResource}`)}::collection(${modelMember(methodName)})),`);
|
|
351
388
|
break;
|
|
352
389
|
case 'OneToOne':
|
|
353
390
|
case 'MorphOne':
|
|
354
|
-
fields.push(` '${methodName}' => $this->whenLoaded('${methodName}', fn () => new ${importer.ref(`${targetResNs}\\${targetResource}`)}($
|
|
391
|
+
fields.push(` '${methodName}' => $this->whenLoaded('${methodName}', fn () => new ${importer.ref(`${targetResNs}\\${targetResource}`)}(${modelMember(methodName)})),`);
|
|
355
392
|
break;
|
|
356
393
|
case 'MorphTo':
|
|
357
394
|
fields.push(` '${methodName}' => $this->whenLoaded('${methodName}'),`);
|
|
@@ -58,6 +58,11 @@ export declare class SchemaReader {
|
|
|
58
58
|
readonly defaultLocale: string;
|
|
59
59
|
readonly fallbackLocale: string;
|
|
60
60
|
readonly enforceLanguageFk?: boolean;
|
|
61
|
+
readonly translatable?: {
|
|
62
|
+
readonly toArrayAlwaysLoadsTranslations?: boolean;
|
|
63
|
+
readonly useFallback?: boolean;
|
|
64
|
+
readonly usePropertyFallback?: boolean;
|
|
65
|
+
};
|
|
61
66
|
};
|
|
62
67
|
getLocales(): string[];
|
|
63
68
|
getDefaultLocale(): string;
|
|
@@ -473,7 +473,10 @@ function generateBaseService(name, schema, reader, config) {
|
|
|
473
473
|
const svcRaw = options.service;
|
|
474
474
|
const svc = (svcRaw && typeof svcRaw === 'object') ? svcRaw : {};
|
|
475
475
|
const hasSoftDelete = options.softDelete ?? false;
|
|
476
|
-
|
|
476
|
+
// #280: per_page is clamped to [1, maxPerPage] inside list(). A default
|
|
477
|
+
// above the ceiling is pulled down to it.
|
|
478
|
+
const maxPerPage = api.maxPerPage ?? 100;
|
|
479
|
+
const perPage = Math.min(api.perPage ?? 25, maxPerPage);
|
|
477
480
|
// #81: lookup fields come from property-level `lookupable: true`.
|
|
478
481
|
// Legacy `options.service.lookupFields` still honoured (deprecation warning
|
|
479
482
|
// fired earlier). Always emit lookup() — it's a free method on every
|
|
@@ -561,7 +564,7 @@ function generateBaseService(name, schema, reader, config) {
|
|
|
561
564
|
// Allowed sort columns whitelist (#75.2: prevent SQL injection via sort filter)
|
|
562
565
|
const allowedSortColumns = buildAllowedSortColumns(searchableFields, filterableFields, sortableFields, defaultSort, hasSoftDelete);
|
|
563
566
|
// list() method
|
|
564
|
-
sections.push(buildListMethod(modelName, searchableFields, filterableFields, sortableFields, hasSoftDelete, eagerLoad, eagerCount, defaultSort, perPage, allowedSortColumns, translationCtx, reader));
|
|
567
|
+
sections.push(buildListMethod(modelName, searchableFields, filterableFields, sortableFields, hasSoftDelete, eagerLoad, eagerCount, defaultSort, perPage, maxPerPage, allowedSortColumns, translationCtx, reader));
|
|
565
568
|
// findById() method
|
|
566
569
|
sections.push(buildFindByIdMethod(modelName, eagerLoad, eagerCount, hasSoftDelete));
|
|
567
570
|
// ── Create section ────────────────────────────────────────────────────────
|
|
@@ -1086,7 +1089,7 @@ function buildAllowedSortColumns(searchableFields, filterableFields, sortableFie
|
|
|
1086
1089
|
set.add(defaultCol);
|
|
1087
1090
|
return Array.from(set).sort();
|
|
1088
1091
|
}
|
|
1089
|
-
function buildListMethod(modelName, searchableFields, filterableFields, sortableFields, hasSoftDelete, eagerLoad, eagerCount, defaultSort, perPage, allowedSortColumns, tx, reader) {
|
|
1092
|
+
function buildListMethod(modelName, searchableFields, filterableFields, sortableFields, hasSoftDelete, eagerLoad, eagerCount, defaultSort, perPage, maxPerPage, allowedSortColumns, tx, reader) {
|
|
1090
1093
|
const lines = [];
|
|
1091
1094
|
// #77 follow-up: strict multi-line array-shape enumerating every filter
|
|
1092
1095
|
// key explicitly (no catch-all). Sort union includes -prefixed DESC variants.
|
|
@@ -1151,9 +1154,14 @@ ${listExample}
|
|
|
1151
1154
|
// Sort
|
|
1152
1155
|
lines.push('');
|
|
1153
1156
|
lines.push(buildSortSection(sortableFields, defaultSort, allowedSortColumns, tx));
|
|
1154
|
-
// Paginate
|
|
1157
|
+
// Paginate — #280: clamp both ends. A negative per_page would otherwise
|
|
1158
|
+
// disable LIMIT (whole-table dump) and a huge one is unbounded.
|
|
1155
1159
|
lines.push(`
|
|
1156
|
-
|
|
1160
|
+
$perPage = filter_var($filters['per_page'] ?? null, FILTER_VALIDATE_INT);
|
|
1161
|
+
$perPage = $perPage === false || $perPage === null ? ${perPage} : $perPage;
|
|
1162
|
+
$perPage = max(1, min($perPage, ${maxPerPage}));
|
|
1163
|
+
|
|
1164
|
+
return $query->paginate($perPage);
|
|
1157
1165
|
}`);
|
|
1158
1166
|
return lines.join('\n');
|
|
1159
1167
|
}
|
|
@@ -20,4 +20,4 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import type { SchemaReader } from './schema-reader.js';
|
|
22
22
|
import type { GeneratedFile, PhpConfig } from './types.js';
|
|
23
|
-
export declare function generateTranslatableConfig(reader: SchemaReader,
|
|
23
|
+
export declare function generateTranslatableConfig(reader: SchemaReader, config: PhpConfig): GeneratedFile[];
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
* or extend it via Laravel's config merging.
|
|
20
20
|
*/
|
|
21
21
|
import { baseFile } from './types.js';
|
|
22
|
-
|
|
22
|
+
import { translationModelNamespace } from './translation-model-generator.js';
|
|
23
|
+
export function generateTranslatableConfig(reader, config) {
|
|
23
24
|
// Only emit when at least one schema has translatable fields — otherwise
|
|
24
25
|
// the file would just be dead weight in projects that don't use i18n.
|
|
25
26
|
const objectSchemas = reader.getProjectObjectSchemas();
|
|
@@ -43,6 +44,14 @@ export function generateTranslatableConfig(reader, _config) {
|
|
|
43
44
|
// `fallbackLocale` if set, otherwise fall back to the same defaultLocale.
|
|
44
45
|
const fallbackLocale = reader.getLocale()?.fallbackLocale ?? defaultLocale;
|
|
45
46
|
const localesPhp = locales.map(l => ` '${l}',`).join('\n');
|
|
47
|
+
// #281: options from omnify.yaml `locale.translatable.*`; absent = true
|
|
48
|
+
// (the values this file has always shipped with).
|
|
49
|
+
const opts = reader.getLocale()?.translatable ?? {};
|
|
50
|
+
const phpBool = (v) => ((v ?? true) ? 'true' : 'false');
|
|
51
|
+
// #281: must match where translation-model-generator writes the
|
|
52
|
+
// `{Model}Translation` classes — `null` made Astrotomic look next to the
|
|
53
|
+
// parent model (e.g. App\Models\IssueTranslation) and fail.
|
|
54
|
+
const translationNamespace = translationModelNamespace(config).replace(/\\/g, '\\\\');
|
|
46
55
|
const content = `<?php
|
|
47
56
|
|
|
48
57
|
/**
|
|
@@ -104,14 +113,14 @@ ${localesPhp}
|
|
|
104
113
|
| which would surface as blank dropdown labels in multi-locale projects.
|
|
105
114
|
|
|
|
106
115
|
*/
|
|
107
|
-
'use_fallback' =>
|
|
116
|
+
'use_fallback' => ${phpBool(opts.useFallback)},
|
|
108
117
|
|
|
109
118
|
/*
|
|
110
119
|
|--------------------------------------------------------------------------
|
|
111
120
|
| Use property fallback
|
|
112
121
|
|--------------------------------------------------------------------------
|
|
113
122
|
*/
|
|
114
|
-
'use_property_fallback' =>
|
|
123
|
+
'use_property_fallback' => ${phpBool(opts.usePropertyFallback)},
|
|
115
124
|
|
|
116
125
|
/*
|
|
117
126
|
|--------------------------------------------------------------------------
|
|
@@ -125,7 +134,7 @@ ${localesPhp}
|
|
|
125
134
|
| Translation model namespace
|
|
126
135
|
|--------------------------------------------------------------------------
|
|
127
136
|
*/
|
|
128
|
-
'translation_model_namespace' =>
|
|
137
|
+
'translation_model_namespace' => '${translationNamespace}',
|
|
129
138
|
|
|
130
139
|
/*
|
|
131
140
|
|--------------------------------------------------------------------------
|
|
@@ -150,7 +159,7 @@ ${localesPhp}
|
|
|
150
159
|
| Keeps paginator results self-contained for JSON API responses.
|
|
151
160
|
|
|
|
152
161
|
*/
|
|
153
|
-
'to_array_always_loads_translations' =>
|
|
162
|
+
'to_array_always_loads_translations' => ${phpBool(opts.toArrayAlwaysLoadsTranslations)},
|
|
154
163
|
|
|
155
164
|
/*
|
|
156
165
|
|--------------------------------------------------------------------------
|
|
@@ -11,3 +11,9 @@ import { SchemaReader } from './schema-reader.js';
|
|
|
11
11
|
import type { GeneratedFile, PhpConfig } from './types.js';
|
|
12
12
|
/** Generate translation model files for all project schemas with translatable fields. */
|
|
13
13
|
export declare function generateTranslationModels(reader: SchemaReader, config: PhpConfig): GeneratedFile[];
|
|
14
|
+
/**
|
|
15
|
+
* Namespace of the editable `{Model}Translation` classes. Also emitted as
|
|
16
|
+
* Astrotomic's `translation_model_namespace` in config/translatable.php so
|
|
17
|
+
* the trait resolves the classes this generator writes (#281).
|
|
18
|
+
*/
|
|
19
|
+
export declare function translationModelNamespace(config: PhpConfig): string;
|
|
@@ -161,6 +161,16 @@ ${fillableLines}
|
|
|
161
161
|
: `${config.models.basePath}/Translation/${baseClassName}.php`;
|
|
162
162
|
return baseFile(filePath, content);
|
|
163
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Namespace of the editable `{Model}Translation` classes. Also emitted as
|
|
166
|
+
* Astrotomic's `translation_model_namespace` in config/translatable.php so
|
|
167
|
+
* the trait resolves the classes this generator writes (#281).
|
|
168
|
+
*/
|
|
169
|
+
export function translationModelNamespace(config) {
|
|
170
|
+
return config.structure === 'modular'
|
|
171
|
+
? config.models.namespace
|
|
172
|
+
: `${config.models.userEditableNamespace}\\Translation`;
|
|
173
|
+
}
|
|
164
174
|
function generateTranslationUserModel(name, config) {
|
|
165
175
|
const modelName = toPascalCase(name);
|
|
166
176
|
// Issue #98 v5.8.2: editable translation stub also lives under
|
|
@@ -171,9 +181,7 @@ function generateTranslationUserModel(name, config) {
|
|
|
171
181
|
// the FILE LOCATION, not the base namespace — otherwise PSR-4 fails
|
|
172
182
|
// at runtime. Use `userEditableNamespace` (resolved from the config
|
|
173
183
|
// override) instead of the base `models.namespace`.
|
|
174
|
-
const modelNamespace = config
|
|
175
|
-
? config.models.namespace
|
|
176
|
-
: `${config.models.userEditableNamespace}\\Translation`;
|
|
184
|
+
const modelNamespace = translationModelNamespace(config);
|
|
177
185
|
const baseNamespace = config.structure === 'modular'
|
|
178
186
|
? resolveModularBaseNamespace(config, name, 'Models', config.models.baseNamespace)
|
|
179
187
|
: `${config.models.baseNamespace}\\Translation`;
|
package/dist/types.d.ts
CHANGED
|
@@ -62,6 +62,12 @@ export interface SchemasJson {
|
|
|
62
62
|
readonly defaultLocale: string;
|
|
63
63
|
readonly fallbackLocale: string;
|
|
64
64
|
readonly enforceLanguageFk?: boolean;
|
|
65
|
+
/** `locale.translatable.*` from omnify.yaml — config/translatable.php options (#281). */
|
|
66
|
+
readonly translatable?: {
|
|
67
|
+
readonly toArrayAlwaysLoadsTranslations?: boolean;
|
|
68
|
+
readonly useFallback?: boolean;
|
|
69
|
+
readonly usePropertyFallback?: boolean;
|
|
70
|
+
};
|
|
65
71
|
};
|
|
66
72
|
readonly customTypes: {
|
|
67
73
|
readonly compound: Record<string, CompoundTypeDefinition>;
|
|
@@ -142,6 +148,8 @@ export interface ApiOptions {
|
|
|
142
148
|
readonly restore?: boolean;
|
|
143
149
|
readonly middleware?: readonly string[];
|
|
144
150
|
readonly perPage?: number;
|
|
151
|
+
/** Upper bound for `per_page` in the generated list() (#280). Default 100. */
|
|
152
|
+
readonly maxPerPage?: number;
|
|
145
153
|
}
|
|
146
154
|
/**
|
|
147
155
|
* Service layer codegen options — controls BaseService generation. Issue #57.
|