Skip to content

Commit 5beae76

Browse files
Merge pull request #794 from appwrite/feat-react-native-sdk
React native SDK
2 parents 9ef19e5 + 9a5e00d commit 5beae76

22 files changed

+1400
-0
lines changed

example.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Appwrite\SDK\Language\Flutter;
2222
use Appwrite\SDK\Language\Android;
2323
use Appwrite\SDK\Language\Kotlin;
24+
use Appwrite\SDK\Language\ReactNative;
2425

2526
try {
2627

@@ -292,6 +293,33 @@ function getSSLPage($url) {
292293

293294
$sdk->generate(__DIR__ . '/examples/flutter');
294295

296+
// React Native
297+
$reactNative = new ReactNative();
298+
$reactNative->setNPMPackage('react-native-appwrite');
299+
$sdk = new SDK($reactNative, new Swagger2($spec));
300+
301+
$sdk
302+
->setName('NAME')
303+
->setDescription('Repo description goes here')
304+
->setShortDescription('Repo short description goes here')
305+
->setURL('https://example.com')
306+
->setLogo('https://appwrite.io/v1/images/console.png')
307+
->setLicenseContent('test test test')
308+
->setWarning('**WORK IN PROGRESS - NOT READY FOR USAGE**')
309+
->setChangelog('**CHANGELOG**')
310+
->setExamples('**EXAMPLES** <HTML>')
311+
->setVersion('0.0.1')
312+
->setGitUserName('repoowner')
313+
->setGitRepoName('reponame')
314+
->setTwitter('appwrite_io')
315+
->setDiscord('564160730845151244', 'https://appwrite.io/discord')
316+
->setDefaultHeaders([
317+
'X-Appwrite-Response-Format' => '1.5.0',
318+
])
319+
;
320+
321+
$sdk->generate(__DIR__ . '/examples/react-native');
322+
295323
// GO
296324

297325
$sdk = new SDK(new Go(), new Swagger2($spec));

src/SDK/Language/ReactNative.php

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
<?php
2+
3+
namespace Appwrite\SDK\Language;
4+
5+
use Twig\TwigFilter;
6+
7+
class ReactNative extends Web
8+
{
9+
/**
10+
* @return string
11+
*/
12+
public function getName(): string
13+
{
14+
return 'ReactNative';
15+
}
16+
17+
/**
18+
* @return array
19+
*/
20+
public function getFiles(): array
21+
{
22+
return [
23+
[
24+
'scope' => 'default',
25+
'destination' => 'src/index.ts',
26+
'template' => 'react-native/src/index.ts.twig',
27+
],
28+
[
29+
'scope' => 'default',
30+
'destination' => 'src/client.ts',
31+
'template' => 'react-native/src/client.ts.twig',
32+
],
33+
[
34+
'scope' => 'default',
35+
'destination' => 'src/service.ts',
36+
'template' => 'react-native/src/service.ts.twig',
37+
],
38+
[
39+
'scope' => 'service',
40+
'destination' => 'src/services/{{service.name | caseDash}}.ts',
41+
'template' => 'react-native/src/services/template.ts.twig',
42+
],
43+
[
44+
'scope' => 'default',
45+
'destination' => 'src/models.ts',
46+
'template' => 'react-native/src/models.ts.twig',
47+
],
48+
[
49+
'scope' => 'default',
50+
'destination' => 'src/permission.ts',
51+
'template' => 'react-native/src/permission.ts.twig',
52+
],
53+
[
54+
'scope' => 'default',
55+
'destination' => 'src/role.ts',
56+
'template' => 'react-native/src/role.ts.twig',
57+
],
58+
[
59+
'scope' => 'default',
60+
'destination' => 'src/id.ts',
61+
'template' => 'react-native/src/id.ts.twig',
62+
],
63+
[
64+
'scope' => 'default',
65+
'destination' => 'src/query.ts',
66+
'template' => 'react-native/src/query.ts.twig',
67+
],
68+
[
69+
'scope' => 'default',
70+
'destination' => 'README.md',
71+
'template' => 'react-native/README.md.twig',
72+
],
73+
[
74+
'scope' => 'default',
75+
'destination' => 'CHANGELOG.md',
76+
'template' => 'react-native/CHANGELOG.md.twig',
77+
],
78+
[
79+
'scope' => 'default',
80+
'destination' => 'LICENSE',
81+
'template' => 'react-native/LICENSE.twig',
82+
],
83+
[
84+
'scope' => 'default',
85+
'destination' => 'package.json',
86+
'template' => 'react-native/package.json.twig',
87+
],
88+
[
89+
'scope' => 'method',
90+
'destination' => 'docs/examples/{{service.name | caseLower}}/{{method.name | caseDash}}.md',
91+
'template' => 'react-native/docs/example.md.twig',
92+
],
93+
[
94+
'scope' => 'default',
95+
'destination' => 'tsconfig.json',
96+
'template' => '/react-native/tsconfig.json.twig',
97+
],
98+
[
99+
'scope' => 'default',
100+
'destination' => 'rollup.config.js',
101+
'template' => '/react-native/rollup.config.js.twig',
102+
],
103+
[
104+
'scope' => 'default',
105+
'destination' => 'dist/cjs/package.json',
106+
'template' => '/react-native/dist/cjs/package.json.twig',
107+
],
108+
[
109+
'scope' => 'default',
110+
'destination' => 'dist/esm/package.json',
111+
'template' => '/react-native/dist/esm/package.json.twig',
112+
],
113+
[
114+
'scope' => 'default',
115+
'destination' => '.github/workflows/publish.yml',
116+
'template' => 'react-native/.github/workflows/publish.yml.twig',
117+
],
118+
[
119+
'scope' => 'enum',
120+
'destination' => 'src/enums/{{ enum.name | caseDash }}.ts',
121+
'template' => 'react-native/src/enums/enum.ts.twig',
122+
],
123+
];
124+
}
125+
126+
/**
127+
* @param array $parameter
128+
* @param array $nestedTypes
129+
* @return string
130+
*/
131+
public function getTypeName(array $parameter, array $spec = []): string
132+
{
133+
if (isset($parameter['enumName'])) {
134+
return \ucfirst($parameter['enumName']);
135+
}
136+
if (!empty($parameter['enumValues'])) {
137+
return \ucfirst($parameter['name']);
138+
}
139+
switch ($parameter['type']) {
140+
case self::TYPE_INTEGER:
141+
case self::TYPE_NUMBER:
142+
return 'number';
143+
case self::TYPE_ARRAY:
144+
if (!empty(($parameter['array'] ?? [])['type']) && !\is_array($parameter['array']['type'])) {
145+
return $this->getTypeName($parameter['array']) . '[]';
146+
}
147+
return 'string[]';
148+
case self::TYPE_FILE:
149+
return 'any';
150+
}
151+
152+
return $parameter['type'];
153+
}
154+
155+
/**
156+
* @param array $param
157+
* @return string
158+
*/
159+
public function getParamExample(array $param): string
160+
{
161+
$type = $param['type'] ?? '';
162+
$example = $param['example'] ?? '';
163+
164+
$output = '';
165+
166+
if (empty($example) && $example !== 0 && $example !== false) {
167+
switch ($type) {
168+
case self::TYPE_NUMBER:
169+
case self::TYPE_INTEGER:
170+
case self::TYPE_BOOLEAN:
171+
$output .= 'null';
172+
break;
173+
case self::TYPE_STRING:
174+
$output .= "''";
175+
break;
176+
case self::TYPE_ARRAY:
177+
$output .= '[]';
178+
break;
179+
case self::TYPE_OBJECT:
180+
$output .= '{}';
181+
break;
182+
case self::TYPE_FILE:
183+
$output .= "await pickSingle()";
184+
break;
185+
}
186+
} else {
187+
switch ($type) {
188+
case self::TYPE_NUMBER:
189+
case self::TYPE_INTEGER:
190+
case self::TYPE_ARRAY:
191+
case self::TYPE_OBJECT:
192+
$output .= $example;
193+
break;
194+
case self::TYPE_BOOLEAN:
195+
$output .= ($example) ? 'true' : 'false';
196+
break;
197+
case self::TYPE_STRING:
198+
$output .= "'{$example}'";
199+
break;
200+
case self::TYPE_FILE:
201+
$output .= "await pickSingle()";
202+
break;
203+
}
204+
}
205+
206+
return $output;
207+
}
208+
209+
public function getReturn(array $method, array $spec): string
210+
{
211+
if ($method['type'] === 'webAuth') {
212+
return 'void | URL';
213+
} elseif ($method['type'] === 'location') {
214+
return 'URL';
215+
}
216+
217+
if (array_key_exists('responseModel', $method) && !empty($method['responseModel']) && $method['responseModel'] !== 'any') {
218+
$ret = 'Promise<';
219+
220+
if (
221+
array_key_exists($method['responseModel'], $spec['definitions']) &&
222+
array_key_exists('additionalProperties', $spec['definitions'][$method['responseModel']]) &&
223+
!$spec['definitions'][$method['responseModel']]['additionalProperties']
224+
) {
225+
$ret .= 'Models.';
226+
}
227+
228+
$ret .= $this->toPascalCase($method['responseModel']);
229+
230+
$models = [];
231+
232+
$this->populateGenerics($method['responseModel'], $spec, $models);
233+
234+
$models = array_unique($models);
235+
$models = array_filter($models, fn ($model) => $model != $this->toPascalCase($method['responseModel']));
236+
237+
if (!empty($models)) {
238+
$ret .= '<' . implode(', ', $models) . '>';
239+
}
240+
241+
$ret .= '>';
242+
243+
return $ret;
244+
}
245+
return 'Promise<{}>';
246+
}
247+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Publish to NPM
2+
3+
on:
4+
release:
5+
types: [published]
6+
workflow_dispatch:
7+
8+
jobs:
9+
publish:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
# Setup Node.js environment
16+
- name: Use Node.js
17+
uses: actions/setup-node@v4
18+
with:
19+
node-version: '20.x'
20+
registry-url: 'https://registry.npmjs.org'
21+
22+
# Determine release tag based on the tag name
23+
- name: Determine release tag
24+
id: release_tag
25+
run: |
26+
if [[ "${{ '{{' }} github.ref {{ '}}' }}" == *"-rc"* ]]; then
27+
echo "tag=next" >> "$GITHUB_OUTPUT"
28+
else
29+
echo "tag=latest" >> "$GITHUB_OUTPUT"
30+
fi
31+
32+
# Install dependencies (if any) and build your project (if necessary)
33+
- name: Install dependencies and build
34+
run: |
35+
npm install
36+
npm run build
37+
38+
# Publish to NPM with the appropriate tag
39+
- name: Publish
40+
run: npm publish --tag ${{ '{{' }} steps.release_tag.outputs.tag {{ '}}' }}
41+
env:
42+
NODE_AUTH_TOKEN: ${{ '{{' }} secrets.NPM_TOKEN {{ '}}' }}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{sdk.changelog}}

templates/react-native/LICENSE.twig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{sdk.licenseContent | raw}}

templates/react-native/README.md.twig

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# {{ spec.title }} {{sdk.name}} SDK
2+
3+
![License](https://img.shields.io/github/license/{{ sdk.gitUserName|url_encode }}/{{ sdk.gitRepoName|url_encode }}.svg?style=flat-square)
4+
![Version](https://img.shields.io/badge/api%20version-{{ spec.version|url_encode }}-blue.svg?style=flat-square)
5+
[![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator)
6+
{% if sdk.twitterHandle %}
7+
[![Twitter Account](https://img.shields.io/twitter/follow/{{ sdk.twitterHandle }}?color=00acee&label=twitter&style=flat-square)](https://twitter.com/{{ sdk.twitterHandle }})
8+
{% endif %}
9+
{% if sdk.discordChannel %}
10+
[![Discord](https://img.shields.io/discord/{{ sdk.discordChannel }}?label=discord&style=flat-square)]({{ sdk.discordUrl }})
11+
{% endif %}
12+
{% if sdk.warning %}
13+
14+
{{ sdk.warning|raw }}
15+
{% endif %}
16+
17+
{{ sdk.description }}
18+
19+
{% if sdk.logo %}
20+
![{{ spec.title }}]({{ sdk.logo }})
21+
{% endif %}
22+
23+
## Installation
24+
25+
To install
26+
27+
```bash
28+
npx expo install react-native-appwrite react-native-url-polyfill
29+
```
30+
31+
{% if sdk.gettingStarted %}
32+
33+
{{ sdk.gettingStarted|raw }}
34+
{% endif %}
35+
36+
## Contribution
37+
38+
This library is auto-generated by Appwrite custom [SDK Generator](https://github.com/appwrite/sdk-generator). To learn more about how you can help us improve this SDK, please check the [contribution guide](https://github.com/appwrite/sdk-generator/blob/master/CONTRIBUTING.md) before sending a pull-request.
39+
40+
## License
41+
42+
Please see the [{{spec.licenseName}} license]({{spec.licenseURL}}) file for more information.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "commonjs"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}

0 commit comments

Comments
 (0)