@bazo/openapi-client-generator 3.0.13 → 3.0.15
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/README.md +27 -5
- package/bin.js +1043 -34
- package/package.json +1 -1
- package/skills/generate-client/SKILL.md +19 -8
- package/skills/integrate-php-client/SKILL.md +200 -0
package/bin.js
CHANGED
|
@@ -18565,11 +18565,7 @@ function resolveServerUrl(url, variables) {
|
|
|
18565
18565
|
});
|
|
18566
18566
|
}
|
|
18567
18567
|
function deriveServerName(server, index) {
|
|
18568
|
-
const candidates = [
|
|
18569
|
-
server["x-name"],
|
|
18570
|
-
server.name,
|
|
18571
|
-
server.description
|
|
18572
|
-
];
|
|
18568
|
+
const candidates = [server["x-name"], server.name, server.description];
|
|
18573
18569
|
for (const candidate of candidates) {
|
|
18574
18570
|
if (typeof candidate !== "string") {
|
|
18575
18571
|
continue;
|
|
@@ -18629,7 +18625,7 @@ function applyStringConstraints(schema) {
|
|
|
18629
18625
|
if (schema.pattern) {
|
|
18630
18626
|
try {
|
|
18631
18627
|
new RegExp(schema.pattern);
|
|
18632
|
-
const escaped = schema.pattern.replace(
|
|
18628
|
+
const escaped = schema.pattern.replace(/\//g, "\\/");
|
|
18633
18629
|
parts.push(`.regex(/${escaped}/)`);
|
|
18634
18630
|
} catch {
|
|
18635
18631
|
}
|
|
@@ -18786,9 +18782,7 @@ function convertArray(schema, ctx) {
|
|
|
18786
18782
|
// src/converter/composition.ts
|
|
18787
18783
|
function convertAllOf(schema, ctx) {
|
|
18788
18784
|
const schemas = schema.allOf;
|
|
18789
|
-
const allObjects = schemas.every(
|
|
18790
|
-
(s) => s.type === "object" || s.properties || s.refName && !s.allOf && !s.oneOf && !s.anyOf
|
|
18791
|
-
);
|
|
18785
|
+
const allObjects = schemas.every((s) => s.type === "object" || s.properties || s.refName && !s.allOf && !s.oneOf && !s.anyOf);
|
|
18792
18786
|
if (allObjects) {
|
|
18793
18787
|
return mergeAllOfObjects(schemas, schema, ctx);
|
|
18794
18788
|
}
|
|
@@ -19180,6 +19174,12 @@ var fullMode = {
|
|
|
19180
19174
|
lines.push(` return (configure ? configure(http) : http) as Http;`);
|
|
19181
19175
|
lines.push(`}`);
|
|
19182
19176
|
lines.push("");
|
|
19177
|
+
lines.push(`export interface ${clientName} {`);
|
|
19178
|
+
for (const op of ops) {
|
|
19179
|
+
lines.push(` ${op.operationId}: ReturnType<typeof ${op.operationId}>;`);
|
|
19180
|
+
}
|
|
19181
|
+
lines.push(`}`);
|
|
19182
|
+
lines.push("");
|
|
19183
19183
|
lines.push(`export class ${clientName} {`);
|
|
19184
19184
|
if (defaultServer) {
|
|
19185
19185
|
lines.push(` static readonly servers = ${clientName}Servers;`);
|
|
@@ -19190,10 +19190,6 @@ var fullMode = {
|
|
|
19190
19190
|
lines.push(` private operations: Map<string, Function>;`);
|
|
19191
19191
|
lines.push(` public http: Http;`);
|
|
19192
19192
|
lines.push("");
|
|
19193
|
-
for (const op of ops) {
|
|
19194
|
-
lines.push(` declare ${op.operationId}: ReturnType<typeof ${op.operationId}>;`);
|
|
19195
|
-
}
|
|
19196
|
-
lines.push("");
|
|
19197
19193
|
if (defaultServer) {
|
|
19198
19194
|
lines.push(` constructor(baseUrl: string, queryClient: QueryClient, options?: RequestInit, onHttpConfigure?: (w: Http) => unknown);`);
|
|
19199
19195
|
lines.push(` constructor(queryClient: QueryClient, options?: RequestInit, onHttpConfigure?: (w: Http) => unknown);`);
|
|
@@ -19384,10 +19380,7 @@ var playwrightMode = {
|
|
|
19384
19380
|
name: "playwright",
|
|
19385
19381
|
operationsInline: true,
|
|
19386
19382
|
generateImports(_ctx) {
|
|
19387
|
-
const lines = [
|
|
19388
|
-
'import { z } from "zod";',
|
|
19389
|
-
'import { type APIRequestContext, type APIResponse } from "@playwright/test";'
|
|
19390
|
-
];
|
|
19383
|
+
const lines = ['import { z } from "zod";', 'import { type APIRequestContext, type APIResponse } from "@playwright/test";'];
|
|
19391
19384
|
return lines.join("\n");
|
|
19392
19385
|
},
|
|
19393
19386
|
generateHelperTypes(_ctx) {
|
|
@@ -20219,6 +20212,8 @@ function generateSwiftMutation(op, namedSchemas, schemaLookup) {
|
|
|
20219
20212
|
// src/modes/swift/index.ts
|
|
20220
20213
|
var swiftMode = {
|
|
20221
20214
|
name: "swift",
|
|
20215
|
+
nativeTarget: true,
|
|
20216
|
+
fileExtension: ".swift",
|
|
20222
20217
|
operationsInline: true,
|
|
20223
20218
|
generateImports(_ctx) {
|
|
20224
20219
|
return ["import Foundation", "#if canImport(FoundationNetworking)", "import FoundationNetworking", "#endif"].join("\n");
|
|
@@ -20397,11 +20392,15 @@ var swiftMode = {
|
|
|
20397
20392
|
lines.push(` }`);
|
|
20398
20393
|
lines.push("");
|
|
20399
20394
|
lines.push(` private func documentedResponse<T: Sendable>(_ payload: T, from response: ApiResponse<Data>) -> APIError {`);
|
|
20400
|
-
lines.push(
|
|
20395
|
+
lines.push(
|
|
20396
|
+
` APIError.documentedResponse(statusCode: response.status, payload: payload, headers: response.headers, url: response.url)`
|
|
20397
|
+
);
|
|
20401
20398
|
lines.push(` }`);
|
|
20402
20399
|
lines.push("");
|
|
20403
20400
|
lines.push(` private func undocumentedResponse(from response: ApiResponse<Data>) -> APIError {`);
|
|
20404
|
-
lines.push(
|
|
20401
|
+
lines.push(
|
|
20402
|
+
` APIError.undocumentedResponse(statusCode: response.status, data: response.data, headers: response.headers, url: response.url)`
|
|
20403
|
+
);
|
|
20405
20404
|
lines.push(` }`);
|
|
20406
20405
|
lines.push("");
|
|
20407
20406
|
lines.push(` private func decodeJSON<T: Decodable>(_ type: T.Type, from response: ApiResponse<Data>) -> T? {`);
|
|
@@ -21024,6 +21023,8 @@ function generateKotlinMutation(op, namedSchemas, schemaLookup) {
|
|
|
21024
21023
|
// src/modes/kotlin/index.ts
|
|
21025
21024
|
var kotlinMode = {
|
|
21026
21025
|
name: "kotlin",
|
|
21026
|
+
nativeTarget: true,
|
|
21027
|
+
fileExtension: ".kt",
|
|
21027
21028
|
operationsInline: true,
|
|
21028
21029
|
generateImports(_ctx) {
|
|
21029
21030
|
const lines = [
|
|
@@ -21162,6 +21163,967 @@ function quoteKotlinString(value) {
|
|
|
21162
21163
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t")}"`;
|
|
21163
21164
|
}
|
|
21164
21165
|
|
|
21166
|
+
// src/converter/schema-to-php.ts
|
|
21167
|
+
var PHP_RESERVED = /* @__PURE__ */ new Set([
|
|
21168
|
+
"abstract",
|
|
21169
|
+
"and",
|
|
21170
|
+
"array",
|
|
21171
|
+
"as",
|
|
21172
|
+
"bool",
|
|
21173
|
+
"break",
|
|
21174
|
+
"callable",
|
|
21175
|
+
"case",
|
|
21176
|
+
"catch",
|
|
21177
|
+
"class",
|
|
21178
|
+
"clone",
|
|
21179
|
+
"const",
|
|
21180
|
+
"continue",
|
|
21181
|
+
"declare",
|
|
21182
|
+
"default",
|
|
21183
|
+
"do",
|
|
21184
|
+
"echo",
|
|
21185
|
+
"else",
|
|
21186
|
+
"elseif",
|
|
21187
|
+
"empty",
|
|
21188
|
+
"enddeclare",
|
|
21189
|
+
"endfor",
|
|
21190
|
+
"endforeach",
|
|
21191
|
+
"endif",
|
|
21192
|
+
"endswitch",
|
|
21193
|
+
"endwhile",
|
|
21194
|
+
"enum",
|
|
21195
|
+
"eval",
|
|
21196
|
+
"exit",
|
|
21197
|
+
"extends",
|
|
21198
|
+
"false",
|
|
21199
|
+
"final",
|
|
21200
|
+
"finally",
|
|
21201
|
+
"float",
|
|
21202
|
+
"fn",
|
|
21203
|
+
"for",
|
|
21204
|
+
"foreach",
|
|
21205
|
+
"function",
|
|
21206
|
+
"global",
|
|
21207
|
+
"goto",
|
|
21208
|
+
"if",
|
|
21209
|
+
"implements",
|
|
21210
|
+
"include",
|
|
21211
|
+
"include_once",
|
|
21212
|
+
"instanceof",
|
|
21213
|
+
"insteadof",
|
|
21214
|
+
"int",
|
|
21215
|
+
"interface",
|
|
21216
|
+
"isset",
|
|
21217
|
+
"iterable",
|
|
21218
|
+
"list",
|
|
21219
|
+
"match",
|
|
21220
|
+
"mixed",
|
|
21221
|
+
"namespace",
|
|
21222
|
+
"never",
|
|
21223
|
+
"new",
|
|
21224
|
+
"null",
|
|
21225
|
+
"object",
|
|
21226
|
+
"or",
|
|
21227
|
+
"parent",
|
|
21228
|
+
"print",
|
|
21229
|
+
"private",
|
|
21230
|
+
"protected",
|
|
21231
|
+
"public",
|
|
21232
|
+
"readonly",
|
|
21233
|
+
"require",
|
|
21234
|
+
"require_once",
|
|
21235
|
+
"return",
|
|
21236
|
+
"self",
|
|
21237
|
+
"static",
|
|
21238
|
+
"string",
|
|
21239
|
+
"switch",
|
|
21240
|
+
"throw",
|
|
21241
|
+
"trait",
|
|
21242
|
+
"true",
|
|
21243
|
+
"try",
|
|
21244
|
+
"unset",
|
|
21245
|
+
"use",
|
|
21246
|
+
"var",
|
|
21247
|
+
"void",
|
|
21248
|
+
"while",
|
|
21249
|
+
"xor",
|
|
21250
|
+
"yield"
|
|
21251
|
+
]);
|
|
21252
|
+
function phpFeatures(version) {
|
|
21253
|
+
const minor = Number.parseInt(version.split(".")[1], 10);
|
|
21254
|
+
return {
|
|
21255
|
+
enums: minor >= 1,
|
|
21256
|
+
readonlyProps: minor >= 1,
|
|
21257
|
+
readonlyClass: minor >= 2,
|
|
21258
|
+
typedConstants: minor >= 3,
|
|
21259
|
+
deprecatedAttribute: minor >= 4,
|
|
21260
|
+
noDiscard: minor >= 5,
|
|
21261
|
+
uriExtension: minor >= 5,
|
|
21262
|
+
pipeOperator: minor >= 5
|
|
21263
|
+
};
|
|
21264
|
+
}
|
|
21265
|
+
function phpClassName(name) {
|
|
21266
|
+
const safe = name.replace(/[^a-zA-Z0-9]+/g, " ").split(" ").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
21267
|
+
let result = safe || "Generated";
|
|
21268
|
+
if (/^[0-9]/.test(result)) {
|
|
21269
|
+
result = `_${result}`;
|
|
21270
|
+
}
|
|
21271
|
+
if (PHP_RESERVED.has(result.toLowerCase())) {
|
|
21272
|
+
result = `${result}Model`;
|
|
21273
|
+
}
|
|
21274
|
+
return result;
|
|
21275
|
+
}
|
|
21276
|
+
function phpPropertyName(name) {
|
|
21277
|
+
let result = name.replace(/[-_]([a-zA-Z])/g, (_, c) => c.toUpperCase());
|
|
21278
|
+
if (result.startsWith("_")) {
|
|
21279
|
+
result = result.slice(1);
|
|
21280
|
+
}
|
|
21281
|
+
result = result.charAt(0).toLowerCase() + result.slice(1);
|
|
21282
|
+
if (!/^[a-zA-Z_]/.test(result)) {
|
|
21283
|
+
result = `_${result}`;
|
|
21284
|
+
}
|
|
21285
|
+
return result;
|
|
21286
|
+
}
|
|
21287
|
+
function phpEnumCaseName(value) {
|
|
21288
|
+
let result = value.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[^a-zA-Z0-9]+/g, " ").split(" ").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
21289
|
+
if (result.length === 0) return "Unknown";
|
|
21290
|
+
if (/^[0-9]/.test(result)) {
|
|
21291
|
+
result = `_${result}`;
|
|
21292
|
+
}
|
|
21293
|
+
if (result.toLowerCase() === "class") {
|
|
21294
|
+
result = `${result}_`;
|
|
21295
|
+
}
|
|
21296
|
+
return result;
|
|
21297
|
+
}
|
|
21298
|
+
function phpConstantName(value) {
|
|
21299
|
+
let result = value.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/[-\s]+/g, "_").replace(/[^a-zA-Z0-9_]/g, "").toUpperCase();
|
|
21300
|
+
if (result.length === 0) return "UNKNOWN";
|
|
21301
|
+
if (/^[0-9]/.test(result)) {
|
|
21302
|
+
result = `_${result}`;
|
|
21303
|
+
}
|
|
21304
|
+
if (result === "CLASS") {
|
|
21305
|
+
result = "CLASS_";
|
|
21306
|
+
}
|
|
21307
|
+
return result;
|
|
21308
|
+
}
|
|
21309
|
+
function enumBacking(values2) {
|
|
21310
|
+
if (values2.length === 0) return null;
|
|
21311
|
+
if (values2.every((v) => typeof v === "string")) return "string";
|
|
21312
|
+
if (values2.every((v) => typeof v === "number" && Number.isInteger(v))) return "int";
|
|
21313
|
+
return null;
|
|
21314
|
+
}
|
|
21315
|
+
function classifyPhpSchemas(schemas, features) {
|
|
21316
|
+
const kinds = /* @__PURE__ */ new Map();
|
|
21317
|
+
for (const [name, schema] of schemas) {
|
|
21318
|
+
kinds.set(name, classifySchema(schema, features, schemas));
|
|
21319
|
+
}
|
|
21320
|
+
return kinds;
|
|
21321
|
+
}
|
|
21322
|
+
function classifySchema(schema, features, lookup) {
|
|
21323
|
+
if (schema.enum) {
|
|
21324
|
+
const backing = enumBacking(schema.enum);
|
|
21325
|
+
if (backing) {
|
|
21326
|
+
return features.enums ? { kind: "enum", backing } : { kind: "constants", backing };
|
|
21327
|
+
}
|
|
21328
|
+
return { kind: "alias" };
|
|
21329
|
+
}
|
|
21330
|
+
if (schema.oneOf || schema.anyOf) {
|
|
21331
|
+
return { kind: "alias" };
|
|
21332
|
+
}
|
|
21333
|
+
if (schema.allOf) {
|
|
21334
|
+
return hasMergedProperties(schema, lookup) ? { kind: "class" } : { kind: "alias" };
|
|
21335
|
+
}
|
|
21336
|
+
if (schema.properties && schema.properties.size > 0) {
|
|
21337
|
+
return { kind: "class" };
|
|
21338
|
+
}
|
|
21339
|
+
return { kind: "alias" };
|
|
21340
|
+
}
|
|
21341
|
+
function hasMergedProperties(schema, lookup, visitedRefs = /* @__PURE__ */ new Set()) {
|
|
21342
|
+
if (schema.refName && lookup.has(schema.refName)) {
|
|
21343
|
+
if (visitedRefs.has(schema.refName)) return false;
|
|
21344
|
+
visitedRefs.add(schema.refName);
|
|
21345
|
+
return hasMergedProperties(lookup.get(schema.refName), lookup, visitedRefs);
|
|
21346
|
+
}
|
|
21347
|
+
if (schema.properties && schema.properties.size > 0) return true;
|
|
21348
|
+
if (schema.allOf) {
|
|
21349
|
+
return schema.allOf.some((sub) => hasMergedProperties(sub, lookup, new Set(visitedRefs)));
|
|
21350
|
+
}
|
|
21351
|
+
return false;
|
|
21352
|
+
}
|
|
21353
|
+
var MIXED = { native: "mixed", doc: "mixed", deserialize: { kind: "json" } };
|
|
21354
|
+
function primitive(native) {
|
|
21355
|
+
return { native, doc: native, deserialize: { kind: "json" } };
|
|
21356
|
+
}
|
|
21357
|
+
function maybeNullable3(t, schema) {
|
|
21358
|
+
if (!schema.nullable) return t;
|
|
21359
|
+
return nullablePhpType(t);
|
|
21360
|
+
}
|
|
21361
|
+
function nullablePhpType(t) {
|
|
21362
|
+
return {
|
|
21363
|
+
native: t.native === "mixed" || t.native.startsWith("?") ? t.native : `?${t.native}`,
|
|
21364
|
+
doc: t.doc === "mixed" || t.doc.endsWith("|null") ? t.doc : `${t.doc}|null`,
|
|
21365
|
+
deserialize: t.deserialize
|
|
21366
|
+
};
|
|
21367
|
+
}
|
|
21368
|
+
function namedType(name, schema, pctx, visited) {
|
|
21369
|
+
const kind = pctx.kinds.get(name) ?? { kind: "alias" };
|
|
21370
|
+
switch (kind.kind) {
|
|
21371
|
+
case "class": {
|
|
21372
|
+
const className = pctx.classPrefix + phpClassName(name);
|
|
21373
|
+
return maybeNullable3({ native: className, doc: className, deserialize: { kind: "class", name: className } }, schema);
|
|
21374
|
+
}
|
|
21375
|
+
case "enum": {
|
|
21376
|
+
const className = pctx.classPrefix + phpClassName(name);
|
|
21377
|
+
return maybeNullable3({ native: className, doc: className, deserialize: { kind: "enum", name: className } }, schema);
|
|
21378
|
+
}
|
|
21379
|
+
case "constants":
|
|
21380
|
+
return maybeNullable3(primitive(kind.backing === "int" ? "int" : "string"), schema);
|
|
21381
|
+
case "alias": {
|
|
21382
|
+
if (visited.has(name)) return MIXED;
|
|
21383
|
+
visited.add(name);
|
|
21384
|
+
const target = pctx.conv.schemaLookup?.get(name);
|
|
21385
|
+
if (!target) return maybeNullable3(MIXED, schema);
|
|
21386
|
+
return maybeNullable3(resolvePhpType(target, pctx, visited), schema);
|
|
21387
|
+
}
|
|
21388
|
+
}
|
|
21389
|
+
}
|
|
21390
|
+
function schemaToPhpType(schema, pctx) {
|
|
21391
|
+
return resolvePhpType(schema, pctx, /* @__PURE__ */ new Set());
|
|
21392
|
+
}
|
|
21393
|
+
function resolvePhpType(schema, pctx, visited) {
|
|
21394
|
+
if (schema.isCircular && schema.refName) {
|
|
21395
|
+
const kind = pctx.kinds.get(schema.refName);
|
|
21396
|
+
if (kind && (kind.kind === "class" || kind.kind === "enum")) {
|
|
21397
|
+
const className = pctx.classPrefix + phpClassName(schema.refName);
|
|
21398
|
+
return nullablePhpType({
|
|
21399
|
+
native: className,
|
|
21400
|
+
doc: className,
|
|
21401
|
+
deserialize: kind.kind === "class" ? { kind: "class", name: className } : { kind: "enum", name: className }
|
|
21402
|
+
});
|
|
21403
|
+
}
|
|
21404
|
+
return MIXED;
|
|
21405
|
+
}
|
|
21406
|
+
if (schema.generatedName && pctx.conv.namedSchemas.has(schema.generatedName)) {
|
|
21407
|
+
return namedType(schema.generatedName, schema, pctx, visited);
|
|
21408
|
+
}
|
|
21409
|
+
if (schema.refName && pctx.conv.namedSchemas.has(schema.refName)) {
|
|
21410
|
+
return namedType(schema.refName, schema, pctx, visited);
|
|
21411
|
+
}
|
|
21412
|
+
if (schema.allOf) return resolveAllOfType3(schema, pctx, visited);
|
|
21413
|
+
if (schema.oneOf) return resolveOneOfType3(schema, pctx, visited);
|
|
21414
|
+
if (schema.anyOf) return resolveAnyOfType3(schema, pctx, visited);
|
|
21415
|
+
if (schema.enum) return resolveEnumType3(schema);
|
|
21416
|
+
switch (normalizeType(schema)) {
|
|
21417
|
+
case "string":
|
|
21418
|
+
return maybeNullable3(primitive("string"), schema);
|
|
21419
|
+
case "number":
|
|
21420
|
+
return maybeNullable3(primitive("float"), schema);
|
|
21421
|
+
case "integer":
|
|
21422
|
+
return maybeNullable3(primitive("int"), schema);
|
|
21423
|
+
case "boolean":
|
|
21424
|
+
return maybeNullable3(primitive("bool"), schema);
|
|
21425
|
+
case "null":
|
|
21426
|
+
return { native: "mixed", doc: "null", deserialize: { kind: "json" } };
|
|
21427
|
+
case "array":
|
|
21428
|
+
return resolveArrayType3(schema, pctx, visited);
|
|
21429
|
+
case "object":
|
|
21430
|
+
return resolveObjectType3(schema, pctx, visited);
|
|
21431
|
+
default:
|
|
21432
|
+
return maybeNullable3(MIXED, schema);
|
|
21433
|
+
}
|
|
21434
|
+
}
|
|
21435
|
+
function resolveArrayType3(schema, pctx, visited) {
|
|
21436
|
+
const itemType = schema.items ? resolvePhpType(schema.items, pctx, visited) : MIXED;
|
|
21437
|
+
const itemDoc = itemType.doc.includes("|") || itemType.doc.includes("<") ? `array<${itemType.doc}>` : `${itemType.doc}[]`;
|
|
21438
|
+
const deserialize = itemType.deserialize.kind === "class" ? { kind: "classArray", name: itemType.deserialize.name } : { kind: "json" };
|
|
21439
|
+
return maybeNullable3({ native: "array", doc: itemDoc, deserialize }, schema);
|
|
21440
|
+
}
|
|
21441
|
+
function resolveObjectType3(schema, pctx, visited) {
|
|
21442
|
+
if (!schema.properties || schema.properties.size === 0) {
|
|
21443
|
+
if (typeof schema.additionalProperties === "object") {
|
|
21444
|
+
const valueType = resolvePhpType(schema.additionalProperties, pctx, visited);
|
|
21445
|
+
return maybeNullable3({ native: "array", doc: `array<string, ${valueType.doc}>`, deserialize: { kind: "json" } }, schema);
|
|
21446
|
+
}
|
|
21447
|
+
return maybeNullable3({ native: "array", doc: "array<string, mixed>", deserialize: { kind: "json" } }, schema);
|
|
21448
|
+
}
|
|
21449
|
+
if (schema.generatedName && pctx.conv.namedSchemas.has(schema.generatedName)) {
|
|
21450
|
+
return namedType(schema.generatedName, schema, pctx, visited);
|
|
21451
|
+
}
|
|
21452
|
+
return maybeNullable3(MIXED, schema);
|
|
21453
|
+
}
|
|
21454
|
+
function resolveAllOfType3(schema, pctx, visited) {
|
|
21455
|
+
const schemas = schema.allOf;
|
|
21456
|
+
if (schemas.length === 1) return resolvePhpType(schemas[0], pctx, visited);
|
|
21457
|
+
if (schemas[0].refName && pctx.conv.namedSchemas.has(schemas[0].refName)) {
|
|
21458
|
+
return namedType(schemas[0].refName, schema, pctx, visited);
|
|
21459
|
+
}
|
|
21460
|
+
return maybeNullable3(MIXED, schema);
|
|
21461
|
+
}
|
|
21462
|
+
function resolveOneOfType3(schema, pctx, visited) {
|
|
21463
|
+
const schemas = schema.oneOf;
|
|
21464
|
+
if (schemas.length === 1) return resolvePhpType(schemas[0], pctx, visited);
|
|
21465
|
+
return maybeNullable3(MIXED, schema);
|
|
21466
|
+
}
|
|
21467
|
+
function resolveAnyOfType3(schema, pctx, visited) {
|
|
21468
|
+
const schemas = schema.anyOf;
|
|
21469
|
+
const nonNull = schemas.filter((s) => s.type !== "null");
|
|
21470
|
+
const hasNull = schemas.some((s) => s.type === "null");
|
|
21471
|
+
if (hasNull && nonNull.length === 1) {
|
|
21472
|
+
return nullablePhpType(resolvePhpType(nonNull[0], pctx, visited));
|
|
21473
|
+
}
|
|
21474
|
+
if (schemas.length === 1) return resolvePhpType(schemas[0], pctx, visited);
|
|
21475
|
+
return maybeNullable3(MIXED, schema);
|
|
21476
|
+
}
|
|
21477
|
+
function resolveEnumType3(schema) {
|
|
21478
|
+
const backing = enumBacking(schema.enum);
|
|
21479
|
+
if (backing === "int") return primitive("int");
|
|
21480
|
+
if (backing === "string") return primitive("string");
|
|
21481
|
+
return MIXED;
|
|
21482
|
+
}
|
|
21483
|
+
function phpStringify(schema, expr, pctx) {
|
|
21484
|
+
const type = schemaToPhpType(schema, pctx);
|
|
21485
|
+
if (type.deserialize.kind === "enum") {
|
|
21486
|
+
return `${expr}->value`;
|
|
21487
|
+
}
|
|
21488
|
+
if (type.native.replace("?", "") === "bool") {
|
|
21489
|
+
return `${expr} ? 'true' : 'false'`;
|
|
21490
|
+
}
|
|
21491
|
+
return expr;
|
|
21492
|
+
}
|
|
21493
|
+
function generatePhpModel(name, schema, pctx) {
|
|
21494
|
+
const kind = pctx.kinds.get(name);
|
|
21495
|
+
if (!kind || kind.kind === "alias") return null;
|
|
21496
|
+
if (kind.kind === "enum") {
|
|
21497
|
+
return generatePhpEnum(name, schema, kind.backing);
|
|
21498
|
+
}
|
|
21499
|
+
if (kind.kind === "constants") {
|
|
21500
|
+
return generatePhpConstantsClass(name, schema, kind.backing);
|
|
21501
|
+
}
|
|
21502
|
+
if (schema.allOf) {
|
|
21503
|
+
return generatePhpAllOfClass(name, schema, pctx);
|
|
21504
|
+
}
|
|
21505
|
+
if (schema.properties && schema.properties.size > 0) {
|
|
21506
|
+
return generatePhpObjectClass(name, schema, pctx);
|
|
21507
|
+
}
|
|
21508
|
+
return null;
|
|
21509
|
+
}
|
|
21510
|
+
function generatePhpEnum(name, schema, backing) {
|
|
21511
|
+
const lines = [];
|
|
21512
|
+
lines.push(`enum ${phpClassName(name)}: ${backing}`);
|
|
21513
|
+
lines.push("{");
|
|
21514
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21515
|
+
for (const v of schema.enum) {
|
|
21516
|
+
let caseName = phpEnumCaseName(String(v));
|
|
21517
|
+
while (seen.has(caseName)) caseName = `${caseName}_`;
|
|
21518
|
+
seen.add(caseName);
|
|
21519
|
+
const literal = backing === "string" ? quotePhpString(String(v)) : String(v);
|
|
21520
|
+
lines.push(` case ${caseName} = ${literal};`);
|
|
21521
|
+
}
|
|
21522
|
+
lines.push("}");
|
|
21523
|
+
return { code: lines.join("\n"), uses: [] };
|
|
21524
|
+
}
|
|
21525
|
+
function generatePhpConstantsClass(name, schema, backing) {
|
|
21526
|
+
const lines = [];
|
|
21527
|
+
lines.push(`final class ${phpClassName(name)}`);
|
|
21528
|
+
lines.push("{");
|
|
21529
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21530
|
+
for (const v of schema.enum) {
|
|
21531
|
+
let constName = phpConstantName(String(v));
|
|
21532
|
+
while (seen.has(constName)) constName = `${constName}_`;
|
|
21533
|
+
seen.add(constName);
|
|
21534
|
+
const literal = backing === "string" ? quotePhpString(String(v)) : String(v);
|
|
21535
|
+
lines.push(` public const ${constName} = ${literal};`);
|
|
21536
|
+
}
|
|
21537
|
+
lines.push("}");
|
|
21538
|
+
return { code: lines.join("\n"), uses: [] };
|
|
21539
|
+
}
|
|
21540
|
+
function generatePhpObjectClass(name, schema, pctx) {
|
|
21541
|
+
const properties = schema.properties;
|
|
21542
|
+
const requiredFields = new Set(schema.required ?? []);
|
|
21543
|
+
const { features } = pctx;
|
|
21544
|
+
const uses = /* @__PURE__ */ new Set();
|
|
21545
|
+
const entries = [];
|
|
21546
|
+
for (const [propName, propSchema] of properties) {
|
|
21547
|
+
entries.push({
|
|
21548
|
+
wireName: propName,
|
|
21549
|
+
safeName: phpPropertyName(propName),
|
|
21550
|
+
type: schemaToPhpType(propSchema, pctx),
|
|
21551
|
+
required: requiredFields.has(propName)
|
|
21552
|
+
});
|
|
21553
|
+
}
|
|
21554
|
+
const ordered = [...entries.filter((e) => e.required), ...entries.filter((e) => !e.required)];
|
|
21555
|
+
const lines = [];
|
|
21556
|
+
const classKeywords = features.readonlyClass ? "final readonly class" : "final class";
|
|
21557
|
+
lines.push(`${classKeywords} ${phpClassName(name)}`);
|
|
21558
|
+
lines.push("{");
|
|
21559
|
+
const docParams = ordered.filter((e) => e.type.doc.includes("[]") || e.type.doc.includes("array<"));
|
|
21560
|
+
if (docParams.length > 0) {
|
|
21561
|
+
lines.push(" /**");
|
|
21562
|
+
for (const e of docParams) {
|
|
21563
|
+
const doc = e.required ? e.type.doc : appendNullDoc(e.type.doc);
|
|
21564
|
+
lines.push(` * @param ${doc} $${e.safeName}`);
|
|
21565
|
+
}
|
|
21566
|
+
lines.push(" */");
|
|
21567
|
+
}
|
|
21568
|
+
lines.push(" public function __construct(");
|
|
21569
|
+
const propKeywords = features.readonlyClass ? "public" : features.readonlyProps ? "public readonly" : "public";
|
|
21570
|
+
for (const e of ordered) {
|
|
21571
|
+
let native = e.type.native;
|
|
21572
|
+
let suffix = "";
|
|
21573
|
+
if (!e.required) {
|
|
21574
|
+
if (native !== "mixed" && !native.startsWith("?")) {
|
|
21575
|
+
native = `?${native}`;
|
|
21576
|
+
}
|
|
21577
|
+
suffix = " = null";
|
|
21578
|
+
}
|
|
21579
|
+
if (e.safeName !== e.wireName) {
|
|
21580
|
+
lines.push(` #[SerializedName(${quotePhpString(e.wireName)})]`);
|
|
21581
|
+
uses.add(serializedNameImport(features));
|
|
21582
|
+
}
|
|
21583
|
+
lines.push(` ${propKeywords} ${native} $${e.safeName}${suffix},`);
|
|
21584
|
+
}
|
|
21585
|
+
lines.push(" ) {");
|
|
21586
|
+
lines.push(" }");
|
|
21587
|
+
lines.push("}");
|
|
21588
|
+
return { code: lines.join("\n"), uses: [...uses] };
|
|
21589
|
+
}
|
|
21590
|
+
function appendNullDoc(doc) {
|
|
21591
|
+
return doc.endsWith("|null") ? doc : `${doc}|null`;
|
|
21592
|
+
}
|
|
21593
|
+
function serializedNameImport(features) {
|
|
21594
|
+
return features.enums ? "Symfony\\Component\\Serializer\\Attribute\\SerializedName" : "Symfony\\Component\\Serializer\\Annotation\\SerializedName";
|
|
21595
|
+
}
|
|
21596
|
+
function generatePhpAllOfClass(name, schema, pctx) {
|
|
21597
|
+
const schemas = schema.allOf;
|
|
21598
|
+
const allProps = /* @__PURE__ */ new Map();
|
|
21599
|
+
for (const s of schemas) {
|
|
21600
|
+
collectPhpProperties(s, pctx, allProps);
|
|
21601
|
+
}
|
|
21602
|
+
if (allProps.size === 0) {
|
|
21603
|
+
return null;
|
|
21604
|
+
}
|
|
21605
|
+
const mergedSchema = {
|
|
21606
|
+
type: "object",
|
|
21607
|
+
properties: /* @__PURE__ */ new Map(),
|
|
21608
|
+
required: []
|
|
21609
|
+
};
|
|
21610
|
+
for (const [propName, prop] of allProps) {
|
|
21611
|
+
mergedSchema.properties.set(propName, prop.schema);
|
|
21612
|
+
if (prop.required) {
|
|
21613
|
+
mergedSchema.required.push(propName);
|
|
21614
|
+
}
|
|
21615
|
+
}
|
|
21616
|
+
return generatePhpObjectClass(name, mergedSchema, pctx);
|
|
21617
|
+
}
|
|
21618
|
+
function collectPhpProperties(schema, pctx, allProps, visitedRefs = /* @__PURE__ */ new Set()) {
|
|
21619
|
+
if (schema.refName && pctx.conv.schemaLookup?.has(schema.refName)) {
|
|
21620
|
+
if (visitedRefs.has(schema.refName)) return;
|
|
21621
|
+
visitedRefs.add(schema.refName);
|
|
21622
|
+
collectPhpProperties(pctx.conv.schemaLookup.get(schema.refName), pctx, allProps, visitedRefs);
|
|
21623
|
+
return;
|
|
21624
|
+
}
|
|
21625
|
+
if (schema.allOf) {
|
|
21626
|
+
for (const subSchema of schema.allOf) {
|
|
21627
|
+
collectPhpProperties(subSchema, pctx, allProps, new Set(visitedRefs));
|
|
21628
|
+
}
|
|
21629
|
+
}
|
|
21630
|
+
if (!schema.properties) return;
|
|
21631
|
+
const required = new Set(schema.required ?? []);
|
|
21632
|
+
for (const [propName, propSchema] of schema.properties) {
|
|
21633
|
+
allProps.set(propName, {
|
|
21634
|
+
schema: propSchema,
|
|
21635
|
+
required: required.has(propName) || (allProps.get(propName)?.required ?? false)
|
|
21636
|
+
});
|
|
21637
|
+
}
|
|
21638
|
+
}
|
|
21639
|
+
function quotePhpString(value) {
|
|
21640
|
+
return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
21641
|
+
}
|
|
21642
|
+
|
|
21643
|
+
// src/modes/shared/response-cases-php.ts
|
|
21644
|
+
function getPhpResponseDocType(op, pctx) {
|
|
21645
|
+
const shapes = collectPhpSuccessShapes(op, pctx);
|
|
21646
|
+
if (shapes.length === 0) return "null";
|
|
21647
|
+
const distinctDocs = new Set(shapes.map((shape) => shapeDocType(shape)));
|
|
21648
|
+
return distinctDocs.size === 1 ? shapeDocType(shapes[0]) : "mixed";
|
|
21649
|
+
}
|
|
21650
|
+
function generatePhpResponseCases(op, pctx) {
|
|
21651
|
+
const cases = [];
|
|
21652
|
+
for (const [statusCode, response] of orderResponseEntries(op.responses)) {
|
|
21653
|
+
const matcher = phpStatusMatcher(statusCode);
|
|
21654
|
+
if (!matcher) continue;
|
|
21655
|
+
if (!isSuccessStatus(statusCode)) {
|
|
21656
|
+
cases.push(`${matcher} => throw new ApiException($statusCode, $content, $headers, $requestUrl),`);
|
|
21657
|
+
continue;
|
|
21658
|
+
}
|
|
21659
|
+
const shape = getPhpResponseShape(response, pctx);
|
|
21660
|
+
cases.push(`${matcher} => new ApiResponse(${phpDataExpr(shape)}, $statusCode, $headers, $requestUrl),`);
|
|
21661
|
+
}
|
|
21662
|
+
cases.push("default => throw new ApiException($statusCode, $content, $headers, $requestUrl),");
|
|
21663
|
+
return cases;
|
|
21664
|
+
}
|
|
21665
|
+
function phpDataExpr(shape) {
|
|
21666
|
+
if (shape.mode === "empty") return "null";
|
|
21667
|
+
if (shape.mode === "text") return "$content";
|
|
21668
|
+
const target = shape.type.deserialize;
|
|
21669
|
+
switch (target.kind) {
|
|
21670
|
+
case "class":
|
|
21671
|
+
case "enum":
|
|
21672
|
+
return `$this->serializer->deserialize($content, ${target.name}::class, 'json')`;
|
|
21673
|
+
case "classArray":
|
|
21674
|
+
return `$this->serializer->deserialize($content, ${target.name}::class . '[]', 'json')`;
|
|
21675
|
+
case "json":
|
|
21676
|
+
return "json_decode($content, true, 512, \\JSON_THROW_ON_ERROR)";
|
|
21677
|
+
}
|
|
21678
|
+
}
|
|
21679
|
+
function shapeDocType(shape) {
|
|
21680
|
+
if (shape.mode === "empty") return "null";
|
|
21681
|
+
if (shape.mode === "text") return "string";
|
|
21682
|
+
return shape.type.doc;
|
|
21683
|
+
}
|
|
21684
|
+
function collectPhpSuccessShapes(op, pctx) {
|
|
21685
|
+
const shapes = [];
|
|
21686
|
+
for (const [statusCode, response] of op.responses) {
|
|
21687
|
+
if (!isSuccessStatus(statusCode)) continue;
|
|
21688
|
+
shapes.push(getPhpResponseShape(response, pctx));
|
|
21689
|
+
}
|
|
21690
|
+
return shapes;
|
|
21691
|
+
}
|
|
21692
|
+
function getPhpResponseShape(response, pctx) {
|
|
21693
|
+
if (!response.hasBody) {
|
|
21694
|
+
return { type: null, mode: "empty" };
|
|
21695
|
+
}
|
|
21696
|
+
const jsonSchema = response.contentTypes.get("application/json");
|
|
21697
|
+
if (jsonSchema) {
|
|
21698
|
+
return { type: schemaToPhpType(jsonSchema, pctx), mode: "json" };
|
|
21699
|
+
}
|
|
21700
|
+
return { type: null, mode: "text" };
|
|
21701
|
+
}
|
|
21702
|
+
function phpStatusMatcher(statusCode) {
|
|
21703
|
+
if (statusCode === "default") return null;
|
|
21704
|
+
const wildcardMatch = statusCode.match(/^([1-5])XX$/i);
|
|
21705
|
+
if (wildcardMatch) {
|
|
21706
|
+
const prefix = Number.parseInt(wildcardMatch[1], 10);
|
|
21707
|
+
const start = prefix * 100;
|
|
21708
|
+
return `$statusCode >= ${start} && $statusCode < ${start + 100}`;
|
|
21709
|
+
}
|
|
21710
|
+
const code = Number.parseInt(statusCode, 10);
|
|
21711
|
+
return Number.isNaN(code) ? null : `$statusCode === ${code}`;
|
|
21712
|
+
}
|
|
21713
|
+
|
|
21714
|
+
// src/modes/php/helpers.ts
|
|
21715
|
+
var RESERVED_LOCALS = /* @__PURE__ */ new Set(["response", "statusCode", "content", "headers", "requestUrl", "query", "options", "body", "url"]);
|
|
21716
|
+
function phpParamName(name) {
|
|
21717
|
+
const safe = phpPropertyName(name);
|
|
21718
|
+
return RESERVED_LOCALS.has(safe) ? `${safe}Param` : safe;
|
|
21719
|
+
}
|
|
21720
|
+
function phpFile(namespace, uses, code) {
|
|
21721
|
+
const lines = ["<?php", "", "declare(strict_types=1);", "", `namespace ${namespace};`, ""];
|
|
21722
|
+
const sorted = [...new Set(uses)].sort();
|
|
21723
|
+
for (const use of sorted) {
|
|
21724
|
+
lines.push(`use ${use};`);
|
|
21725
|
+
}
|
|
21726
|
+
if (sorted.length > 0) {
|
|
21727
|
+
lines.push("");
|
|
21728
|
+
}
|
|
21729
|
+
lines.push(code);
|
|
21730
|
+
lines.push("");
|
|
21731
|
+
return lines.join("\n");
|
|
21732
|
+
}
|
|
21733
|
+
function generatePhpOperation(op, pctx) {
|
|
21734
|
+
const { features } = pctx;
|
|
21735
|
+
const entry = (p) => ({ param: p, safeName: phpParamName(p.name), type: schemaToPhpType(p.schema, pctx) });
|
|
21736
|
+
const pathParams = op.parameters.filter((p) => p.in === "path").map(entry);
|
|
21737
|
+
const queryParams = op.parameters.filter((p) => p.in === "query").map(entry);
|
|
21738
|
+
const headerParams = op.parameters.filter((p) => p.in === "header").map(entry);
|
|
21739
|
+
const hasBody = op.type === "mutation" && op.requestBody !== null;
|
|
21740
|
+
const bodySchema = hasBody ? op.requestBody.contentTypes.get(op.requestBody.primaryContentType) ?? null : null;
|
|
21741
|
+
const bodyType = bodySchema ? schemaToPhpType(bodySchema, pctx) : null;
|
|
21742
|
+
const bodyRequired = hasBody && op.requestBody.required;
|
|
21743
|
+
const sig = [];
|
|
21744
|
+
for (const e of pathParams) {
|
|
21745
|
+
sig.push({ decl: `${e.type.native} $${e.safeName}`, docType: docTypeIfUseful(e.type), safeName: e.safeName, required: true });
|
|
21746
|
+
}
|
|
21747
|
+
if (bodyType) {
|
|
21748
|
+
if (bodyRequired) {
|
|
21749
|
+
sig.push({ decl: `${bodyType.native} $body`, docType: docTypeIfUseful(bodyType), safeName: "body", required: true });
|
|
21750
|
+
} else {
|
|
21751
|
+
sig.push({
|
|
21752
|
+
decl: `${optionalNative(bodyType)} $body = null`,
|
|
21753
|
+
docType: nullableDoc(docTypeIfUseful(bodyType)),
|
|
21754
|
+
safeName: "body",
|
|
21755
|
+
required: false
|
|
21756
|
+
});
|
|
21757
|
+
}
|
|
21758
|
+
}
|
|
21759
|
+
for (const e of [...queryParams, ...headerParams]) {
|
|
21760
|
+
if (e.param.required) {
|
|
21761
|
+
sig.push({ decl: `${e.type.native} $${e.safeName}`, docType: docTypeIfUseful(e.type), safeName: e.safeName, required: true });
|
|
21762
|
+
} else {
|
|
21763
|
+
sig.push({
|
|
21764
|
+
decl: `${optionalNative(e.type)} $${e.safeName} = null`,
|
|
21765
|
+
docType: nullableDoc(docTypeIfUseful(e.type)),
|
|
21766
|
+
safeName: e.safeName,
|
|
21767
|
+
required: false
|
|
21768
|
+
});
|
|
21769
|
+
}
|
|
21770
|
+
}
|
|
21771
|
+
const ordered = [...sig.filter((s) => s.required), ...sig.filter((s) => !s.required)];
|
|
21772
|
+
const responseDocType = getPhpResponseDocType(op, pctx);
|
|
21773
|
+
const lines = [];
|
|
21774
|
+
lines.push(" /**");
|
|
21775
|
+
if (op.description) {
|
|
21776
|
+
lines.push(` * ${op.description.replace(/\n/g, " ").trim()}`);
|
|
21777
|
+
lines.push(" *");
|
|
21778
|
+
}
|
|
21779
|
+
for (const s of ordered) {
|
|
21780
|
+
if (s.docType) {
|
|
21781
|
+
lines.push(` * @param ${s.docType} $${s.safeName}`);
|
|
21782
|
+
}
|
|
21783
|
+
}
|
|
21784
|
+
lines.push(` * @return ApiResponse<${responseDocType}>`);
|
|
21785
|
+
lines.push(" * @throws ApiException");
|
|
21786
|
+
if (op.deprecated && !features.deprecatedAttribute) {
|
|
21787
|
+
lines.push(" * @deprecated Deprecated in the OpenAPI specification");
|
|
21788
|
+
}
|
|
21789
|
+
lines.push(" */");
|
|
21790
|
+
if (op.deprecated && features.deprecatedAttribute) {
|
|
21791
|
+
lines.push(" #[\\Deprecated(message: 'Deprecated in the OpenAPI specification')]");
|
|
21792
|
+
}
|
|
21793
|
+
if (features.noDiscard) {
|
|
21794
|
+
lines.push(" #[\\NoDiscard]");
|
|
21795
|
+
}
|
|
21796
|
+
lines.push(` public function ${op.operationId}(${ordered.map((s) => s.decl).join(", ")}): ApiResponse`);
|
|
21797
|
+
lines.push(" {");
|
|
21798
|
+
if (queryParams.length > 0) {
|
|
21799
|
+
lines.push(" $query = [];");
|
|
21800
|
+
for (const e of queryParams) {
|
|
21801
|
+
const value = phpStringify(e.param.schema, `$${e.safeName}`, pctx);
|
|
21802
|
+
if (e.param.required) {
|
|
21803
|
+
lines.push(` $query[${quotePhpString(e.param.name)}] = ${value};`);
|
|
21804
|
+
} else {
|
|
21805
|
+
lines.push(` if ($${e.safeName} !== null) {`);
|
|
21806
|
+
lines.push(` $query[${quotePhpString(e.param.name)}] = ${value};`);
|
|
21807
|
+
lines.push(" }");
|
|
21808
|
+
}
|
|
21809
|
+
}
|
|
21810
|
+
lines.push("");
|
|
21811
|
+
}
|
|
21812
|
+
if (headerParams.length > 0) {
|
|
21813
|
+
lines.push(" $headerValues = [];");
|
|
21814
|
+
for (const e of headerParams) {
|
|
21815
|
+
const value = phpStringify(e.param.schema, `$${e.safeName}`, pctx);
|
|
21816
|
+
if (e.param.required) {
|
|
21817
|
+
lines.push(` $headerValues[${quotePhpString(e.param.name)}] = ${value};`);
|
|
21818
|
+
} else {
|
|
21819
|
+
lines.push(` if ($${e.safeName} !== null) {`);
|
|
21820
|
+
lines.push(` $headerValues[${quotePhpString(e.param.name)}] = ${value};`);
|
|
21821
|
+
lines.push(" }");
|
|
21822
|
+
}
|
|
21823
|
+
}
|
|
21824
|
+
lines.push("");
|
|
21825
|
+
}
|
|
21826
|
+
const pathExpr = phpPathExpr(op.path, pathParams, pctx);
|
|
21827
|
+
if (features.uriExtension) {
|
|
21828
|
+
lines.push(` $url = new \\Uri\\Rfc3986\\Uri($this->baseUrl . ${pathExpr})->toString();`);
|
|
21829
|
+
} else {
|
|
21830
|
+
lines.push(` $url = $this->baseUrl . ${pathExpr};`);
|
|
21831
|
+
}
|
|
21832
|
+
const hasOptions = queryParams.length > 0 || headerParams.length > 0 || bodyType !== null;
|
|
21833
|
+
if (hasOptions) {
|
|
21834
|
+
lines.push(" $options = [];");
|
|
21835
|
+
if (queryParams.length > 0) {
|
|
21836
|
+
if (queryParams.some((e) => e.param.required)) {
|
|
21837
|
+
lines.push(" $options['query'] = $query;");
|
|
21838
|
+
} else {
|
|
21839
|
+
lines.push(" if ($query !== []) {");
|
|
21840
|
+
lines.push(" $options['query'] = $query;");
|
|
21841
|
+
lines.push(" }");
|
|
21842
|
+
}
|
|
21843
|
+
}
|
|
21844
|
+
if (headerParams.length > 0) {
|
|
21845
|
+
if (headerParams.some((e) => e.param.required)) {
|
|
21846
|
+
lines.push(" $options['headers'] = $headerValues;");
|
|
21847
|
+
} else {
|
|
21848
|
+
lines.push(" if ($headerValues !== []) {");
|
|
21849
|
+
lines.push(" $options['headers'] = $headerValues;");
|
|
21850
|
+
lines.push(" }");
|
|
21851
|
+
}
|
|
21852
|
+
}
|
|
21853
|
+
if (bodyType) {
|
|
21854
|
+
const body = phpBodyLines(bodyType);
|
|
21855
|
+
if (bodyRequired) {
|
|
21856
|
+
lines.push(...body.map((l) => ` ${l}`));
|
|
21857
|
+
} else {
|
|
21858
|
+
lines.push(" if ($body !== null) {");
|
|
21859
|
+
lines.push(...body.map((l) => ` ${l}`));
|
|
21860
|
+
lines.push(" }");
|
|
21861
|
+
}
|
|
21862
|
+
}
|
|
21863
|
+
lines.push("");
|
|
21864
|
+
lines.push(` $response = $this->client->request(${quotePhpString(op.method.toUpperCase())}, $url, $options);`);
|
|
21865
|
+
} else {
|
|
21866
|
+
lines.push("");
|
|
21867
|
+
lines.push(` $response = $this->client->request(${quotePhpString(op.method.toUpperCase())}, $url);`);
|
|
21868
|
+
}
|
|
21869
|
+
lines.push("");
|
|
21870
|
+
lines.push(" $statusCode = $response->getStatusCode();");
|
|
21871
|
+
lines.push(" $content = $response->getContent(false);");
|
|
21872
|
+
lines.push(" $headers = $response->getHeaders(false);");
|
|
21873
|
+
lines.push(" $requestUrl = (string) $response->getInfo('url');");
|
|
21874
|
+
lines.push("");
|
|
21875
|
+
lines.push(" return match (true) {");
|
|
21876
|
+
for (const c of generatePhpResponseCases(op, pctx)) {
|
|
21877
|
+
lines.push(` ${c}`);
|
|
21878
|
+
}
|
|
21879
|
+
lines.push(" };");
|
|
21880
|
+
lines.push(" }");
|
|
21881
|
+
return lines.join("\n");
|
|
21882
|
+
}
|
|
21883
|
+
function optionalNative(type) {
|
|
21884
|
+
if (type.native === "mixed" || type.native.startsWith("?")) return type.native;
|
|
21885
|
+
return `?${type.native}`;
|
|
21886
|
+
}
|
|
21887
|
+
function docTypeIfUseful(type) {
|
|
21888
|
+
return type.doc.includes("[]") || type.doc.includes("array<") ? type.doc : null;
|
|
21889
|
+
}
|
|
21890
|
+
function nullableDoc(doc) {
|
|
21891
|
+
if (doc === null) return null;
|
|
21892
|
+
return doc.endsWith("|null") ? doc : `${doc}|null`;
|
|
21893
|
+
}
|
|
21894
|
+
function phpBodyLines(bodyType) {
|
|
21895
|
+
const bare = bodyType.native.replace("?", "");
|
|
21896
|
+
const isModelLike = bodyType.deserialize.kind !== "json" || bare === "array";
|
|
21897
|
+
if (!isModelLike) {
|
|
21898
|
+
return ["$options['json'] = $body;"];
|
|
21899
|
+
}
|
|
21900
|
+
return [
|
|
21901
|
+
"$options['headers']['Content-Type'] = 'application/json';",
|
|
21902
|
+
"$options['body'] = $this->serializer->serialize($body, 'json', [AbstractObjectNormalizer::SKIP_NULL_VALUES => true]);"
|
|
21903
|
+
];
|
|
21904
|
+
}
|
|
21905
|
+
function phpPathExpr(path, pathParams, pctx) {
|
|
21906
|
+
const parts = [];
|
|
21907
|
+
const regex = /\{([^}]+)\}/g;
|
|
21908
|
+
let lastIndex = 0;
|
|
21909
|
+
let match;
|
|
21910
|
+
while ((match = regex.exec(path)) !== null) {
|
|
21911
|
+
const literal = path.slice(lastIndex, match.index);
|
|
21912
|
+
if (literal) parts.push(quotePhpString(literal));
|
|
21913
|
+
parts.push(pathParamExpr(match[1], pathParams, pctx));
|
|
21914
|
+
lastIndex = regex.lastIndex;
|
|
21915
|
+
}
|
|
21916
|
+
const tail = path.slice(lastIndex);
|
|
21917
|
+
if (tail) parts.push(quotePhpString(tail));
|
|
21918
|
+
return parts.length > 0 ? parts.join(" . ") : quotePhpString(path);
|
|
21919
|
+
}
|
|
21920
|
+
function pathParamExpr(paramName, pathParams, pctx) {
|
|
21921
|
+
const entry = pathParams.find((e) => e.param.name === paramName);
|
|
21922
|
+
if (!entry) return quotePhpString(`{${paramName}}`);
|
|
21923
|
+
const stringified = phpStringify(entry.param.schema, `$${entry.safeName}`, pctx);
|
|
21924
|
+
const needsCast = stringified === `$${entry.safeName}` && entry.type.native.replace("?", "") !== "string";
|
|
21925
|
+
return `rawurlencode(${needsCast ? `(string) $${entry.safeName}` : stringified})`;
|
|
21926
|
+
}
|
|
21927
|
+
|
|
21928
|
+
// src/modes/php/query.ts
|
|
21929
|
+
function generatePhpQuery(op, pctx) {
|
|
21930
|
+
return generatePhpOperation(op, pctx);
|
|
21931
|
+
}
|
|
21932
|
+
|
|
21933
|
+
// src/modes/php/mutation.ts
|
|
21934
|
+
function generatePhpMutation(op, pctx) {
|
|
21935
|
+
return generatePhpOperation(op, pctx);
|
|
21936
|
+
}
|
|
21937
|
+
|
|
21938
|
+
// src/modes/php/runtime.ts
|
|
21939
|
+
function generatePhpRuntimeFiles(php, features) {
|
|
21940
|
+
const files = /* @__PURE__ */ new Map();
|
|
21941
|
+
files.set("ApiResponse.php", phpFile(php.namespace, [], apiResponseClass(features)));
|
|
21942
|
+
files.set("ApiException.php", phpFile(php.namespace, [], apiExceptionClass(features)));
|
|
21943
|
+
files.set("SerializerFactory.php", phpFile(php.namespace, serializerFactoryUses(features), serializerFactoryClass(features)));
|
|
21944
|
+
return files;
|
|
21945
|
+
}
|
|
21946
|
+
function apiResponseClass(features) {
|
|
21947
|
+
const classKeywords = features.readonlyClass ? "final readonly class" : "final class";
|
|
21948
|
+
const prop = features.readonlyClass ? "public" : features.readonlyProps ? "public readonly" : "public";
|
|
21949
|
+
return [
|
|
21950
|
+
"/**",
|
|
21951
|
+
" * @template T",
|
|
21952
|
+
" */",
|
|
21953
|
+
`${classKeywords} ApiResponse`,
|
|
21954
|
+
"{",
|
|
21955
|
+
" /**",
|
|
21956
|
+
" * @param T $data",
|
|
21957
|
+
" * @param array<string, string[]> $headers Response headers (keys are lower-cased by Symfony HttpClient)",
|
|
21958
|
+
" */",
|
|
21959
|
+
" public function __construct(",
|
|
21960
|
+
` ${prop} mixed $data,`,
|
|
21961
|
+
` ${prop} int $status,`,
|
|
21962
|
+
` ${prop} array $headers,`,
|
|
21963
|
+
` ${prop} string $url,`,
|
|
21964
|
+
" ) {",
|
|
21965
|
+
" }",
|
|
21966
|
+
"}"
|
|
21967
|
+
].join("\n");
|
|
21968
|
+
}
|
|
21969
|
+
function apiExceptionClass(features) {
|
|
21970
|
+
const prop = features.readonlyProps ? "public readonly" : "public";
|
|
21971
|
+
return [
|
|
21972
|
+
"class ApiException extends \\RuntimeException",
|
|
21973
|
+
"{",
|
|
21974
|
+
" /**",
|
|
21975
|
+
" * @param array<string, string[]> $responseHeaders",
|
|
21976
|
+
" */",
|
|
21977
|
+
" public function __construct(",
|
|
21978
|
+
` ${prop} int $statusCode,`,
|
|
21979
|
+
` ${prop} ?string $body,`,
|
|
21980
|
+
` ${prop} array $responseHeaders,`,
|
|
21981
|
+
` ${prop} string $url,`,
|
|
21982
|
+
" ) {",
|
|
21983
|
+
" parent::__construct(sprintf('API error %d (%s)', $statusCode, $url));",
|
|
21984
|
+
" }",
|
|
21985
|
+
"}"
|
|
21986
|
+
].join("\n");
|
|
21987
|
+
}
|
|
21988
|
+
function serializerFactoryUses(features) {
|
|
21989
|
+
const uses = [
|
|
21990
|
+
"Symfony\\Component\\PropertyInfo\\Extractor\\PhpDocExtractor",
|
|
21991
|
+
"Symfony\\Component\\PropertyInfo\\Extractor\\ReflectionExtractor",
|
|
21992
|
+
"Symfony\\Component\\PropertyInfo\\PropertyInfoExtractor",
|
|
21993
|
+
"Symfony\\Component\\Serializer\\Encoder\\JsonEncoder",
|
|
21994
|
+
"Symfony\\Component\\Serializer\\Mapping\\Factory\\ClassMetadataFactory",
|
|
21995
|
+
"Symfony\\Component\\Serializer\\NameConverter\\MetadataAwareNameConverter",
|
|
21996
|
+
"Symfony\\Component\\Serializer\\Normalizer\\ArrayDenormalizer",
|
|
21997
|
+
"Symfony\\Component\\Serializer\\Normalizer\\ObjectNormalizer",
|
|
21998
|
+
"Symfony\\Component\\Serializer\\Serializer"
|
|
21999
|
+
];
|
|
22000
|
+
if (features.enums) {
|
|
22001
|
+
uses.push("Symfony\\Component\\Serializer\\Mapping\\Loader\\AttributeLoader");
|
|
22002
|
+
uses.push("Symfony\\Component\\Serializer\\Normalizer\\BackedEnumNormalizer");
|
|
22003
|
+
} else {
|
|
22004
|
+
uses.push("Symfony\\Component\\Serializer\\Mapping\\Loader\\AnnotationLoader");
|
|
22005
|
+
}
|
|
22006
|
+
return uses;
|
|
22007
|
+
}
|
|
22008
|
+
function serializerFactoryClass(features) {
|
|
22009
|
+
const loader = features.enums ? "AttributeLoader" : "AnnotationLoader";
|
|
22010
|
+
const normalizers = features.enums ? [
|
|
22011
|
+
" new BackedEnumNormalizer(),",
|
|
22012
|
+
" new ArrayDenormalizer(),",
|
|
22013
|
+
" new ObjectNormalizer($classMetadataFactory, $nameConverter, null, $propertyInfo),"
|
|
22014
|
+
] : [" new ArrayDenormalizer(),", " new ObjectNormalizer($classMetadataFactory, $nameConverter, null, $propertyInfo),"];
|
|
22015
|
+
return [
|
|
22016
|
+
"final class SerializerFactory",
|
|
22017
|
+
"{",
|
|
22018
|
+
" public static function create(): Serializer",
|
|
22019
|
+
" {",
|
|
22020
|
+
` $classMetadataFactory = new ClassMetadataFactory(new ${loader}());`,
|
|
22021
|
+
" $nameConverter = new MetadataAwareNameConverter($classMetadataFactory);",
|
|
22022
|
+
" $propertyInfo = new PropertyInfoExtractor(",
|
|
22023
|
+
" [],",
|
|
22024
|
+
" [new PhpDocExtractor(), new ReflectionExtractor()],",
|
|
22025
|
+
" );",
|
|
22026
|
+
"",
|
|
22027
|
+
" return new Serializer(",
|
|
22028
|
+
" [",
|
|
22029
|
+
...normalizers,
|
|
22030
|
+
" ],",
|
|
22031
|
+
" [new JsonEncoder()],",
|
|
22032
|
+
" );",
|
|
22033
|
+
" }",
|
|
22034
|
+
"}"
|
|
22035
|
+
].join("\n");
|
|
22036
|
+
}
|
|
22037
|
+
|
|
22038
|
+
// src/modes/php/index.ts
|
|
22039
|
+
var phpMode = {
|
|
22040
|
+
name: "php",
|
|
22041
|
+
nativeTarget: true,
|
|
22042
|
+
generateFiles(ctx) {
|
|
22043
|
+
const php = ctx.php ?? { namespace: ctx.clientName, phpVersion: "8.1" };
|
|
22044
|
+
const features = phpFeatures(php.phpVersion);
|
|
22045
|
+
const conv = createConversionContext(new Set(ctx.document.schemas.keys()), void 0, ctx.document.schemas);
|
|
22046
|
+
const kinds = classifyPhpSchemas(ctx.document.schemas, features);
|
|
22047
|
+
const modelCtx = { conv, php, features, kinds, classPrefix: "" };
|
|
22048
|
+
const clientCtx = { ...modelCtx, classPrefix: "Model\\" };
|
|
22049
|
+
const files = /* @__PURE__ */ new Map();
|
|
22050
|
+
for (const [name, schema] of ctx.document.schemas) {
|
|
22051
|
+
const chunk = generatePhpModel(name, schema, modelCtx);
|
|
22052
|
+
if (!chunk) continue;
|
|
22053
|
+
files.set(`Model/${phpClassName(name)}.php`, phpFile(`${php.namespace}\\Model`, chunk.uses, chunk.code));
|
|
22054
|
+
}
|
|
22055
|
+
for (const [relPath, content] of generatePhpRuntimeFiles(php, features)) {
|
|
22056
|
+
files.set(relPath, content);
|
|
22057
|
+
}
|
|
22058
|
+
files.set(`${ctx.clientName}.php`, generatePhpClientFile(ctx, clientCtx));
|
|
22059
|
+
return files;
|
|
22060
|
+
}
|
|
22061
|
+
};
|
|
22062
|
+
function generatePhpClientFile(ctx, pctx) {
|
|
22063
|
+
const { clientName } = ctx;
|
|
22064
|
+
const { features, php } = pctx;
|
|
22065
|
+
const servers = ctx.document.servers;
|
|
22066
|
+
const defaultServer = servers[0];
|
|
22067
|
+
const lines = [];
|
|
22068
|
+
lines.push(`final class ${clientName}`);
|
|
22069
|
+
lines.push("{");
|
|
22070
|
+
if (defaultServer) {
|
|
22071
|
+
if (features.typedConstants) {
|
|
22072
|
+
lines.push(` public const string DEFAULT_BASE_URL = ${quotePhpString(defaultServer.url)};`);
|
|
22073
|
+
} else {
|
|
22074
|
+
lines.push(` public const DEFAULT_BASE_URL = ${quotePhpString(defaultServer.url)};`);
|
|
22075
|
+
}
|
|
22076
|
+
lines.push("");
|
|
22077
|
+
lines.push(" /** @var array<string, string> */");
|
|
22078
|
+
const constKeyword = features.typedConstants ? "public const array" : "public const";
|
|
22079
|
+
lines.push(` ${constKeyword} SERVERS = [`);
|
|
22080
|
+
for (const server of servers) {
|
|
22081
|
+
lines.push(` ${quotePhpString(server.name)} => ${quotePhpString(server.url)},`);
|
|
22082
|
+
}
|
|
22083
|
+
lines.push(" ];");
|
|
22084
|
+
lines.push("");
|
|
22085
|
+
}
|
|
22086
|
+
const propKeyword = features.readonlyProps ? "private readonly" : "private";
|
|
22087
|
+
lines.push(` ${propKeyword} SerializerInterface $serializer;`);
|
|
22088
|
+
lines.push("");
|
|
22089
|
+
lines.push(" public function __construct(");
|
|
22090
|
+
lines.push(` ${propKeyword} HttpClientInterface $client,`);
|
|
22091
|
+
if (defaultServer) {
|
|
22092
|
+
lines.push(` ${propKeyword} string $baseUrl = self::DEFAULT_BASE_URL,`);
|
|
22093
|
+
} else {
|
|
22094
|
+
lines.push(` ${propKeyword} string $baseUrl,`);
|
|
22095
|
+
}
|
|
22096
|
+
lines.push(" ?SerializerInterface $serializer = null,");
|
|
22097
|
+
lines.push(" ) {");
|
|
22098
|
+
lines.push(" $this->serializer = $serializer ?? SerializerFactory::create();");
|
|
22099
|
+
lines.push(" }");
|
|
22100
|
+
const queries = ctx.document.operations.filter((op) => op.type === "query");
|
|
22101
|
+
const mutations = ctx.document.operations.filter((op) => op.type === "mutation");
|
|
22102
|
+
if (queries.length > 0) {
|
|
22103
|
+
lines.push("");
|
|
22104
|
+
lines.push(" // \u2500\u2500 Queries \u2500\u2500");
|
|
22105
|
+
for (const op of queries) {
|
|
22106
|
+
lines.push("");
|
|
22107
|
+
lines.push(generatePhpQuery(op, pctx));
|
|
22108
|
+
}
|
|
22109
|
+
}
|
|
22110
|
+
if (mutations.length > 0) {
|
|
22111
|
+
lines.push("");
|
|
22112
|
+
lines.push(" // \u2500\u2500 Mutations \u2500\u2500");
|
|
22113
|
+
for (const op of mutations) {
|
|
22114
|
+
lines.push("");
|
|
22115
|
+
lines.push(generatePhpMutation(op, pctx));
|
|
22116
|
+
}
|
|
22117
|
+
}
|
|
22118
|
+
lines.push("}");
|
|
22119
|
+
const code = lines.join("\n");
|
|
22120
|
+
const uses = ["Symfony\\Component\\Serializer\\SerializerInterface", "Symfony\\Contracts\\HttpClient\\HttpClientInterface"];
|
|
22121
|
+
if (code.includes("AbstractObjectNormalizer::")) {
|
|
22122
|
+
uses.push("Symfony\\Component\\Serializer\\Normalizer\\AbstractObjectNormalizer");
|
|
22123
|
+
}
|
|
22124
|
+
return phpFile(php.namespace, uses, code);
|
|
22125
|
+
}
|
|
22126
|
+
|
|
21165
22127
|
// src/modes/mode.ts
|
|
21166
22128
|
function getMode(name) {
|
|
21167
22129
|
switch (name) {
|
|
@@ -21173,8 +22135,10 @@ function getMode(name) {
|
|
|
21173
22135
|
return swiftMode;
|
|
21174
22136
|
case "kotlin":
|
|
21175
22137
|
return kotlinMode;
|
|
22138
|
+
case "php":
|
|
22139
|
+
return phpMode;
|
|
21176
22140
|
default:
|
|
21177
|
-
throw new Error(`Unknown mode: ${name}. Expected "full", "playwright", "swift", or "
|
|
22141
|
+
throw new Error(`Unknown mode: ${name}. Expected "full", "playwright", "swift", "kotlin", or "php".`);
|
|
21178
22142
|
}
|
|
21179
22143
|
}
|
|
21180
22144
|
|
|
@@ -21289,25 +22253,40 @@ function filterUsedImports(names, source, importStatement) {
|
|
|
21289
22253
|
// src/pipeline.ts
|
|
21290
22254
|
async function generate(options) {
|
|
21291
22255
|
const { input: input2, outputDir: outputDir2, name, mode: modeName } = options;
|
|
22256
|
+
const mode2 = getMode(modeName);
|
|
21292
22257
|
const document = await parseOpenApiDocument((0, import_node_path.resolve)(input2));
|
|
21293
|
-
if (
|
|
22258
|
+
if (mode2.nativeTarget) {
|
|
21294
22259
|
hoistAnonymousSchemas(document);
|
|
21295
22260
|
}
|
|
21296
22261
|
document.schemas = topologicalSortSchemas(document.schemas);
|
|
21297
|
-
const mode2 = getMode(modeName);
|
|
21298
22262
|
const ctx = {
|
|
21299
22263
|
document,
|
|
21300
22264
|
zodSchemas: /* @__PURE__ */ new Map(),
|
|
21301
22265
|
clientName: name,
|
|
21302
22266
|
mode: modeName
|
|
21303
22267
|
};
|
|
22268
|
+
if (modeName === "php") {
|
|
22269
|
+
ctx.php = {
|
|
22270
|
+
namespace: options.namespace ?? name,
|
|
22271
|
+
phpVersion: options.phpVersion ?? "8.1"
|
|
22272
|
+
};
|
|
22273
|
+
}
|
|
21304
22274
|
const namedSchemas = new Set(document.schemas.keys());
|
|
21305
22275
|
const convCtx = createConversionContext(namedSchemas, void 0, document.schemas);
|
|
21306
|
-
if (
|
|
22276
|
+
if (!mode2.nativeTarget) {
|
|
21307
22277
|
for (const [schemaName, schema] of document.schemas) {
|
|
21308
22278
|
ctx.zodSchemas.set(schemaName, schemaToZod(schema, convCtx));
|
|
21309
22279
|
}
|
|
21310
22280
|
}
|
|
22281
|
+
if ("generateFiles" in mode2) {
|
|
22282
|
+
const rootDir = (0, import_node_path.resolve)(outputDir2, name);
|
|
22283
|
+
for (const [relPath, content] of mode2.generateFiles(ctx)) {
|
|
22284
|
+
const absPath = (0, import_node_path.join)(rootDir, relPath);
|
|
22285
|
+
(0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(absPath), { recursive: true });
|
|
22286
|
+
(0, import_node_fs.writeFileSync)(absPath, content, "utf-8");
|
|
22287
|
+
}
|
|
22288
|
+
return rootDir;
|
|
22289
|
+
}
|
|
21311
22290
|
const parts = [];
|
|
21312
22291
|
parts.push(mode2.generateImports(ctx));
|
|
21313
22292
|
parts.push(mode2.generateHelperTypes(ctx));
|
|
@@ -21325,10 +22304,9 @@ async function generate(options) {
|
|
|
21325
22304
|
}
|
|
21326
22305
|
}
|
|
21327
22306
|
parts.push(mode2.generateClient(document.operations, ctx));
|
|
21328
|
-
const output =
|
|
22307
|
+
const output = mode2.nativeTarget ? parts.join("\n") : removeDeadCode(parts.join("\n"));
|
|
21329
22308
|
(0, import_node_fs.mkdirSync)((0, import_node_path.resolve)(outputDir2), { recursive: true });
|
|
21330
|
-
const
|
|
21331
|
-
const ext = extMap[modeName] ?? ".ts";
|
|
22309
|
+
const ext = mode2.fileExtension ?? ".ts";
|
|
21332
22310
|
const outputPath = (0, import_node_path.resolve)(outputDir2, `${name}${ext}`);
|
|
21333
22311
|
(0, import_node_fs.writeFileSync)(outputPath, output, "utf-8");
|
|
21334
22312
|
return outputPath;
|
|
@@ -21545,21 +22523,28 @@ function generateSchemaSection(ctx, namedSchemas, convCtx) {
|
|
|
21545
22523
|
return lines.join("\n");
|
|
21546
22524
|
}
|
|
21547
22525
|
|
|
22526
|
+
// src/types.ts
|
|
22527
|
+
var PHP_VERSIONS = ["8.0", "8.1", "8.2", "8.3", "8.4", "8.5"];
|
|
22528
|
+
|
|
21548
22529
|
// src/bin.ts
|
|
21549
22530
|
var HELP = `
|
|
21550
|
-
Usage: openapi-client <spec.json> <output-dir> -n <ClassName> [-m full|playwright|swift|kotlin]
|
|
22531
|
+
Usage: openapi-client <spec.json> <output-dir> -n <ClassName> [-m full|playwright|swift|kotlin|php]
|
|
21551
22532
|
|
|
21552
22533
|
Options:
|
|
21553
|
-
-n, --name <name>
|
|
21554
|
-
-m, --mode <mode>
|
|
21555
|
-
|
|
21556
|
-
|
|
22534
|
+
-n, --name <name> Client class name (required)
|
|
22535
|
+
-m, --mode <mode> Generation mode: "full", "playwright", "swift", "kotlin", or "php" (default: "full")
|
|
22536
|
+
--namespace <ns> Root PHP namespace, php mode only (default: --name)
|
|
22537
|
+
--php-version <v> Target PHP version, php mode only: ${PHP_VERSIONS.join("|")} (default: "8.1")
|
|
22538
|
+
-v, --version Show version
|
|
22539
|
+
-h, --help Show help
|
|
21557
22540
|
`;
|
|
21558
22541
|
var { values, positionals } = (0, import_node_util.parseArgs)({
|
|
21559
22542
|
args: process.argv.slice(2),
|
|
21560
22543
|
options: {
|
|
21561
22544
|
name: { type: "string", short: "n" },
|
|
21562
22545
|
mode: { type: "string", short: "m", default: "full" },
|
|
22546
|
+
namespace: { type: "string" },
|
|
22547
|
+
"php-version": { type: "string", default: "8.1" },
|
|
21563
22548
|
version: { type: "boolean", short: "v" },
|
|
21564
22549
|
help: { type: "boolean", short: "h" }
|
|
21565
22550
|
},
|
|
@@ -21590,12 +22575,36 @@ if (!TS_IDENTIFIER_RE.test(values.name)) {
|
|
|
21590
22575
|
process.exit(1);
|
|
21591
22576
|
}
|
|
21592
22577
|
var mode = values.mode;
|
|
21593
|
-
if (mode !== "full" && mode !== "playwright" && mode !== "swift" && mode !== "kotlin") {
|
|
21594
|
-
console.error(`Error: --mode must be "full", "playwright", "swift", or "
|
|
22578
|
+
if (mode !== "full" && mode !== "playwright" && mode !== "swift" && mode !== "kotlin" && mode !== "php") {
|
|
22579
|
+
console.error(`Error: --mode must be "full", "playwright", "swift", "kotlin", or "php", got "${mode}".`);
|
|
21595
22580
|
process.exit(1);
|
|
21596
22581
|
}
|
|
22582
|
+
var phpVersion = values["php-version"];
|
|
22583
|
+
if (mode === "php") {
|
|
22584
|
+
const PHP_IDENTIFIER_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
22585
|
+
const PHP_NAMESPACE_RE = /^[a-zA-Z_][a-zA-Z0-9_]*(\\[a-zA-Z_][a-zA-Z0-9_]*)*$/;
|
|
22586
|
+
if (!PHP_IDENTIFIER_RE.test(values.name)) {
|
|
22587
|
+
console.error(`Error: --name "${values.name}" is not a valid PHP class name.`);
|
|
22588
|
+
process.exit(1);
|
|
22589
|
+
}
|
|
22590
|
+
if (values.namespace !== void 0 && !PHP_NAMESPACE_RE.test(values.namespace)) {
|
|
22591
|
+
console.error(`Error: --namespace "${values.namespace}" is not a valid PHP namespace (expected e.g. "App\\Api\\Petstore").`);
|
|
22592
|
+
process.exit(1);
|
|
22593
|
+
}
|
|
22594
|
+
if (!PHP_VERSIONS.includes(phpVersion)) {
|
|
22595
|
+
console.error(`Error: --php-version must be one of ${PHP_VERSIONS.join(", ")}, got "${phpVersion}".`);
|
|
22596
|
+
process.exit(1);
|
|
22597
|
+
}
|
|
22598
|
+
} else {
|
|
22599
|
+
if (values.namespace !== void 0) {
|
|
22600
|
+
console.warn(`Warning: --namespace is only used in php mode, ignoring.`);
|
|
22601
|
+
}
|
|
22602
|
+
if (values["php-version"] !== "8.1") {
|
|
22603
|
+
console.warn(`Warning: --php-version is only used in php mode, ignoring.`);
|
|
22604
|
+
}
|
|
22605
|
+
}
|
|
21597
22606
|
console.log(`Generating ${values.name} in ${mode} mode from ${input}...`);
|
|
21598
|
-
generate({ input, outputDir, name: values.name, mode }).then((outputPath) => {
|
|
22607
|
+
generate({ input, outputDir, name: values.name, mode, namespace: values.namespace, phpVersion }).then((outputPath) => {
|
|
21599
22608
|
console.log(`Generated: ${outputPath}`);
|
|
21600
22609
|
}).catch((error) => {
|
|
21601
22610
|
console.error("Generation failed:", error.message || error);
|