3 Commits

Author SHA1 Message Date
1f32935a29 added return structure 2026-03-29 13:37:14 +02:00
951fe36da3 fixed parames of interface for type-check 2026-02-14 06:28:03 +01:00
d258bcc919 separated JavaScript and TypeScript export,
added AGENTS.md for AI bot
2026-02-13 09:54:08 +01:00
8 changed files with 534 additions and 133 deletions

37
AGENTS.md Normal file
View File

@ -0,0 +1,37 @@
# AGENTS.md
## Project overview
APIlite is a lightweight PHP library. A class extends `TPsoft\APIlite\APIlite`, public methods become API actions, requests are processed automatically, and responses are returned as JSON.
The project also generates frontend clients:
- JavaScript client: `format=javascript` (`.js`)
- TypeScript client: `format=typescript` (`.ts`, real typed output)
## Core files
- `src/APIlite.php`: runtime, routing, docs JSON/HTML/client generation
- `src/help.tpl.php`: HTML documentation template
- `src/javascript.tpl.php`: JavaScript client template
- `src/typescript.tpl.php`: TypeScript client template
- `bin/apilite-files`: helper script for bootstrapping files in consumer projects
## Working rules
- Keep API behavior backward compatible unless explicitly requested.
- Maintain both generated clients:
- JavaScript stays plain JS.
- TypeScript stays typed (interfaces + typed method signatures).
- If you change output field names in JSON help, update README and templates consistently.
- Prefer small, focused changes over broad rewrites.
## Verification checklist
- Run syntax checks on edited PHP files:
- `php -l src/APIlite.php`
- `php -l src/help.tpl.php`
- `php -l src/javascript.tpl.php`
- `php -l src/typescript.tpl.php`
- `php -l bin/apilite-files`
- If client generation changes, test with:
- `php test/APIcalculator.php --javascript`
- `php test/APIcalculator.php --typescript`
## Documentation rule
When output format names/flags/URLs change, update `README.md` in the same change set.

100
README.md
View File

