appwrite-cli 7.0.0 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,7 +29,7 @@ Once the installation is complete, you can verify the install using
29
29
 
30
30
  ```sh
31
31
  $ appwrite -v
32
- 7.0.0
32
+ 8.0.0
33
33
  ```
34
34
 
35
35
  ### Install using prebuilt binaries
@@ -60,7 +60,7 @@ $ scoop install https://raw.githubusercontent.com/appwrite/sdk-for-cli/master/sc
60
60
  Once the installation completes, you can verify your install using
61
61
  ```
62
62
  $ appwrite -v
63
- 7.0.0
63
+ 8.0.0
64
64
  ```
65
65
 
66
66
  ## Getting Started
package/index.js CHANGED
@@ -13,12 +13,12 @@ const { client } = require("./lib/commands/generic");
13
13
  const inquirer = require("inquirer");
14
14
  const { login, logout, whoami, migrate, register } = require("./lib/commands/generic");
15
15
  const { init } = require("./lib/commands/init");
16
+ const { types } = require("./lib/commands/types");
16
17
  const { pull } = require("./lib/commands/pull");
17
18
  const { run } = require("./lib/commands/run");
18
19
  const { push, deploy } = require("./lib/commands/push");
19
20
  const { account } = require("./lib/commands/account");
20
21
  const { avatars } = require("./lib/commands/avatars");
21
- const { assistant } = require("./lib/commands/assistant");
22
22
  const { console } = require("./lib/commands/console");
23
23
  const { databases } = require("./lib/commands/databases");
24
24
  const { functions } = require("./lib/commands/functions");
@@ -80,12 +80,12 @@ program
80
80
  .addCommand(init)
81
81
  .addCommand(pull)
82
82
  .addCommand(push)
83
+ .addCommand(types)
83
84
  .addCommand(deploy)
84
85
  .addCommand(run)
85
86
  .addCommand(logout)
86
87
  .addCommand(account)
87
88
  .addCommand(avatars)
88
- .addCommand(assistant)
89
89
  .addCommand(console)
90
90
  .addCommand(databases)
91
91
  .addCommand(functions)
package/install.ps1 CHANGED
@@ -13,8 +13,8 @@
13
13
  # You can use "View source" of this page to see the full script.
14
14
 
15
15
  # REPO
16
- $GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/7.0.0/appwrite-cli-win-x64.exe"
17
- $GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/7.0.0/appwrite-cli-win-arm64.exe"
16
+ $GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/8.0.0/appwrite-cli-win-x64.exe"
17
+ $GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/8.0.0/appwrite-cli-win-arm64.exe"
18
18
 
19
19
  $APPWRITE_BINARY_NAME = "appwrite.exe"
20
20
 
