Skip to content

feat: node-appwrite use ts #799

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
1e01b38
feat: node-appwrite use ts
loks0n Mar 12, 2024
130303b
chore: remove node debug
loks0n Mar 12, 2024
81ad78d
fix: flag
loks0n Mar 12, 2024
9433c6b
chore: remove unneccessary deps
loks0n Mar 12, 2024
2cdcfea
fix: type
loks0n Mar 12, 2024
0406dca
fix: pjson
loks0n Mar 12, 2024
b771fad
chore: use node changelog
loks0n Mar 12, 2024
2aa9c66
fix: arrayBuffer
loks0n Mar 12, 2024
0a017aa
chore: compat InputFile
loks0n Mar 12, 2024
00eff15
chore: use File type for inputfile
loks0n Mar 12, 2024
d497934
chore: publint recommendations
loks0n Mar 13, 2024
57a10e1
chore: fix edge
loks0n Mar 13, 2024
1923225
fix: node 18
loks0n Mar 13, 2024
9126083
chore: fix local build
loks0n Mar 13, 2024
982fe0f
chore: revert pjson changes
loks0n Mar 19, 2024
0e79594
feat: support onProgress
loks0n Mar 22, 2024
962b89b
feat: base user agent
loks0n Mar 22, 2024
f5ad360
chore: remove realtime references
loks0n Mar 22, 2024
0b71332
fix: export models
loks0n Mar 27, 2024
1cb4395
fix: build warnings
loks0n Mar 28, 2024
29e7d93
chore: remove esm build
loks0n Apr 2, 2024
ac094f6
feat: restore InputFile entrypoint
loks0n Apr 2, 2024
7304672
Revert "feat: restore InputFile entrypoint"
loks0n Apr 2, 2024
45919f0
Revert "chore: remove esm build"
loks0n Apr 2, 2024
107507c
feat: improve user agent
loks0n Apr 9, 2024
79cdd26
feat: support self signed
loks0n Apr 11, 2024
47ea41b
fix: build
loks0n Apr 12, 2024
c1a5053
chore: bump node-fetch-native
loks0n Apr 12, 2024
0b1b8db
chore: improve ua
loks0n Apr 12, 2024
3c65f7e
fix: node 16
loks0n Apr 12, 2024
5e9c5d4
fix: remove credentials include
loks0n Apr 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 103 additions & 104 deletions src/SDK/Language/Node.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Appwrite\SDK\Language;

class Node extends JS
class Node extends Web
{
/**
* @return string
Expand All @@ -12,31 +12,84 @@ public function getName(): string
return 'NodeJS';
}

/**
* @param array $parameter
* @param array $spec
* @return string
*/
public function getTypeName(array $parameter, array $spec = []): string
public function getTypeName(array $parameter, array $method = []): string
{
if (isset($parameter['enumName'])) {
return \ucfirst($parameter['enumName']);
}
if (!empty($parameter['enumValues'])) {
return \ucfirst($parameter['name']);
}
return match ($parameter['type']) {
self::TYPE_INTEGER,
self::TYPE_NUMBER => 'number',
self::TYPE_STRING => 'string',
self::TYPE_FILE => 'InputFile',
self::TYPE_BOOLEAN => 'boolean',
self::TYPE_OBJECT => 'object',
self::TYPE_ARRAY => (!empty(($parameter['array'] ?? [])['type']) && !\is_array($parameter['array']['type']))
? $this->getTypeName($parameter['array']) . '[]'
: 'string[]',
default => $parameter['type'],
};
switch ($parameter['type']) {
case self::TYPE_INTEGER:
case self::TYPE_NUMBER:
return 'number';
case self::TYPE_ARRAY:
if (!empty(($parameter['array'] ?? [])['type']) && !\is_array($parameter['array']['type'])) {
return $this->getTypeName($parameter['array']) . '[]';
}
return 'string[]';
case self::TYPE_FILE:
return "File";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should still be InputFile right? Otherwise the storage service param will expect a File?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've switched this to File on purpose. The InputFile class now returns an instance of the File class.

File is a web Javascript standard API[1] and is available on most edge runtimes including vercel[2].
It's available in Node.js from version 18, and we use node-fetch-native to fallback on a polyfill where it doesn't exist.

[1] https://developer.mozilla.org/en-US/docs/Web/API/File
[2] https://nextjs.org/docs/pages/api-reference/edge
[3] https://nodejs.org/docs/latest/api/buffer.html#class-file

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this change the service method parameter types? We can use File internally, but should still expect an InputFile in the user-facing methods like storage.createFile

Copy link
Member Author

@loks0n loks0n Mar 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, because the user's InputFile helpers import will break on edge runtimes (due to its dependency on Node's fs module), so if we want storage.createFile to work on edge runtimes, we'll have to use the builtin File object.

If we use InputFile in the service method parameters then it is more obvious to the user that the helpers exist, but it will only work in Node-like environments

case self::TYPE_OBJECT:
if (empty($method)) {
return $parameter['type'];
}
switch ($method['responseModel']) {
case 'user':
return "Partial<Preferences>";
case 'document':
if ($method['method'] === 'post') {
return "Omit<Document, keyof Models.Document>";
}
if ($method['method'] === 'patch') {
return "Partial<Omit<Document, keyof Models.Document>>";
}
}
break;
}
return $parameter['type'];
}