@ -132,6 +132,7 @@ When you run this subfile through the webserver, you will see the JSON documenta
{
"name": "APIcalculator",
"html_version": "http://localhost/APIlite/test/APIcalculator.php?format=html",
"javascript_version": "http://localhost/APIlite/test/APIcalculator.php?format=javascript",
"typescript_version": "http://localhost/APIlite/test/APIcalculator.php?format=typescript",
"actions": [
{
@ -230,84 +231,35 @@ and there is also an HTML version available
<img src="test/Example.APIcalculator.png" />
To connect to the API from TypeScript (e.g. Vue application) it is possible to download the backend script
You can also download generated frontend clients:
```ts
/**
* Generated by APIlite
* https://gitea.tpsoft.org/TPsoft.org/APIlite
*
* 2025-06-12 06:24:33 */
* JavaScript: `?format=javascript`
* TypeScript (typed for Vue/TS projects): `?format=typescript`
class APIcalculator {
endpont = "http://";
JavaScript usage example:
/* ----------------------------------------------------
* General API call
*/
call(method, data, callback) {
var xhttp = new XMLHttpRequest();
xhttp.withCredentials = true;
xhttp.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status == 200) {
if (callback != null) callback(JSON.parse(this.responseText));
} else {
if (callback != null) callback({'status': 'ERROR', 'message': 'HTTP STATUS ' + this.status});
}
}
}
var form_data = new FormData();
Object.keys(data).forEach(key => {
let val = data[key];
if (typeof val == 'object') val = JSON.stringify(val);
form_data.append(key, val);
});
xhttp.open('POST', this.endpont + '?action=' + method);
xhttp.send(form_data);
}
```js
import backend from './backend.js';
callPromise(method, data) {
return new Promise((resolve, reject) => {
this.call(method, data, function(response) {
if (response.status == 'OK') {
resolve(response.data);
} else {
reject(response.msg);
}
});
})
}
/* ----------------------------------------------------
* API actions
*/
help() {
return this.callPromise('__HELP__', {});
}
add(a, b) {
return this.callPromise('add', {a: a, b: b});
}
subtract(a, b) {
return this.callPromise('subtract', {a: a, b: b});
}
multiply(a, b) {
return this.callPromise('multiply', {a: a, b: b});
}
divide(a, b) {
return this.callPromise('divide', {a: a, b: b});
}
};
export default new BackendAPI();
backend.add(1, 2).then((response) => {
console.log(response.data);
});
```
These outputs can also be generated in the command line as follows
TypeScript usage example (Vue + TS):
* for HTML`$> php APIcalculator.php --html`
* for TypeScript`$> php APIcalculator.php --typescript`
```ts
import backend from './backend';
backend.add(1, 2).then((response) => {
console.log(response.data); // typed value based on PHP return type
});
```
If a method return type is a PHP class with public properties, JSON help now also includes `return_structure`, and the generated TypeScript client maps that class to an object shape based on those public properties.
These outputs can also be generated in command line:
* HTML: `$> php APIcalculator.php --html`
* JavaScript: `$> php APIcalculator.php --javascript > backend.js` (`--js` alias is available)
* TypeScript: `$> php APIcalculator.php --typescript > backend.ts`

View File

@ -55,7 +55,7 @@ $backend_api = new TPsoft\BugreportBackend\API(\'typescript\', \'import.meta.env
$output = ob_get_contents();
ob_end_clean();
$ts_path = realpath(__DIR__ . \'/../../frontend/src\').\'/backend.js\';
$ts_path = realpath(__DIR__ . \'/../../frontend/src\').\'/backend.ts\';
$suc = file_put_contents($ts_path, $output);
if ($suc === false) {
echo "✗ TypeScript store into file failed\n";

View File

@ -9,6 +9,7 @@
"rest",
"json",
"php",
"javascript",
"typescript"
],
"authors": [

View File

@ -39,6 +39,9 @@ class APIlite
if (in_array('--html', $switches)) {
$format = 'html';
}
if (in_array('--javascript', $switches) || in_array('--js', $switches)) {
$format = 'javascript';
}
if (in_array('--typescript', $switches)) {
$format = 'typescript';
}
@ -47,6 +50,10 @@ class APIlite
case 'html':
$this->printHelpHTML();
break;
case 'javascript':
case 'js':
$this->printHelpJavascript();
break;
case 'typescript':
$this->printHelpTypescript();
break;
@ -80,7 +87,8 @@ class APIlite
'doc' => null,
'description' => null,
'params' => array(),
'return' => null
'return' => null,
'return_structure' => null
);
$docComment = $ref_method->getDocComment();
if ($docComment) {
@ -108,27 +116,129 @@ class APIlite
}
if ($ref_method->hasReturnType()) {
$ref_type = $ref_method->getReturnType();
if ($ref_type instanceof \ReflectionNamedType) {
$method['return'] = $ref_type->getName();
}
if ($ref_type instanceof \ReflectionUnionType
|| $ref_type instanceof \ReflectionIntersectionType )
{
$types = $ref_type->getTypes();
$method['return'] = [];
foreach ($types as $type) {
if ($type instanceof \ReflectionNamedType) {
$method['return'][] = $type->getName();
}
}
}
$method['return'] = $this->reflectionTypeToNames($ref_type, $ref_method->getDeclaringClass());
$method['return_structure'] = $this->reflectionTypeToStructure($ref_type, $ref_method->getDeclaringClass());
}
$this->methods[] = $method;
}
return true;
}
private function reflectionTypeToNames(?\ReflectionType $ref_type, ?\ReflectionClass $context_class = null): string|array|null
{
if ($ref_type instanceof \ReflectionNamedType) {
$type_name = $this->resolveTypeName($ref_type->getName(), $context_class);
if ($ref_type->allowsNull() && strtolower($type_name) !== 'null' && strtolower($type_name) !== 'mixed') {
return array($type_name, 'null');
}
return $type_name;
}
if ($ref_type instanceof \ReflectionUnionType || $ref_type instanceof \ReflectionIntersectionType) {
$types = array();
foreach ($ref_type->getTypes() as $type) {
if (!$type instanceof \ReflectionNamedType) {
continue;
}
$one_type = $this->reflectionTypeToNames($type, $context_class);
if (is_array($one_type)) {
$types = array_merge($types, $one_type);
} else if (is_string($one_type)) {
$types[] = $one_type;
}
}
$types = array_values(array_unique($types));
return empty($types) ? null : $types;
}
return null;
}
private function reflectionTypeToStructure(?\ReflectionType $ref_type, ?\ReflectionClass $context_class = null, array $visited = array()): array|null
{
if ($ref_type instanceof \ReflectionNamedType) {
return $this->classTypeStructure(
$this->resolveTypeName($ref_type->getName(), $context_class),
$visited
);
}
if ($ref_type instanceof \ReflectionUnionType || $ref_type instanceof \ReflectionIntersectionType) {
$structures = array();
foreach ($ref_type->getTypes() as $type) {
if (!$type instanceof \ReflectionNamedType) {
continue;
}
$structure = $this->reflectionTypeToStructure($type, $context_class, $visited);
if (!is_null($structure)) {
$structures[] = $structure;
}
}
return count($structures) > 0 ? $structures : null;
}
return null;
}
private function classTypeStructure(string $type_name, array $visited = array()): array|null
{
$type_name = ltrim($type_name, '\\');
if ($this->isBuiltinTypeName($type_name) || !class_exists($type_name)) {
return null;
}
if (in_array($type_name, $visited, true)) {
return array(
'type' => $type_name,
'recursive' => true,
'properties' => array()
);
}
$visited[] = $type_name;
$refClass = new \ReflectionClass($type_name);
$properties = array();
foreach ($refClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $ref_property) {
if ($ref_property->isStatic()) {
continue;
}
$property_type = $ref_property->getType();
$properties[] = array(
'name' => $ref_property->getName(),
'type' => $this->reflectionTypeToNames($property_type, $refClass),
'nullable' => is_null($property_type) ? true : $property_type->allowsNull(),
'type_structure' => $this->reflectionTypeToStructure($property_type, $refClass, $visited)
);
}
return array(
'type' => $type_name,
'properties' => $properties
);
}
private function resolveTypeName(string $type_name, ?\ReflectionClass $context_class = null): string
{
$type_name = ltrim($type_name, '\\');
if (is_null($context_class)) {
return $type_name;
}
switch (strtolower($type_name)) {
case 'self':
case 'static':
return $context_class->getName();
case 'parent':
$parent = $context_class->getParentClass();
return $parent ? $parent->getName() : $type_name;
default:
return $type_name;
}
}
private function isBuiltinTypeName(string $type_name): bool
{
return in_array(strtolower(ltrim($type_name, '\\')), array(
'array', 'bool', 'boolean', 'callable', 'closure', 'false', 'float', 'int', 'integer',
'iterable', 'mixed', 'never', 'null', 'object', 'resource', 'scalar', 'string',
'true', 'void'
), true);
}
private function parseDescription(string $doc): string
{
$lines = explode("\n", $doc);
@ -189,6 +299,7 @@ class APIlite
$this->response(array(
'name' => $this->apiName,
'html_version' => $this->getCurrentUrl().'?format=html',
'javascript_version' => $this->getCurrentUrl().'?format=javascript',
'typescript_version' => $this->getCurrentUrl().'?format=typescript',
'actions' => $this->methods
));
@ -199,20 +310,36 @@ class APIlite
include __DIR__ . '/help.tpl.php';
}
private function printHelpTypescript(): void
private function printHelpJavascript(): void
{
ob_clean();
header('Content-Type: application/javascript');
header('Content-Disposition: attachment; filename="' . $this->apiName . '.js"');
include __DIR__ . '/javascript.tpl.php';
}
private function printHelpTypescript(): void
{
ob_clean();
header('Content-Type: application/typescript');
header('Content-Disposition: attachment; filename="' . $this->apiName . '.ts"');
include __DIR__ . '/typescript.tpl.php';
}
private function getCurrentUrl(): string {
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' ||
$_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
$host = $_SERVER['HTTP_HOST'];
$uri = $_SERVER['REQUEST_URI'];
$https = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
$serverPort = isset($_SERVER['SERVER_PORT']) ? (int) $_SERVER['SERVER_PORT'] : null;
$protocol = ($https || $serverPort === 443) ? 'https://' : 'http://';
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
$uri = $_SERVER['REQUEST_URI'] ?? ($_SERVER['SCRIPT_NAME'] ?? '/');
$path = parse_url($uri, PHP_URL_PATH);
if (!is_string($path) || $path === '') {
$path = '/';
}
$path = str_replace('\\', '/', $path);
if (substr($path, 0, 1) !== '/') {
$path = '/' . ltrim($path, '/');
}
return $protocol . $host . $path;
}

View File

@ -1,3 +1,50 @@
<?php
$formatTypeLabel = function (mixed $type): string {
if (is_array($type)) {
return implode(' | ', array_map(function ($item) {
return is_string($item) ? $item : 'mixed';
}, $type));
}
return is_string($type) ? $type : 'mixed';
};
$renderTypeStructure = function (mixed $structure) use (&$renderTypeStructure, $formatTypeLabel): string {
if (!is_array($structure)) {
return '';
}
$structures = (array_key_exists('type', $structure) && array_key_exists('properties', $structure))
? array($structure)
: $structure;
$html = '';
foreach ($structures as $item) {
if (!is_array($item) || !isset($item['type'])) {
continue;
}
$html .= '<div style="margin-top: 1rem; padding: 1rem; background: #f8fafc; border: 1px solid #e1e5e9; border-radius: 8px;">';
$html .= '<div style="font-weight: 600; margin-bottom: 0.75rem;">' . htmlspecialchars($item['type']) . '</div>';
if (!empty($item['recursive'])) {
$html .= '<div style="color: #64748b;">Recursive reference</div>';
} else if (!empty($item['properties']) && is_array($item['properties'])) {
$html .= '<ul style="margin: 0; padding-left: 1.25rem;">';
foreach ($item['properties'] as $property) {
if (!is_array($property) || !isset($property['name'])) {
continue;
}
$html .= '<li style="margin-bottom: 0.5rem;">';
$html .= htmlspecialchars((string) $property['name']);
$html .= '<code class="parameter-type">' . htmlspecialchars($formatTypeLabel($property['type'] ?? null)) . '</code>';
$html .= $renderTypeStructure($property['type_structure'] ?? null);
$html .= '</li>';
}
$html .= '</ul>';
} else {
$html .= '<div style="color: #64748b;">No public properties</div>';
}
$html .= '</div>';
}
return $html;
};
?>
<!DOCTYPE html>
<html lang="en">
@ -396,6 +443,7 @@
<nav class="nav-menu">
<div class="nav-links">
<a href="<?php echo $this->getCurrentUrl(); ?>?format=json">🔗 JSON Documentation</a>
<a href="<?php echo $this->getCurrentUrl(); ?>?format=javascript">📄 JavaScript backend script</a>
<a href="<?php echo $this->getCurrentUrl(); ?>?format=typescript">📄 TypeScript backend script</a>
</div>
</nav>
@ -460,6 +508,7 @@
<?php if (is_array($method['return'])) foreach ($method['return'] as $return) { ?>
<code class="parameter-type"><?php echo $return; ?></code>
<?php } ?>
<?php echo $renderTypeStructure($method['return_structure'] ?? null); ?>
</div>

69
src/javascript.tpl.php Normal file
View File

@ -0,0 +1,69 @@
/**
* Generated by APIlite
* https://gitea.tpsoft.org/TPsoft.org/APIlite
*
* <?php echo date('Y-m-d H:i:s'); ?>
*/
class <?php echo $this->apiName; ?> {
endpoint = <?php echo sprintf(substr($this->endpoint, 0, 4) == 'http' ? '"%s"' : '%s', $this->endpoint); ?>;
/* ----------------------------------------------------
* General API call
*/
call(method, data, callback) {
var xhttp = new XMLHttpRequest();
xhttp.withCredentials = true;
xhttp.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status === 200) {
if (callback != null) callback(JSON.parse(this.responseText));
} else {
if (callback != null) callback({'status': 'ERROR', 'msg': 'HTTP STATUS ' + this.status});
}
}
}
var form_data = new FormData();
Object.keys(data).forEach(key => {
let val = data[key];
if (typeof val === 'undefined') return;
if (typeof val == 'object') val = JSON.stringify(val);
form_data.append(key, val);
});
xhttp.open('POST', this.endpoint + '?action=' + method);
xhttp.send(form_data);
}
callPromise(method, data) {
return new Promise((resolve, reject) => {
this.call(method, data, function(response) {
if (method === '__HELP__') {
resolve(response);
return;
}
if (response.status === 'OK') {
resolve(response.data);
} else {
reject(response.msg);
}
});
})
}
/* ----------------------------------------------------
* API actions
*/
help() {
return this.callPromise('__HELP__', {});
}
<?php if (is_array($this->methods)) foreach ($this->methods as $method) {
echo "\t".$method['name'].'('.implode(', ', array_map(function($param) { return $param['name']; }, $method['params'])).') {';
echo "\n\t\treturn this.callPromise('".$method['name']."', {".implode(', ', array_map(function($param) { return $param['name'].': '.$param['name']; }, $method['params']))."});";
echo "\n\t}\n\n";
}
?>
};
export default new <?php echo $this->apiName; ?>();

View File

@ -1,3 +1,98 @@
<?php
$mapType = function (?string $type): string {
if (!is_string($type) || $type === '') {
return 'unknown';
}
$type = strtolower(ltrim($type, '\\'));
return match ($type) {
'int', 'integer', 'float', 'double' => 'number',
'string' => 'string',
'bool', 'boolean' => 'boolean',
'array', 'iterable' => 'unknown[]',
'object', 'stdclass' => 'Record<string, unknown>',
'mixed', 'resource' => 'unknown',
'null', 'void' => 'null',
'scalar' => 'string | number | boolean',
'callable', 'closure' => '(...args: unknown[]) => unknown',
'never' => 'never',
default => 'unknown',
};
};
$mapUnionType = function (mixed $type) use ($mapType): string {
if (is_array($type)) {
$parts = array();
foreach ($type as $singleType) {
$parts[] = $mapType(is_string($singleType) ? $singleType : null);
}
$parts = array_values(array_unique($parts));
return empty($parts) ? 'unknown' : implode(' | ', $parts);
}
return $mapType(is_string($type) ? $type : null);
};
$normalizeTypeStructures = function (mixed $structure): array {
if (!is_array($structure)) {
return array();
}
if (array_key_exists('type', $structure) && array_key_exists('properties', $structure)) {
return array($structure);
}
return array_values(array_filter($structure, 'is_array'));
};
$findTypeStructure = function (?string $type, mixed $structure) use ($normalizeTypeStructures): array|null {
if (!is_string($type) || $type === '') {
return null;
}
$type = ltrim($type, '\\');
foreach ($normalizeTypeStructures($structure) as $one_structure) {
if (($one_structure['type'] ?? null) === $type) {
return $one_structure;
}
}
return null;
};
$mapTypeWithStructure = null;
$mapUnionTypeWithStructure = null;
$mapTypeWithStructure = function (?string $type, mixed $structure) use ($mapType, &$mapUnionTypeWithStructure): string {
if (is_array($structure) && array_key_exists('type', $structure) && array_key_exists('properties', $structure)) {
$properties = array();
foreach (($structure['properties'] ?? array()) as $property) {
if (!is_array($property) || !isset($property['name'])) {
continue;
}
$propertyType = $mapUnionTypeWithStructure($property['type'] ?? null, $property['type_structure'] ?? null);
if (!empty($property['nullable']) && strpos($propertyType, 'null') === false) {
$propertyType .= ' | null';
}
$properties[] = $property['name'] . ': ' . $propertyType;
}
return empty($properties) ? 'Record<string, unknown>' : '{ ' . implode('; ', $properties) . ' }';
}
return $mapType($type);
};
$mapUnionTypeWithStructure = function (mixed $type, mixed $structure) use ($mapType, $findTypeStructure, &$mapTypeWithStructure): string {
if (is_array($type)) {
$parts = array();
foreach ($type as $singleType) {
$typeName = is_string($singleType) ? $singleType : null;
$parts[] = $mapTypeWithStructure($typeName, $findTypeStructure($typeName, $structure));
}
$parts = array_values(array_unique($parts));
return empty($parts) ? 'unknown' : implode(' | ', $parts);
}
return $mapTypeWithStructure(is_string($type) ? $type : null, $structure);
};
?>
/**
* Generated by APIlite
* https://gitea.tpsoft.org/TPsoft.org/APIlite
@ -5,64 +100,135 @@
* <?php echo date('Y-m-d H:i:s'); ?>
*/
class <?php echo $this->apiName; ?> {
endpoint = <?php echo sprintf(substr($this->endpoint, 0, 4) == 'http' ? '"%s"' : '%s', $this->endpoint); ?>;
export interface APIliteActionResponse<T> {
status: 'OK';
data: T;
msg: string;
}
/* ----------------------------------------------------
* General API call
*/
call(method, data, callback) {
var xhttp = new XMLHttpRequest();
export interface APIliteErrorResponse {
status: 'ERROR';
msg: string;
}
export interface APIliteMethodParam {
name: string;
type: string | null;
optional: boolean;
default: unknown;
doc: string | null;
}
export interface APIliteMethodDoc {
name: string;
doc: string | null;
description: string | null;
params: APIliteMethodParam[];
return: string | string[] | null;
return_structure: APIliteTypeStructure | APIliteTypeStructure[] | null;
}
export interface APIliteTypeStructureProperty {
name: string;
type: string | string[] | null;
nullable: boolean;
type_structure: APIliteTypeStructure | APIliteTypeStructure[] | null;
}
export interface APIliteTypeStructure {
type: string;
recursive?: boolean;
properties: APIliteTypeStructureProperty[];
}
export interface APIliteHelpResponse {
name: string;
html_version: string;
javascript_version: string;
typescript_version: string;
actions: APIliteMethodDoc[];
status: string;
data: string;
msg: string;
}
class <?php echo $this->apiName; ?> {
endpoint: string = <?php echo sprintf(substr($this->endpoint, 0, 4) == 'http' ? '"%s"' : '%s', $this->endpoint); ?>;
private call(
method: string,
data: Record<string, unknown>,
callback: (response: APIliteHelpResponse | APIliteActionResponse<unknown> | APIliteErrorResponse) => void
): void {
const xhttp = new XMLHttpRequest();
xhttp.withCredentials = true;
xhttp.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status == 200) {
if (callback != null) callback(JSON.parse(this.responseText));
if (this.readyState === 4) {
if (this.status === 200) {
const response = JSON.parse(this.responseText) as APIliteHelpResponse | APIliteActionResponse<unknown> | APIliteErrorResponse;
callback(response);
} else {
if (callback != null) callback({'status': 'ERROR', 'message': 'HTTP STATUS ' + this.status});
callback({ status: 'ERROR', msg: 'HTTP STATUS ' + this.status });
}
}
}
var form_data = new FormData();
Object.keys(data).forEach(key => {
let val = data[key];
if (typeof val == 'object') val = JSON.stringify(val);
form_data.append(key, val);
};
const formData = new FormData();
Object.keys(data).forEach((key) => {
const rawValue = data[key];
if (typeof rawValue === 'undefined') {
return;
}
let value: string | Blob;
if (rawValue instanceof Blob) {
value = rawValue;
} else if (typeof rawValue === 'object' && rawValue !== null) {
value = JSON.stringify(rawValue);
} else {
value = String(rawValue);
}
formData.append(key, value);
});
xhttp.open('POST', this.endpoint + '?action=' + method);
xhttp.send(form_data);
xhttp.send(formData);
}
callPromise(method, data) {
return new Promise((resolve, reject) => {
this.call(method, data, function(response) {
if (method == '__HELP__') {
resolve(response);
private callPromise<T>(method: string, data: Record<string, unknown>): Promise<T> {
return new Promise<T>((resolve, reject) => {
this.call(method, data, (response) => {
if (method === '__HELP__') {
resolve(response as T);
return;
}
if (response.status == 'OK') {
resolve(response.data);
} else {
reject(response.msg);
if (response.status === 'OK') {
resolve(response.data as T);
return;
}
reject(response.msg);
});
})
});
}
/* ----------------------------------------------------
* API actions
*/
help() {
return this.callPromise('__HELP__', {});
help(): Promise<APIliteHelpResponse> {
return this.callPromise<APIliteHelpResponse>('__HELP__', {});
}
<?php if (is_array($this->methods)) foreach ($this->methods as $method) {
echo "\t".$method['name'].'('.implode(', ', array_map(function($param) { return $param['name']; }, $method['params'])).') {';
echo "\n\t\treturn this.callPromise('".$method['name']."', {".implode(', ', array_map(function($param) { return $param['name'].': '.$param['name']; }, $method['params']))."});";
echo "\n\t}\n\n";
$paramsSignature = array();
$paramsPayload = array();
foreach ($method['params'] as $param) {
$paramType = $mapType($param['type']);
$paramsSignature[] = $param['name'] . ($param['optional'] ? '?' : '') . ': ' . $paramType;
$paramsPayload[] = $param['name'];
}
$returnType = $mapUnionTypeWithStructure($method['return'], $method['return_structure'] ?? null);
?>
<?php echo $method['name']; ?>(<?php echo implode(', ', $paramsSignature); ?>): Promise<APIliteActionResponse<<?php echo $returnType; ?>>> {
return this.callPromise<APIliteActionResponse<<?php echo $returnType; ?>>>('<?php echo $method['name']; ?>', { <?php echo implode(', ', $paramsPayload); ?> });
}
};
<?php } ?>
}
export default new <?php echo $this->apiName; ?>();