package/install.sh CHANGED
@@ -97,7 +97,7 @@ printSuccess() {
97
97
  downloadBinary() {
98
98
  echo "[2/4] Downloading executable for $OS ($ARCH) ..."
99
99
 
100
- GITHUB_LATEST_VERSION="7.0.0"
100
+ GITHUB_LATEST_VERSION="8.0.0"
101
101
  GITHUB_FILE="appwrite-cli-${OS}-${ARCH}"
102
102
  GITHUB_URL="https://github.com/$GITHUB_REPOSITORY_NAME/releases/download/$GITHUB_LATEST_VERSION/$GITHUB_FILE"
103
103
 
package/lib/client.js CHANGED
@@ -16,8 +16,8 @@ class Client {
16
16
  'x-sdk-name': 'Command Line',
17
17
  'x-sdk-platform': 'console',
18
18
  'x-sdk-language': 'cli',
19
- 'x-sdk-version': '7.0.0',
20
- 'user-agent' : `AppwriteCLI/7.0.0 (${os.type()} ${os.version()}; ${os.arch()})`,
19
+ 'x-sdk-version': '8.0.0',
20
+ 'user-agent' : `AppwriteCLI/8.0.0 (${os.type()} ${os.version()}; ${os.arch()})`,
21
21
  'X-Appwrite-Response-Format' : '1.7.0',
22
22
  };
23
23
  }
@@ -2660,7 +2660,7 @@ databases
2660
2660
 
2661
2661
  databases
2662
2662
  .command(`create-documents`)
2663
- .description(`Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.`)
2663
+ .description(`**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions. Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.`)
2664
2664
  .requiredOption(`--database-id <database-id>`, `Database ID.`)
2665
2665
  .requiredOption(`--collection-id <collection-id>`, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.`)
2666
2666
  .requiredOption(`--documents [documents...]`, `Array of documents data as JSON objects.`)
@@ -2668,7 +2668,7 @@ databases
2668
2668
 
2669
2669
  databases
2670
2670
  .command(`upsert-documents`)
2671
- .description(`Create or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console. `)
2671
+ .description(`**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions. Create or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console. `)
2672
2672
  .requiredOption(`--database-id <database-id>`, `Database ID.`)
2673
2673
  .requiredOption(`--collection-id <collection-id>`, `Collection ID.`)
2674
2674
  .requiredOption(`--documents [documents...]`, `Array of document data as JSON objects. May contain partial documents.`)
@@ -2685,7 +2685,7 @@ databases
2685
2685
 
2686
2686
  databases
2687
2687
  .command(`delete-documents`)
2688
- .description(`Bulk delete documents using queries, if no queries are passed then all documents are deleted.`)
2688
+ .description(`**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions. Bulk delete documents using queries, if no queries are passed then all documents are deleted.`)
2689
2689
  .requiredOption(`--database-id <database-id>`, `Database ID.`)
2690
2690
  .requiredOption(`--collection-id <collection-id>`, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`)
2691
2691
  .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`)
@@ -2703,7 +2703,7 @@ databases
2703
2703
 
2704
2704
  databases
2705
2705
  .command(`upsert-document`)
2706
- .description(`Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.`)
2706
+ .description(`**WARNING: Experimental Feature** - This endpoint is experimental and not yet officially supported. It may be subject to breaking changes or removal in future versions. Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.`)
2707
2707
  .requiredOption(`--database-id <database-id>`, `Database ID.`)
2708
2708
  .requiredOption(`--collection-id <collection-id>`, `Collection ID.`)
2709
2709
  .requiredOption(`--document-id <document-id>`, `Document ID.`)
@@ -0,0 +1,126 @@
1
+ const ejs = require("ejs");
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+ const { LanguageMeta, detectLanguage } = require("../type-generation/languages/language");
5
+ const { Command, Option, Argument } = require("commander");
6
+ const { localConfig } = require("../config");
7
+ const { success, log, actionRunner } = require("../parser");
8
+ const { PHP } = require("../type-generation/languages/php");
9
+ const { TypeScript } = require("../type-generation/languages/typescript");
10
+ const { Kotlin } = require("../type-generation/languages/kotlin");
11
+ const { Swift } = require("../type-generation/languages/swift");
12
+ const { Java } = require("../type-generation/languages/java");
13
+ const { Dart } = require("../type-generation/languages/dart");
14
+ const { JavaScript } = require("../type-generation/languages/javascript");
15
+
16
+ /**
17
+ * @param {string} language
18
+ * @returns {import("../type-generation/languages/language").LanguageMeta}
19
+ */
20
+ function createLanguageMeta(language) {
21
+ switch (language) {
22
+ case "ts":
23
+ return new TypeScript();
24
+ case "js":
25
+ return new JavaScript();
26
+ case "php":
27
+ return new PHP();
28
+ case "kotlin":
29
+ return new Kotlin();
30
+ case "swift":
31
+ return new Swift();
32
+ case "java":
33
+ return new Java();
34
+ case "dart":
35
+ return new Dart();
36
+ default:
37
+ throw new Error(`Language '${language}' is not supported`);
38
+ }
39
+ }
40
+
41
+ const templateHelpers = {
42
+ toPascalCase: LanguageMeta.toPascalCase,
43
+ toCamelCase: LanguageMeta.toCamelCase,
44
+ toSnakeCase: LanguageMeta.toSnakeCase,
45
+ toKebabCase: LanguageMeta.toKebabCase,
46
+ toUpperSnakeCase: LanguageMeta.toUpperSnakeCase
47
+ }
48
+
49
+ const typesOutputArgument = new Argument(
50
+ "<output-directory>",
51
+ "The directory to write the types to"
52
+ );
53
+
54
+ const typesLanguageOption = new Option(
55
+ "-l, --language <language>",
56
+ "The language of the types"
57
+ )
58
+ .choices(["auto", "ts", "js", "php", "kotlin", "swift", "java", "dart"])
59
+ .default("auto");
60
+
61
+ const typesCommand = actionRunner(async (rawOutputDirectory, {language}) => {
62
+ if (language === "auto") {
63
+ language = detectLanguage();
64
+ log(`Detected language: ${language}`);
65
+ }
66
+
67
+ const meta = createLanguageMeta(language);
68
+
69
+ const outputDirectory = path.resolve(rawOutputDirectory);
70
+ if (!fs.existsSync(outputDirectory)) {
71
+ log(`Directory: ${outputDirectory} does not exist, creating...`);
72
+ fs.mkdirSync(outputDirectory, { recursive: true });
73
+ }
74
+
75
+ if (!fs.existsSync("appwrite.json")) {
76
+ throw new Error("appwrite.json not found in current directory");
77
+ }
78
+
79
+ const collections = localConfig.getCollections();
80
+ if (collections.length === 0) {
81
+ throw new Error("No collections found in appwrite.json");
82
+ }
83
+
84
+ log(`Found ${collections.length} collections: ${collections.map(c => c.name).join(", ")}`);
85
+
86
+ const totalAttributes = collections.reduce((count, collection) => count + collection.attributes.length, 0);
87
+ log(`Found ${totalAttributes} attributes across all collections`);
88
+
89
+ const templater = ejs.compile(meta.getTemplate());
90
+
91
+ if (meta.isSingleFile()) {
92
+ const content = templater({
93
+ collections,
94
+ ...templateHelpers,
95
+ getType: meta.getType
96
+ });
97
+
98
+ const destination = path.join(outputDirectory, meta.getFileName());
99
+
100
+ fs.writeFileSync(destination, content);
101
+ log(`Added types to ${destination}`);
102
+ } else {
103
+ for (const collection of collections) {
104
+ const content = templater({
105
+ collection,
106
+ ...templateHelpers,
107
+ getType: meta.getType
108
+ });
109
+
110
+ const destination = path.join(outputDirectory, meta.getFileName(collection));
111
+
112
+ fs.writeFileSync(destination, content);
113
+ log(`Added types for ${collection.name} to ${destination}`);
114
+ }
115
+ }
116
+
117
+ success(`Generated types for all the listed collections`);
118
+ });
119
+
120
+ const types = new Command("types")
121
+ .description("Generate types for your Appwrite project")
122
+ .addArgument(typesOutputArgument)
123
+ .addOption(typesLanguageOption)
124
+ .action(actionRunner(typesCommand));
125
+
126
+ module.exports = { types };
package/lib/parser.js CHANGED
@@ -120,7 +120,7 @@ const parseError = (err) => {
120
120
  } catch {
121
121
  }
122
122
 
123
- const version = '7.0.0';
123
+ const version = '8.0.0';
124
124
  const stepsToReproduce = `Running \`appwrite ${cliConfig.reportData.data.args.join(' ')}\``;
125
125
  const yourEnvironment = `CLI version: ${version}\nOperation System: ${os.type()}\nAppwrite version: ${appwriteVersion}\nIs Cloud: ${isCloud}`;
126
126
 
@@ -221,7 +221,6 @@ const commandDescriptions = {
221
221
  "whoami": `The whomai command gives information about the currently logged-in user.`,
222
222
  "register": `Outputs the link to create an Appwrite account.`,
223
223
  "console" : `The console command gives you access to the APIs used by the Appwrite Console.`,
224
- "assistant": `The assistant command allows you to interact with the Appwrite Assistant AI`,
225
224
  "messaging": `The messaging command allows you to manage topics and targets and send messages.`,
226
225
  "migrations": `The migrations command allows you to migrate data between services.`,
227
226
  "vcs": `The vcs command allows you to interact with VCS providers and manage your code repositories.`,
@@ -0,0 +1,16 @@
1
+ const AttributeType = {
2
+ STRING: "string",
3
+ INTEGER: "integer",
4
+ FLOAT: "float",
5
+ BOOLEAN: "boolean",
6
+ DATETIME: "datetime",
7
+ EMAIL: "email",
8
+ IP: "ip",
9
+ URL: "url",
10
+ ENUM: "enum",
11
+ RELATIONSHIP: "relationship",
12
+ };
13
+
14
+ module.exports = {
15
+ AttributeType,
16
+ };
@@ -0,0 +1,152 @@
1
+ /** @typedef {import('../attribute').Attribute} Attribute */
2
+ const { AttributeType } = require('../attribute');
3
+ const { LanguageMeta } = require("./language");
4
+
5
+ class Dart extends LanguageMeta {
6
+ getType(attribute) {
7
+ let type = "";
8
+ switch (attribute.type) {
9
+ case AttributeType.STRING:
10
+ case AttributeType.EMAIL:
11
+ case AttributeType.DATETIME:
12
+ type = "String";
13
+ if (attribute.format === AttributeType.ENUM) {
14
+ type = LanguageMeta.toPascalCase(attribute.key);
15
+ }
16
+ break;
17
+ case AttributeType.INTEGER:
18
+ type = "int";
19
+ break;
20
+ case AttributeType.FLOAT:
21
+ type = "double";
22
+ break;
23
+ case AttributeType.BOOLEAN:
24
+ type = "bool";
25
+ break;
26
+ case AttributeType.RELATIONSHIP:
27
+ type = LanguageMeta.toPascalCase(attribute.relatedCollection);
28
+ if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') {
29
+ type = `List<${type}>`;
30
+ }
31
+ break;
32
+ default:
33
+ throw new Error(`Unknown attribute type: ${attribute.type}`);
34
+ }
35
+ if (attribute.array) {
36
+ type = `List<${type}>`;
37
+ }
38
+ if (!attribute.required) {
39
+ type += "?";
40
+ }
41
+ return type;
42
+ }
43
+
44
+ getTemplate() {
45
+ return `<% for (const attribute of collection.attributes) { -%>
46
+ <% if (attribute.type === 'relationship') { -%>
47
+ import '<%- attribute.relatedCollection.toLowerCase() %>.dart';
48
+
49
+ <% } -%>
50
+ <% } -%>
51
+ <% for (const attribute of collection.attributes) { -%>
52
+ <% if (attribute.format === 'enum') { -%>
53
+ enum <%- toPascalCase(attribute.key) %> {
54
+ <% for (const element of attribute.elements) { -%>
55
+ <%- element %>,
56
+ <% } -%>
57
+ }
58
+
59
+ <% } -%>
60
+ <% } -%>
61
+ class <%= toPascalCase(collection.name) %> {
62
+ <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
63
+ <%- getType(attribute) %> <%= toCamelCase(attribute.key) %>;
64
+ <% } -%>
65
+
66
+ <%= toPascalCase(collection.name) %>({
67
+ <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
68
+ <% if (attribute.required) { %>required <% } %>this.<%= toCamelCase(attribute.key) %>,
69
+ <% } -%>
70
+ });
71
+
72
+ factory <%= toPascalCase(collection.name) %>.fromMap(Map<String, dynamic> map) {
73
+ return <%= toPascalCase(collection.name) %>(
74
+ <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
75
+ <%= toCamelCase(attribute.key) %>: <% if (attribute.type === 'string' || attribute.type === 'email' || attribute.type === 'datetime') { -%>
76
+ <% if (attribute.format === 'enum') { -%>
77
+ <% if (attribute.array) { -%>
78
+ (map['<%= attribute.key %>'] as List<dynamic>?)?.map((e) => <%- toPascalCase(attribute.key) %>.values.firstWhere((element) => element.name == e)).toList()<% if (!attribute.required) { %> ?? []<% } -%>
79
+ <% } else { -%>
80
+ <% if (!attribute.required) { -%>
81
+ map['<%= attribute.key %>'] != null ? <%- toPascalCase(attribute.key) %>.values.where((e) => e.name == map['<%= attribute.key %>']).firstOrNull : null<% } else { -%>
82
+ <%- toPascalCase(attribute.key) %>.values.firstWhere((e) => e.name == map['<%= attribute.key %>'])<% } -%>
83
+ <% } -%>
84
+ <% } else { -%>
85
+ <% if (attribute.array) { -%>
86
+ List<String>.from(map['<%= attribute.key %>'] ?? [])<% if (!attribute.required) { %> ?? []<% } -%>
87
+ <% } else { -%>
88
+ map['<%= attribute.key %>']<% if (!attribute.required) { %>?<% } %>.toString()<% if (!attribute.required) { %> ?? null<% } -%>
89
+ <% } -%>
90
+ <% } -%>
91
+ <% } else if (attribute.type === 'integer') { -%>
92
+ <% if (attribute.array) { -%>
93
+ List<int>.from(map['<%= attribute.key %>'] ?? [])<% if (!attribute.required) { %> ?? []<% } -%>
94
+ <% } else { -%>
95
+ map['<%= attribute.key %>']<% if (!attribute.required) { %> ?? null<% } -%>
96
+ <% } -%>
97
+ <% } else if (attribute.type === 'float') { -%>
98
+ <% if (attribute.array) { -%>
99
+ List<double>.from(map['<%= attribute.key %>'] ?? [])<% if (!attribute.required) { %> ?? []<% } -%>
100
+ <% } else { -%>
101
+ map['<%= attribute.key %>']<% if (!attribute.required) { %> ?? null<% } -%>
102
+ <% } -%>
103
+ <% } else if (attribute.type === 'boolean') { -%>
104
+ <% if (attribute.array) { -%>
105
+ List<bool>.from(map['<%= attribute.key %>'] ?? [])<% if (!attribute.required) { %> ?? []<% } -%>
106
+ <% } else { -%>
107
+ map['<%= attribute.key %>']<% if (!attribute.required) { %> ?? null<% } -%>
108
+ <% } -%>
109
+ <% } else if (attribute.type === 'relationship') { -%>
110
+ <% if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') { -%>
111
+ (map['<%= attribute.key %>'] as List<dynamic>?)?.map((e) => <%- toPascalCase(attribute.relatedCollection) %>.fromMap(e)).toList()<% if (!attribute.required) { %> ?? []<% } -%>
112
+ <% } else { -%>
113
+ <% if (!attribute.required) { -%>
114
+ map['<%= attribute.key %>'] != null ? <%- toPascalCase(attribute.relatedCollection) %>.fromMap(map['<%= attribute.key %>']) : null<% } else { -%>
115
+ <%- toPascalCase(attribute.relatedCollection) %>.fromMap(map['<%= attribute.key %>'])<% } -%>
116
+ <% } -%>
117
+ <% } -%>,
118
+ <% } -%>
119
+ );
120
+ }
121
+
122
+ Map<String, dynamic> toMap() {
123
+ return {
124
+ <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
125
+ "<%= attribute.key %>": <% if (attribute.type === 'relationship') { -%>
126
+ <% if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') { -%>
127
+ <%= toCamelCase(attribute.key) %><% if (!attribute.required) { %>?<% } %>.map((e) => e.toMap()).toList()<% if (!attribute.required) { %> ?? []<% } -%>
128
+ <% } else { -%>
129
+ <%= toCamelCase(attribute.key) %><% if (!attribute.required) { %>?<% } %>.toMap()<% if (!attribute.required) { %> ?? {}<% } -%>
130
+ <% } -%>
131
+ <% } else if (attribute.format === 'enum') { -%>
132
+ <% if (attribute.array) { -%>
133
+ <%= toCamelCase(attribute.key) %><% if (!attribute.required) { %>?<% } %>.map((e) => e.name).toList()<% if (!attribute.required) { %> ?? []<% } -%>
134
+ <% } else { -%>
135
+ <%= toCamelCase(attribute.key) %><% if (!attribute.required) { %>?<% } %>.name<% if (!attribute.required) { %> ?? null<% } -%>
136
+ <% } -%>
137
+ <% } else { -%>
138
+ <%= toCamelCase(attribute.key) -%>
139
+ <% } -%>,
140
+ <% } -%>
141
+ };
142
+ }
143
+ }
144
+ `;
145
+ }
146
+
147
+ getFileName(collection) {
148
+ return LanguageMeta.toSnakeCase(collection.name) + ".dart";
149
+ }
150
+ }
151
+
152
+ module.exports = { Dart };
@@ -0,0 +1,121 @@
1
+ /** @typedef {import('../attribute').Attribute} Attribute */
2
+ const { AttributeType } = require('../attribute');
3
+ const { LanguageMeta } = require("./language");
4
+
5
+ class Java extends LanguageMeta {
6
+ getType(attribute) {
7
+ let type = "";
8
+ switch (attribute.type) {
9
+ case AttributeType.STRING:
10
+ case AttributeType.EMAIL:
11
+ case AttributeType.DATETIME:
12
+ type = "String";
13
+ if (attribute.format === AttributeType.ENUM) {
14
+ type = LanguageMeta.toPascalCase(attribute.key);
15
+ }
16
+ break;
17
+ case AttributeType.INTEGER:
18
+ type = "int";
19
+ break;
20
+ case AttributeType.FLOAT:
21
+ type = "double";
22
+ break;
23
+ case AttributeType.BOOLEAN:
24
+ type = "boolean";
25
+ break;
26
+ case AttributeType.RELATIONSHIP:
27
+ type = LanguageMeta.toPascalCase(attribute.relatedCollection);
28
+ if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') {
29
+ type = "List<" + type + ">";
30
+ }
31
+ break;
32
+ default:
33
+ throw new Error(`Unknown attribute type: ${attribute.type}`);
34
+ }
35
+ if (attribute.array) {
36
+ type = "List<" + type + ">";
37
+ }
38
+ return type;
39
+ }
40
+
41
+ getTemplate() {
42
+ return `package io.appwrite.models;
43
+
44
+ import java.util.*;
45
+ <% for (const attribute of collection.attributes) { -%>
46
+ <% if (attribute.type === 'relationship') { -%>
47
+ import <%- toPascalCase(attribute.relatedCollection) %>;
48
+
49
+ <% } -%>
50
+ <% } -%>
51
+ public class <%- toPascalCase(collection.name) %> {
52
+ <% for (const attribute of collection.attributes) { -%>
53
+ <% if (attribute.format === 'enum') { -%>
54
+
55
+ public enum <%- toPascalCase(attribute.key) %> {
56
+ <% for (const [index, element] of Object.entries(attribute.elements)) { -%>
57
+ <%- element %><%- index < attribute.elements.length - 1 ? ',' : ';' %>
58
+ <% } -%>
59
+ }
60
+
61
+ <% } -%>
62
+ <% } -%>
63
+ <% for (const attribute of collection.attributes) { -%>
64
+ private <%- getType(attribute) %> <%- toCamelCase(attribute.key) %>;
65
+ <% } -%>
66
+
67
+ public <%- toPascalCase(collection.name) %>() {
68
+ }
69
+
70
+ public <%- toPascalCase(collection.name) %>(
71
+ <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
72
+ <%- getType(attribute) %> <%= toCamelCase(attribute.key) %><%- index < collection.attributes.length - 1 ? ',' : '' %>
73
+ <% } -%>
74
+ ) {
75
+ <% for (const attribute of collection.attributes) { -%>
76
+ this.<%= toCamelCase(attribute.key) %> = <%= toCamelCase(attribute.key) %>;
77
+ <% } -%>
78
+ }
79
+
80
+ <% for (const attribute of collection.attributes) { -%>
81
+ public <%- getType(attribute) %> get<%- toPascalCase(attribute.key) %>() {
82
+ return <%= toCamelCase(attribute.key) %>;
83
+ }
84
+
85
+ public void set<%- toPascalCase(attribute.key) %>(<%- getType(attribute) %> <%= toCamelCase(attribute.key) %>) {
86
+ this.<%= toCamelCase(attribute.key) %> = <%= toCamelCase(attribute.key) %>;
87
+ }
88
+
89
+ <% } -%>
90
+ @Override
91
+ public boolean equals(Object obj) {
92
+ if (this == obj) return true;
93
+ if (obj == null || getClass() != obj.getClass()) return false;
94
+ <%- toPascalCase(collection.name) %> that = (<%- toPascalCase(collection.name) %>) obj;
95
+ return <% collection.attributes.forEach((attr, index) => { %>Objects.equals(<%= toCamelCase(attr.key) %>, that.<%= toCamelCase(attr.key) %>)<% if (index < collection.attributes.length - 1) { %> &&
96
+ <% } }); %>;
97
+ }
98
+
99
+ @Override
100
+ public int hashCode() {
101
+ return Objects.hash(<%= collection.attributes.map(attr => toCamelCase(attr.key)).join(', ') %>);
102
+ }
103
+
104
+ @Override
105
+ public String toString() {
106
+ return "<%- toPascalCase(collection.name) %>{" +
107
+ <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
108
+ "<%= toCamelCase(attribute.key) %>=" + <%= toCamelCase(attribute.key) %> +
109
+ <% } -%>
110
+ '}';
111
+ }
112
+ }
113
+ `;
114
+ }
115
+
116
+ getFileName(collection) {
117
+ return LanguageMeta.toPascalCase(collection.name) + ".java";
118
+ }
119
+ }
120
+
121
+ module.exports = { Java };
@@ -0,0 +1,84 @@
1
+ /** @typedef {import('../attribute').Attribute} Attribute */
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+
5
+ const { AttributeType } = require('../attribute');
6
+ const { LanguageMeta } = require("./language");
7
+
8
+ class JavaScript extends LanguageMeta {
9
+ getType(attribute) {
10
+ let type = ""
11
+ switch (attribute.type) {
12
+ case AttributeType.STRING:
13
+ case AttributeType.EMAIL:
14
+ case AttributeType.DATETIME:
15
+ case AttributeType.IP:
16
+ case AttributeType.URL:
17
+ type = "string";
18
+ if (attribute.format === AttributeType.ENUM) {
19
+ type = `"${attribute.elements.join('"|"')}"`;
20
+ }
21
+ break;
22
+ case AttributeType.INTEGER:
23
+ type = "number";
24
+ break;
25
+ case AttributeType.FLOAT:
26
+ type = "number";
27
+ break;
28
+ case AttributeType.BOOLEAN:
29
+ type = "boolean";
30
+ break;
31
+ case AttributeType.RELATIONSHIP:
32
+ type = LanguageMeta.toPascalCase(attribute.relatedCollection);
33
+ if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') {
34
+ type = `Array<${type}>`;
35
+ }
36
+ break;
37
+ default:
38
+ throw new Error(`Unknown attribute type: ${attribute.type}`);
39
+ }
40
+ if (attribute.array) {
41
+ type += "[]";
42
+ }
43
+ if (!attribute.required) {
44
+ type += "|null|undefined";
45
+ }
46
+ return type;
47
+ }
48
+
49
+ isSingleFile() {
50
+ return true;
51
+ }
52
+
53
+ _getAppwriteDependency() {
54
+ if (fs.existsSync(path.resolve(process.cwd(), 'package.json'))) {
55
+ const packageJsonRaw = fs.readFileSync(path.resolve(process.cwd(), 'package.json'));
56
+ const packageJson = JSON.parse(packageJsonRaw.toString('utf-8'));
57
+ return packageJson.dependencies['node-appwrite'] ? 'node-appwrite' : 'appwrite';
58
+ }
59
+
60
+ return "appwrite";
61
+ }
62
+
63
+ getTemplate() {
64
+ return `/**
65
+ * @typedef {import('${this._getAppwriteDependency()}').Models.Document} Document
66
+ */
67
+
68
+ <% for (const collection of collections) { %>
69
+ /**
70
+ * @typedef {Object} <%- toPascalCase(collection.name) %>
71
+ <% for (const attribute of collection.attributes) { -%>
72
+ * @property {<%- getType(attribute) %>} <%- toCamelCase(attribute.key) %>
73
+ <% } -%>
74
+ */
75
+
76
+ <% } %>`;
77
+ }
78
+
79
+ getFileName(_) {
80
+ return "appwrite-types.js";
81
+ }
82
+ }
83
+
84
+ module.exports = { JavaScript };
@@ -0,0 +1,75 @@
1
+ /** @typedef {import('../attribute').Attribute} Attribute */
2
+ const { AttributeType } = require('../attribute');
3
+ const { LanguageMeta } = require("./language");
4
+
5
+ class Kotlin extends LanguageMeta {
6
+ getType(attribute) {
7
+ let type = "";
8
+ switch (attribute.type) {
9
+ case AttributeType.STRING:
10
+ case AttributeType.EMAIL:
11
+ case AttributeType.DATETIME:
12
+ type = "String";
13
+ if (attribute.format === AttributeType.ENUM) {
14
+ type = LanguageMeta.toPascalCase(attribute.key);
15
+ }
16
+ break;
17
+ case AttributeType.INTEGER:
18
+ type = "Int";
19
+ break;
20
+ case AttributeType.FLOAT:
21
+ type = "Float";
22
+ break;
23
+ case AttributeType.BOOLEAN:
24
+ type = "Boolean";
25
+ break;
26
+ case AttributeType.RELATIONSHIP:
27
+ type = LanguageMeta.toPascalCase(attribute.relatedCollection);
28
+ if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') {
29
+ type = `List<${type}>`;
30
+ }
31
+ break;
32
+ default:
33
+ throw new Error(`Unknown attribute type: ${attribute.type}`);
34
+ }
35
+ if (attribute.array) {
36
+ type = "List<" + type + ">";
37
+ }
38
+ if (!attribute.required) {
39
+ type += "?";
40
+ }
41
+ return type;
42
+ }
43
+
44
+ getTemplate() {
45
+ return `package io.appwrite.models
46
+
47
+ <% for (const attribute of collection.attributes) { -%>
48
+ <% if (attribute.type === 'relationship') { -%>
49
+ import <%- toPascalCase(attribute.relatedCollection) %>
50
+
51
+ <% } -%>
52
+ <% } -%>
53
+ <% for (const attribute of collection.attributes) { -%>
54
+ <% if (attribute.format === 'enum') { -%>
55
+ enum class <%- toPascalCase(attribute.key) %> {
56
+ <% for (const [index, element] of Object.entries(attribute.elements)) { -%>
57
+ <%- element %><%- index < attribute.elements.length - 1 ? ',' : '' %>
58
+ <% } -%>
59
+ }
60
+
61
+ <% } -%>
62
+ <% } -%>
63
+ data class <%- toPascalCase(collection.name) %>(
64
+ <% for (const attribute of collection.attributes) { -%>
65
+ val <%- toCamelCase(attribute.key) %>: <%- getType(attribute) %>,
66
+ <% } -%>
67
+ )`;
68
+ }
69
+
70
+ getFileName(collection) {
71
+ return LanguageMeta.toPascalCase(collection.name) + ".kt";
72
+ }
73
+ }
74
+
75
+ module.exports = { Kotlin };
@@ -0,0 +1,125 @@
1
+ /** @typedef {import('../attribute').Attribute} Attribute */
2
+ /** @typedef {import('../collection').Collection} Collection */
3
+
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+
7
+ class LanguageMeta {
8
+ constructor() {
9
+ if (new.target === LanguageMeta) {
10
+ throw new TypeError("Abstract classes can't be instantiated.");
11
+ }
12
+ }
13
+
14
+ static toKebabCase(string) {
15
+ return string
16
+ .replace(/[^a-zA-Z0-9\s-_]/g, "") // Remove invalid characters
17
+ .replace(/([a-z])([A-Z])/g, "$1-$2") // Add hyphen between camelCase
18
+ .replace(/([A-Z])([A-Z][a-z])/g, "$1-$2") // Add hyphen between PascalCase
19
+ .replace(/[_\s]+/g, "-") // Replace spaces and underscores with hyphens
20
+ .replace(/^-+|-+$/g, "") // Remove leading and trailing hyphens
21
+ .replace(/--+/g, "-") // Replace multiple hyphens with a single hyphen
22
+ .toLowerCase();
23
+ }
24
+
25
+ static toSnakeCase(string) {
26
+ return this.toKebabCase(string).replace(/-/g, "_");
27
+ }
28
+
29
+ static toUpperSnakeCase(string) {
30
+ return this.toSnakeCase(string).toUpperCase();
31
+ }
32
+
33
+ static toCamelCase(string) {
34
+ return this.toKebabCase(string).replace(/-([a-z0-9])/g, (g) =>
35
+ g[1].toUpperCase()
36
+ );
37
+ }
38
+
39
+ static toPascalCase(string) {
40
+ return this.toCamelCase(string).replace(/^./, (g) => g.toUpperCase());
41
+ }
42
+
43
+ /**
44
+ * Get the type literal of the given attribute.
45
+ *
46
+ * @abstract
47
+ * @param {Attribute} attribute
48
+ * @return {string}
49
+ */
50
+ getType(attribute) {
51
+ throw new TypeError("Stub.");
52
+ }
53
+
54
+ /**
55
+ * Returns true if the language uses a single file for all types.
56
+ *
57
+ * @returns {boolean}
58
+ */
59
+ isSingleFile() {
60
+ return false;
61
+ }
62
+
63
+ /**
64
+ * Get the EJS template used to generate the types for this language.
65
+ *
66
+ * @abstract
67
+ * @returns {string}
68
+ */
69
+ getTemplate() {
70
+ throw new TypeError("Stub.");
71
+ }
72
+
73
+ /**
74
+ * Get the file extension used by files of this language.
75
+ *
76
+ * @abstract
77
+ * @param {Collection|undefined} collection
78
+ * @returns {string}
79
+ */
80
+ getFileName(collection) {
81
+ throw new TypeError("Stub.");
82
+ }
83
+ }
84
+
85
+ const existsFiles = (...files) =>
86
+ files.some((file) => fs.existsSync(path.join(process.cwd(), file)));
87
+
88
+ /**
89
+ * @returns {string}
90
+ */
91
+ function detectLanguage() {
92
+ if (existsFiles("tsconfig.json", "deno.json")) {
93
+ return "ts";
94
+ }
95
+ if (existsFiles("package.json")) {
96
+ return "js";
97
+ }
98
+ if (existsFiles("composer.json")) {
99
+ return "php";
100
+ }
101
+ if (existsFiles("requirements.txt", "Pipfile", "pyproject.toml")) {
102
+ return "python";
103
+ }
104
+ if (existsFiles("Gemfile", "Rakefile")) {
105
+ return "ruby";
106
+ }
107
+ if (existsFiles("build.gradle.kts")) {
108
+ return "kotlin";
109
+ }
110
+ if (existsFiles("build.gradle", "pom.xml")) {
111
+ return "java";
112
+ }
113
+ if (existsFiles("*.csproj")) {
114
+ return "dotnet";
115
+ }
116
+ if (existsFiles("Package.swift")) {
117
+ return "swift";
118
+ }
119
+ if (existsFiles("pubspec.yaml")) {
120
+ return "dart";
121
+ }
122
+ throw new Error("Could not detect language, please specify with -l");
123
+ }
124
+
125
+ module.exports = { LanguageMeta, detectLanguage };
@@ -0,0 +1,100 @@
1
+ /** @typedef {import('../attribute').Attribute} Attribute */
2
+ const { AttributeType } = require('../attribute');
3
+ const { LanguageMeta } = require("./language");
4
+
5
+ class PHP extends LanguageMeta {
6
+ getType(attribute) {
7
+ if (attribute.array) {
8
+ return "array";
9
+ }
10
+ let type = ""
11
+ switch (attribute.type) {
12
+ case AttributeType.STRING:
13
+ case AttributeType.EMAIL:
14
+ case AttributeType.DATETIME:
15
+ type = "string";
16
+ if (attribute.format === AttributeType.ENUM) {
17
+ type = LanguageMeta.toPascalCase(attribute.key);
18
+ }
19
+ break;
20
+ case AttributeType.INTEGER:
21
+ type = "int";
22
+ break;
23
+ case AttributeType.FLOAT:
24
+ type = "float";
25
+ break;
26
+ case AttributeType.BOOLEAN:
27
+ type = "bool";
28
+ break;
29
+ case AttributeType.RELATIONSHIP:
30
+ type = LanguageMeta.toPascalCase(attribute.relatedCollection);
31
+ if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') {
32
+ type = "array";
33
+ }
34
+ break;
35
+ default:
36
+ throw new Error(`Unknown attribute type: ${attribute.type}`);
37
+ }
38
+ if (!attribute.required) {
39
+ type += "|null";
40
+ }
41
+ return type;
42
+ }
43
+
44
+ getTemplate() {
45
+ return `<?php
46
+ namespace Appwrite\\Models;
47
+
48
+ <% for (const attribute of collection.attributes) { -%>
49
+ <% if (attribute.type === 'relationship' && !(attribute.relationType === 'manyToMany') && !(attribute.relationType === 'oneToMany' && attribute.side === 'parent')) { -%>
50
+ use Appwrite\\Models\\<%- toPascalCase(attribute.relatedCollection) %>;
51
+
52
+ <% } -%>
53
+ <% } -%>
54
+ <% for (const attribute of collection.attributes) { -%>
55
+ <% if (attribute.format === 'enum') { -%>
56
+ enum <%- toPascalCase(attribute.key) %> {
57
+ <% for (const [index, element] of Object.entries(attribute.elements)) { -%>
58
+ case <%- element.toUpperCase() %> = '<%- element %>';
59
+ <% } -%>
60
+ }
61
+
62
+ <% } -%>
63
+ <% } -%>
64
+ class <%- toPascalCase(collection.name) %> {
65
+ <% for (const attribute of collection.attributes ){ -%>
66
+ private <%- getType(attribute) %> $<%- toCamelCase(attribute.key) %>;
67
+ <% } -%>
68
+
69
+ public function __construct(
70
+ <% for (const attribute of collection.attributes ){ -%>
71
+ <% if (attribute.required) { -%>
72
+ <%- getType(attribute).replace('|null', '') %> $<%- toCamelCase(attribute.key) %><% if (collection.attributes.indexOf(attribute) < collection.attributes.length - 1) { %>,<% } %>
73
+ <% } else { -%>
74
+ ?<%- getType(attribute).replace('|null', '') %> $<%- toCamelCase(attribute.key) %> = null<% if (collection.attributes.indexOf(attribute) < collection.attributes.length - 1) { %>,<% } %>
75
+ <% } -%>
76
+ <% } -%>
77
+ ) {
78
+ <% for (const attribute of collection.attributes ){ -%>
79
+ $this-><%- toCamelCase(attribute.key) %> = $<%- toCamelCase(attribute.key) %>;
80
+ <% } -%>
81
+ }
82
+
83
+ <% for (const attribute of collection.attributes ){ -%>
84
+ public function get<%- toPascalCase(attribute.key) %>(): <%- getType(attribute) %> {
85
+ return $this-><%- toCamelCase(attribute.key) %>;
86
+ }
87
+
88
+ public function set<%- toPascalCase(attribute.key) %>(<%- getType(attribute) %> $<%- toCamelCase(attribute.key) %>): void {
89
+ $this-><%- toCamelCase(attribute.key) %> = $<%- toCamelCase(attribute.key) %>;
90
+ }
91
+ <% } -%>
92
+ }`;
93
+ }
94
+
95
+ getFileName(collection) {
96
+ return LanguageMeta.toPascalCase(collection.name) + ".php";
97
+ }
98
+ }
99
+
100
+ module.exports = { PHP };
@@ -0,0 +1,156 @@
1
+ /** @typedef {import('../attribute').Attribute} Attribute */
2
+ const { AttributeType } = require('../attribute');
3
+ const { LanguageMeta } = require("./language");
4
+
5
+ class Swift extends LanguageMeta {
6
+ getType(attribute) {
7
+ let type = "";
8
+ switch (attribute.type) {
9
+ case AttributeType.STRING:
10
+ case AttributeType.EMAIL:
11
+ case AttributeType.DATETIME:
12
+ type = "String";
13
+ if (attribute.format === AttributeType.ENUM) {
14
+ type = LanguageMeta.toPascalCase(attribute.key);
15
+ }
16
+ break;
17
+ case AttributeType.INTEGER:
18
+ type = "Int";
19
+ break;
20
+ case AttributeType.FLOAT:
21
+ type = "Double";
22
+ break;
23
+ case AttributeType.BOOLEAN:
24
+ type = "Bool";
25
+ break;
26
+ case AttributeType.RELATIONSHIP:
27
+ type = LanguageMeta.toPascalCase(attribute.relatedCollection);
28
+ if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') {
29
+ type = `[${type}]`;
30
+ }
31
+ break;
32
+ default:
33
+ throw new Error(`Unknown attribute type: ${attribute.type}`);
34
+ }
35
+ if (attribute.array) {
36
+ type = "[" + type + "]";
37
+ }
38
+ if (!attribute.required) {
39
+ type += "?";
40
+ }
41
+ return type;
42
+ }
43
+
44
+ getTemplate() {
45
+ return `import Foundation
46
+
47
+ <% for (const attribute of collection.attributes) { -%>
48
+ <% if (attribute.format === 'enum') { -%>
49
+ public enum <%- toPascalCase(attribute.key) %>: String, Codable, CaseIterable {
50
+ <% for (const [index, element] of Object.entries(attribute.elements)) { -%>
51
+ case <%- element %> = "<%- element %>"
52
+ <% } -%>
53
+ }
54
+
55
+ <% } -%>
56
+ <% } -%>
57
+ public class <%- toPascalCase(collection.name) %>: Codable {
58
+ <% for (const attribute of collection.attributes) { -%>
59
+ public let <%- toCamelCase(attribute.key) %>: <%- getType(attribute) %>
60
+ <% } %>
61
+ enum CodingKeys: String, CodingKey {
62
+ <% for (const attribute of collection.attributes) { -%>
63
+ case <%- toCamelCase(attribute.key) %> = "<%- attribute.key %>"
64
+ <% } -%>
65
+ }
66
+
67
+ init(
68
+ <% for (const attribute of collection.attributes) { -%>
69
+ <%- toCamelCase(attribute.key) %>: <%- getType(attribute) %><% if (attribute !== collection.attributes[collection.attributes.length - 1]) { %>,<% } %>
70
+ <% } -%>
71
+ ) {
72
+ <% for (const attribute of collection.attributes) { -%>
73
+ self.<%- toCamelCase(attribute.key) %> = <%- toCamelCase(attribute.key) %>
74
+ <% } -%>
75
+ }
76
+
77
+ public required init(from decoder: Decoder) throws {
78
+ let container = try decoder.container(keyedBy: CodingKeys.self)
79
+
80
+ <% for (const attribute of collection.attributes) { -%>
81
+ <% if (attribute.required) { -%>
82
+ self.<%- toCamelCase(attribute.key) %> = try container.decode(<%- getType(attribute).replace('?', '') %>.self, forKey: .<%- toCamelCase(attribute.key) %>)
83
+ <% } else { -%>
84
+ self.<%- toCamelCase(attribute.key) %> = try container.decodeIfPresent(<%- getType(attribute).replace('?', '') %>.self, forKey: .<%- toCamelCase(attribute.key) %>)
85
+ <% } -%>
86
+ <% } -%>
87
+ }
88
+
89
+ public func encode(to encoder: Encoder) throws {
90
+ var container = encoder.container(keyedBy: CodingKeys.self)
91
+
92
+ <% for (const attribute of collection.attributes) { -%>
93
+ <% if (attribute.required) { -%>
94
+ try container.encode(<%- toCamelCase(attribute.key) %>, forKey: .<%- toCamelCase(attribute.key) %>)
95
+ <% } else { -%>
96
+ try container.encodeIfPresent(<%- toCamelCase(attribute.key) %>, forKey: .<%- toCamelCase(attribute.key) %>)
97
+ <% } -%>
98
+ <% } -%>
99
+ }
100
+
101
+ public func toMap() -> [String: Any] {
102
+ return [
103
+ <% for (const attribute of collection.attributes) { -%>
104
+ <% if (attribute.type === 'relationship') { -%>
105
+ "<%- attribute.key %>": <%- toCamelCase(attribute.key) %> as Any<% if (attribute !== collection.attributes[collection.attributes.length - 1]) { %>,<% } %>
106
+ <% } else if (attribute.array && attribute.type !== 'string' && attribute.type !== 'integer' && attribute.type !== 'float' && attribute.type !== 'boolean') { -%>
107
+ "<%- attribute.key %>": <%- toCamelCase(attribute.key) %>?.map { $0.toMap() } as Any<% if (attribute !== collection.attributes[collection.attributes.length - 1]) { %>,<% } %>
108
+ <% } else { -%>
109
+ "<%- attribute.key %>": <%- toCamelCase(attribute.key) %> as Any<% if (attribute !== collection.attributes[collection.attributes.length - 1]) { %>,<% } %>
110
+ <% } -%>
111
+ <% } -%>
112
+ ]
113
+ }
114
+
115
+ public static func from(map: [String: Any]) -> <%- toPascalCase(collection.name) %> {
116
+ return <%- toPascalCase(collection.name) %>(
117
+ <% for (const attribute of collection.attributes) { -%>
118
+ <% if (attribute.type === 'relationship') { -%>
119
+ <%- toCamelCase(attribute.key) %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> <%- toPascalCase(attribute.relatedCollection) %><% if (attribute !== collection.attributes[collection.attributes.length - 1]) { %>,<% } %>
120
+ <% } else if (attribute.array) { -%>
121
+ <% if (attribute.type === 'string') { -%>
122
+ <%- toCamelCase(attribute.key) %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [String]<% if (attribute !== collection.attributes[collection.attributes.length - 1]) { %>,<% } %>
123
+ <% } else if (attribute.type === 'integer') { -%>
124
+ <%- toCamelCase(attribute.key) %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [Int]<% if (attribute !== collection.attributes[collection.attributes.length - 1]) { %>,<% } %>
125
+ <% } else if (attribute.type === 'float') { -%>
126
+ <%- toCamelCase(attribute.key) %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [Double]<% if (attribute !== collection.attributes[collection.attributes.length - 1]) { %>,<% } %>
127
+ <% } else if (attribute.type === 'boolean') { -%>
128
+ <%- toCamelCase(attribute.key) %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [Bool]<% if (attribute !== collection.attributes[collection.attributes.length - 1]) { %>,<% } %>
129
+ <% } else { -%>
130
+ <%- toCamelCase(attribute.key) %>: (map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> [[String: Any]])<% if (!attribute.required) { %>?<% } %>.map { <%- toPascalCase(attribute.type) %>.from(map: $0) }<% if (attribute !== collection.attributes[collection.attributes.length - 1]) { %>,<% } %>
131
+ <% } -%>
132
+ <% } else { -%>
133
+ <% if (attribute.type === 'string' || attribute.type === 'email' || attribute.type === 'datetime' || attribute.type === 'enum') { -%>
134
+ <%- toCamelCase(attribute.key) %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> String<% if (attribute !== collection.attributes[collection.attributes.length - 1]) { %>,<% } %>
135
+ <% } else if (attribute.type === 'integer') { -%>
136
+ <%- toCamelCase(attribute.key) %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> Int<% if (attribute !== collection.attributes[collection.attributes.length - 1]) { %>,<% } %>
137
+ <% } else if (attribute.type === 'float') { -%>
138
+ <%- toCamelCase(attribute.key) %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> Double<% if (attribute !== collection.attributes[collection.attributes.length - 1]) { %>,<% } %>
139
+ <% } else if (attribute.type === 'boolean') { -%>
140
+ <%- toCamelCase(attribute.key) %>: map["<%- attribute.key %>"] as<% if (!attribute.required) { %>?<% } else { %>!<% } %> Bool<% if (attribute !== collection.attributes[collection.attributes.length - 1]) { %>,<% } %>
141
+ <% } else { -%>
142
+ <%- toCamelCase(attribute.key) %>: <%- toPascalCase(attribute.type) %>.from(map: map["<%- attribute.key %>"] as! [String: Any])<% if (attribute !== collection.attributes[collection.attributes.length - 1]) { %>,<% } %>
143
+ <% } -%>
144
+ <% } -%>
145
+ <% } -%>
146
+ )
147
+ }
148
+ }`;
149
+ }
150
+
151
+ getFileName(collection) {
152
+ return LanguageMeta.toPascalCase(collection.name) + ".swift";
153
+ }
154
+ }
155
+
156
+ module.exports = { Swift };
@@ -0,0 +1,95 @@
1
+ /** @typedef {import('../attribute').Attribute} Attribute */
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+
5
+ const { AttributeType } = require('../attribute');
6
+ const { LanguageMeta } = require("./language");
7
+
8
+ class TypeScript extends LanguageMeta {
9
+ getType(attribute) {
10
+ let type = ""
11
+ switch (attribute.type) {
12
+ case AttributeType.STRING:
13
+ case AttributeType.EMAIL:
14
+ case AttributeType.DATETIME:
15
+ case AttributeType.IP:
16
+ case AttributeType.URL:
17
+ type = "string";
18
+ if (attribute.format === AttributeType.ENUM) {
19
+ type = LanguageMeta.toPascalCase(attribute.key);
20
+ }
21
+ break;
22
+ case AttributeType.INTEGER:
23
+ type = "number";
24
+ break;
25
+ case AttributeType.FLOAT:
26
+ type = "number";
27
+ break;
28
+ case AttributeType.BOOLEAN:
29
+ type = "boolean";
30
+ break;
31
+ case AttributeType.RELATIONSHIP:
32
+ type = LanguageMeta.toPascalCase(attribute.relatedCollection);
33
+ if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') {
34
+ type = `${type}[]`;
35
+ }
36
+ break;
37
+ default:
38
+ throw new Error(`Unknown attribute type: ${attribute.type}`);
39
+ }
40
+ if (attribute.array) {
41
+ type += "[]";
42
+ }
43
+ if (!attribute.required) {
44
+ type += " | null";
45
+ }
46
+ return type;
47
+ }
48
+
49
+ isSingleFile() {
50
+ return true;
51
+ }
52
+
53
+ _getAppwriteDependency() {
54
+ if (fs.existsSync(path.resolve(process.cwd(), 'package.json'))) {
55
+ const packageJsonRaw = fs.readFileSync(path.resolve(process.cwd(), 'package.json'));
56
+ const packageJson = JSON.parse(packageJsonRaw.toString('utf-8'));
57
+ return packageJson.dependencies['node-appwrite'] ? 'node-appwrite' : 'appwrite';
58
+ }
59
+
60
+ if (fs.existsSync(path.resolve(process.cwd(), 'deno.json'))) {
61
+ return "https://deno.land/x/appwrite/mod.ts";
62
+ }
63
+
64
+ return "appwrite";
65
+ }
66
+
67
+ getTemplate() {
68
+ return `import { Models } from '${this._getAppwriteDependency()}';
69
+
70
+ <% for (const collection of collections) { -%>
71
+ <% for (const attribute of collection.attributes) { -%>
72
+ <% if (attribute.format === 'enum') { -%>
73
+ export enum <%- toPascalCase(attribute.key) %> {
74
+ <% for (const [index, element] of Object.entries(attribute.elements)) { -%>
75
+ <%- element.toUpperCase() %> = "<%- element %>",
76
+ <% } -%>
77
+ }
78
+ <% } -%>
79
+ <% } -%>
80
+ <% } -%>
81
+ <% for (const collection of collections) { %>
82
+ export type <%- toPascalCase(collection.name) %> = Models.Document & {
83
+ <% for (const attribute of collection.attributes) { -%>
84
+ <%- toCamelCase(attribute.key) %>: <%- getType(attribute) %>;
85
+ <% } -%>
86
+ }
87
+ <% } %>`;
88
+ }
89
+
90
+ getFileName(_) {
91
+ return "appwrite.d.ts";
92
+ }
93
+ }
94
+
95
+ module.exports = { TypeScript };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "appwrite-cli",
3
3
  "homepage": "https://appwrite.io/support",