public function getReturn(array $method, array $spec): string
{
if ($method['type'] === 'webAuth') {
return 'Promise<string>';
}

if ($method['type'] === 'location') {
return 'Promise<ArrayBuffer>';
}

if (array_key_exists('responseModel', $method) && !empty($method['responseModel']) && $method['responseModel'] !== 'any') {
$ret = 'Promise<';

if (
array_key_exists($method['responseModel'], $spec['definitions']) &&
array_key_exists('additionalProperties', $spec['definitions'][$method['responseModel']]) &&
!$spec['definitions'][$method['responseModel']]['additionalProperties']
) {
$ret .= 'Models.';
}

$ret .= $this->toPascalCase($method['responseModel']);

$models = [];

$this->populateGenerics($method['responseModel'], $spec, $models);

$models = array_unique($models);
$models = array_filter($models, fn ($model) => $model != $this->toPascalCase($method['responseModel']));

if (!empty($models)) {
$ret .= '<' . implode(', ', $models) . '>';
}

$ret .= '>';

return $ret;
}
return 'Promise<{}>';
}

/**
Expand All @@ -47,53 +100,48 @@ public function getFiles(): array
return [
[
'scope' => 'default',
'destination' => 'index.js',
'template' => 'node/index.js.twig',
'destination' => 'src/index.ts',
'template' => 'node/src/index.ts.twig',
],
[
'scope' => 'default',
'destination' => 'index.d.ts',
'template' => 'node/index.d.ts.twig',
'destination' => 'src/client.ts',
'template' => 'node/src/client.ts.twig',
],
[
'scope' => 'default',
'destination' => 'lib/client.js',
'template' => 'node/lib/client.js.twig',
'destination' => 'src/inputFile.ts',
'template' => 'node/src/inputFile.ts.twig',
],
[
'scope' => 'default',
'destination' => 'lib/permission.js',
'template' => 'node/lib/permission.js.twig',
'scope' => 'service',
'destination' => 'src/services/{{service.name | caseDash}}.ts',
'template' => 'node/src/services/template.ts.twig',
],
[
'scope' => 'default',
'destination' => 'lib/role.js',
'template' => 'node/lib/role.js.twig',
'destination' => 'src/models.ts',
'template' => 'web/src/models.ts.twig',
],
[
'scope' => 'default',
'destination' => 'lib/id.js',
'template' => 'node/lib/id.js.twig',
'destination' => 'src/permission.ts',
'template' => 'web/src/permission.ts.twig',
],
[
'scope' => 'default',
'destination' => 'lib/query.js',
'template' => 'node/lib/query.js.twig',
'destination' => 'src/role.ts',
'template' => 'web/src/role.ts.twig',
],
[
'scope' => 'default',
'destination' => 'lib/inputFile.js',
'template' => 'node/lib/inputFile.js.twig',
'destination' => 'src/id.ts',
'template' => 'web/src/id.ts.twig',
],
[
'scope' => 'default',
'destination' => '/lib/service.js',
'template' => 'node/lib/service.js.twig',
],
[
'scope' => 'service',
'destination' => '/lib/services/{{service.name | caseDash}}.js',
'template' => 'node/lib/services/service.js.twig',
'destination' => 'src/query.ts',
'template' => 'web/src/query.ts.twig',
],
[
'scope' => 'default',
Expand All @@ -115,80 +163,31 @@ public function getFiles(): array
'destination' => 'package.json',
'template' => 'node/package.json.twig',
],
[
'scope' => 'default',
'destination' => 'lib/exception.js',
'template' => 'node/lib/exception.js.twig',
],
[
'scope' => 'method',
'destination' => 'docs/examples/{{service.name | caseLower}}/{{method.name | caseDash}}.md',
'template' => 'node/docs/example.md.twig',
],
[
'scope' => 'default',
'destination' => 'tsconfig.json',
'template' => '/node/tsconfig.json.twig',
],
[
'scope' => 'default',
'destination' => 'tsup.config.js',
'template' => 'node/tsup.config.js.twig',
],
[
'scope' => 'default',
'destination' => '.travis.yml',
'template' => 'node/.travis.yml.twig',
],
[
'scope' => 'enum',
'destination' => 'lib/enums/{{ enum.name | caseDash }}.js',
'template' => 'node/lib/enums/enum.js.twig',
'destination' => 'src/enums/{{ enum.name | caseDash }}.ts',
'template' => 'web/src/enums/enum.ts.twig',
],
];
}

/**
* @param array $param
* @return string
*/
public function getParamExample(array $param): string
{
$type = $param['type'] ?? '';
$example = $param['example'] ?? '';

$output = '';

if (empty($example) && $example !== 0 && $example !== false) {
switch ($type) {
case self::TYPE_NUMBER:
case self::TYPE_INTEGER:
case self::TYPE_BOOLEAN:
$output .= 'null';
break;
case self::TYPE_STRING:
$output .= "''";
break;
case self::TYPE_ARRAY:
$output .= '[]';
break;
case self::TYPE_OBJECT:
$output .= '{}';
break;
case self::TYPE_FILE:
$output .= "InputFile.fromPath('/path/to/file.png', 'file.png')";
break;
}
} else {
switch ($type) {
case self::TYPE_NUMBER:
case self::TYPE_INTEGER:
case self::TYPE_ARRAY:
case self::TYPE_OBJECT:
$output .= $example;
break;
case self::TYPE_BOOLEAN:
$output .= ($example) ? 'true' : 'false';
break;
case self::TYPE_STRING:
$output .= "'{$example}'";
break;
case self::TYPE_FILE:
$output .= "InputFile.fromPath('/path/to/file.png', 'file.png')";
break;
}
}

return $output;
}
}
23 changes: 0 additions & 23 deletions templates/node/base/params.twig

This file was deleted.

8 changes: 0 additions & 8 deletions templates/node/base/requests/api.twig

This file was deleted.

Loading