4
4
  "description": "Appwrite is an open-source self-hosted backend server that abstract and simplify complex and repetitive development tasks behind a very simple REST API",
5
- "version": "7.0.0",
5
+ "version": "8.0.0",
6
6
  "license": "BSD-3-Clause",
7
7
  "main": "index.js",
8
8
  "bin": {
@@ -23,6 +23,7 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "undici": "^5.28.2",
26
+ "ejs": "^3.1.9",
26
27
  "chalk": "4.1.2",
27
28
  "cli-progress": "^3.12.0",
28
29
  "cli-table3": "^0.6.2",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/ScoopInstaller/Scoop/master/schema.json",
3
- "version": "7.0.0",
3
+ "version": "8.0.0",
4
4
  "description": "The Appwrite CLI is a command-line application that allows you to interact with Appwrite and perform server-side tasks using your terminal.",
5
5
  "homepage": "https://github.com/appwrite/sdk-for-cli",
6
6
  "license": "BSD-3-Clause",
7
7
  "architecture": {
8
8
  "64bit": {
9
- "url": "https://github.com/appwrite/sdk-for-cli/releases/download/7.0.0/appwrite-cli-win-x64.exe",
9
+ "url": "https://github.com/appwrite/sdk-for-cli/releases/download/8.0.0/appwrite-cli-win-x64.exe",
10
10
  "bin": [
11
11
  [
12
12
  "appwrite-cli-win-x64.exe",
@@ -15,7 +15,7 @@
15
15
  ]
16
16
  },
17
17
  "arm64": {
18
- "url": "https://github.com/appwrite/sdk-for-cli/releases/download/7.0.0/appwrite-cli-win-arm64.exe",
18
+ "url": "https://github.com/appwrite/sdk-for-cli/releases/download/8.0.0/appwrite-cli-win-arm64.exe",
19
19
  "bin": [
20
20
  [
21
21
  "appwrite-cli-win-arm64.exe",
@@ -1,2 +0,0 @@
1
- appwrite assistant chat \
2
- --prompt <PROMPT>
@@ -1,85 +0,0 @@
1
- const fs = require('fs');
2
- const pathLib = require('path');
3
- const tar = require("tar");
4
- const ignore = require("ignore");
5
- const { promisify } = require('util');
6
- const libClient = require('../client.js');
7
- const { getAllFiles, showConsoleLink } = require('../utils.js');
8
- const { Command } = require('commander');
9
- const { sdkForProject, sdkForConsole } = require('../sdks')
10
- const { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log } = require('../parser')
11
- const { localConfig, globalConfig } = require("../config");
12
- const { File } = require('undici');
13
- const { ReadableStream } = require('stream/web');
14
-
15
- /**
16
- * @param {fs.ReadStream} readStream
17
- * @returns {ReadableStream}
18
- */
19
- function convertReadStreamToReadableStream(readStream) {
20
- return new ReadableStream({
21
- start(controller) {
22
- readStream.on("data", (chunk) => {
23
- controller.enqueue(chunk);
24
- });
25
- readStream.on("end", () => {
26
- controller.close();
27
- });
28
- readStream.on("error", (err) => {
29
- controller.error(err);
30
- });
31
- },
32
- cancel() {
33
- readStream.destroy();
34
- },
35
- });
36
- }
37
-
38
- const assistant = new Command("assistant").description(commandDescriptions['assistant'] ?? '').configureHelp({
39
- helpWidth: process.stdout.columns || 80
40
- })
41
-
42
- /**
43
- * @typedef {Object} AssistantChatRequestParams
44
- * @property {string} prompt Prompt. A string containing questions asked to the AI assistant.
45
- * @property {boolean} overrideForCli
46
- * @property {boolean} parseOutput
47
- * @property {libClient | undefined} sdk
48
- */
49
-
50
- /**
51
- * @param {AssistantChatRequestParams} params
52
- */
53
- const assistantChat = async ({prompt,parseOutput = true, overrideForCli = false, sdk = undefined}) => {
54
- let client = !sdk ? await sdkForProject() :
55
- sdk;
56
- let apiPath = '/console/assistant';
57
- let payload = {};
58
- if (typeof prompt !== 'undefined') {
59
- payload['prompt'] = prompt;
60
- }
61
-
62
- let response = undefined;
63
-
64
- response = await client.call('post', apiPath, {
65
- 'content-type': 'application/json',
66
- }, payload);
67
-
68
- if (parseOutput) {
69
- parse(response)
70
- }
71
-
72
- return response;
73
-
74
- }
75
-
76
- assistant
77
- .command(`chat`)
78
- .description(`Send a prompt to the AI assistant and receive a response. This endpoint allows you to interact with Appwrite's AI assistant by sending questions or prompts and receiving helpful responses in real-time through a server-sent events stream. `)
79
- .requiredOption(`--prompt <prompt>`, `Prompt. A string containing questions asked to the AI assistant.`)
80
- .action(actionRunner(assistantChat))
81
-
82
- module.exports = {
83
- assistant,
84
- assistantChat
85
- };