Skip to content

Commit 7381d2d

Browse files
Merge pull request #1102 from appwrite/type-generation-improvements
2 parents 4b363a1 + 8f81603 commit 7381d2d

File tree

8 files changed

+206
-128
lines changed

8 files changed

+206
-128
lines changed

templates/cli/lib/commands/types.js.twig

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,22 @@ const typesLanguageOption = new Option(
5858
.choices(["auto", "ts", "js", "php", "kotlin", "swift", "java", "dart"])
5959
.default("auto");
6060

61-
const typesCommand = actionRunner(async (rawOutputDirectory, {language}) => {
61+
const typesStrictOption = new Option(
62+
"-s, --strict",
63+
"Enable strict mode to automatically convert field names to follow language conventions"
64+
)
65+
.default(false);
66+
67+
const typesCommand = actionRunner(async (rawOutputDirectory, {language, strict}) => {
6268
if (language === "auto") {
6369
language = detectLanguage();
6470
log(`Detected language: ${language}`);
6571
}
6672

73+
if (strict) {
74+
log(`Strict mode enabled: Field names will be converted to follow ${language} conventions`);
75+
}
76+
6777
const meta = createLanguageMeta(language);
6878

6979
const rawOutputPath = rawOutputDirectory;
@@ -106,6 +116,7 @@ const typesCommand = actionRunner(async (rawOutputDirectory, {language}) => {
106116
if (meta.isSingleFile()) {
107117
const content = templater({
108118
collections,
119+
strict,
109120
...templateHelpers,
110121
getType: meta.getType
111122
});
@@ -118,6 +129,7 @@ const typesCommand = actionRunner(async (rawOutputDirectory, {language}) => {
118129
for (const collection of collections) {
119130
const content = templater({
120131
collection,
132+
strict,
121133
...templateHelpers,
122134
getType: meta.getType
123135
});
@@ -136,6 +148,7 @@ const types = new Command("types")
136148
.description("Generate types for your Appwrite project")
137149
.addArgument(typesOutputArgument)
138150
.addOption(typesLanguageOption)
151+
.addOption(typesStrictOption)
139152
.action(actionRunner(typesCommand));
140153

141154
module.exports = { types };

templates/cli/lib/type-generation/languages/dart.js.twig

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,45 @@
11
/** @typedef {import('../attribute').Attribute} Attribute */
22
const { AttributeType } = require('../attribute');
33
const { LanguageMeta } = require("./language");
4+
const fs = require('fs');
5+
const path = require('path');
46

57
class Dart extends LanguageMeta {
8+
getPackageName() {
9+
const pubspecPath = path.join(this.getCurrentDirectory(), 'pubspec.yaml');
10+
if (fs.existsSync(pubspecPath)) {
11+
const pubspecContent = fs.readFileSync(pubspecPath, 'utf8');
12+
const lines = pubspecContent.split('\n');
13+
14+
const dependenciesIndex = lines.findIndex(line => line.trim() === 'dependencies:');
15+
16+
if (dependenciesIndex !== -1) {
17+
const indent = lines[dependenciesIndex].search(/\S|$/);
18+
const dependencies = [];
19+
for (let i = dependenciesIndex + 1; i < lines.length; i++) {
20+
const line = lines[i];
21+
if (line.trim() === '') continue;
22+
23+
const lineIndent = line.search(/\S|$/);
24+
if (lineIndent <= indent && line.trim() !== '') {
25+
break;
26+
}
27+
28+
dependencies.push(line.trim());
29+
}
30+
31+
if (dependencies.some(dep => dep.startsWith('dart_appwrite:'))) {
32+
return 'dart_appwrite';
33+
}
34+
if (dependencies.some(dep => dep.startsWith('appwrite:'))) {
35+
return 'appwrite';
36+
}
37+
}
38+
}
39+
40+
return 'appwrite';
41+
}
42+
643
getType(attribute) {
744
let type = "";
845
switch (attribute.type) {
@@ -46,42 +83,55 @@ class Dart extends LanguageMeta {
4683
}
4784

4885
getTemplate() {
49-
return `<% for (const attribute of collection.attributes) { -%>
86+
return `import 'package:${this.getPackageName()}/models.dart';
87+
<% for (const attribute of collection.attributes) { -%>
5088
<% if (attribute.type === 'relationship') { -%>
5189
import '<%- attribute.relatedCollection.toLowerCase() %>.dart';
5290

5391
<% } -%>
5492
<% } -%>
55-
/**
56-
* This file is auto-generated by the Appwrite CLI.
57-
* You can regenerate it by running \`appwrite types -l dart ${this.getCurrentDirectory()}\`.
58-
*/
93+
/// This file is auto-generated by the Appwrite CLI.
94+
/// You can regenerate it by running \`appwrite types -l dart ${this.getCurrentDirectory()}\`.
5995

6096
<% for (const attribute of collection.attributes) { -%>
6197
<% if (attribute.format === 'enum') { -%>
6298
enum <%- toPascalCase(attribute.key) %> {
6399
<% for (const [index, element] of Object.entries(attribute.elements)) { -%>
64-
<%- toSnakeCase(element) %><% if (index < attribute.elements.length - 1) { %>,<% } %>
100+
<%- strict ? toCamelCase(element) : element %><% if (index < attribute.elements.length - 1) { %>,<% } %>
65101
<% } -%>
66102
}
67103

68104
<% } -%>
69105
<% } -%>
70-
class <%= toPascalCase(collection.name) %> {
106+
class <%= toPascalCase(collection.name) %> extends Document {
71107
<% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
72-
<%- getType(attribute) %> <%= toCamelCase(attribute.key) %>;
108+
<%- getType(attribute) %> <%= strict ? toCamelCase(attribute.key) : attribute.key %>;
73109
<% } -%>
74110

75111
<%= toPascalCase(collection.name) %>({
112+
required super.$id,
113+
required super.$collectionId,
114+
required super.$databaseId,
115+
required super.$createdAt,
116+
required super.$updatedAt,
117+
required super.$permissions,
118+
required super.data,
76119
<% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
77-
<% if (attribute.required) { %>required <% } %>this.<%= toCamelCase(attribute.key) %><% if (index < collection.attributes.length - 1) { %>,<% } %>
120+
<% if (attribute.required) { %>required <% } %>this.<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (index < collection.attributes.length - 1) { %>,<% } %>
78121
<% } -%>
79122
});
80123

81124
factory <%= toPascalCase(collection.name) %>.fromMap(Map<String, dynamic> map) {
82125
return <%= toPascalCase(collection.name) %>(
126+
$id: map['\\$id'].toString(),
127+
$collectionId: map['\\$collectionId'].toString(),
128+
$databaseId: map['\\$databaseId'].toString(),
129+
$createdAt: map['\\$createdAt'].toString(),
130+
$updatedAt: map['\\$updatedAt'].toString(),
131+
$permissions: List<String>.from(map['\\$permissions'] ?? []),
132+
data: map,
83133
<% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
84-
<%= toCamelCase(attribute.key) %>: <% if (attribute.type === 'string' || attribute.type === 'email' || attribute.type === 'datetime') { -%>
134+
<%= strict ? toCamelCase(attribute.key) : attribute.key %>: <% if (attribute.type === 'string' || attribute.type === 'email' || attribute.type === 'datetime') { -%>
85135
<% if (attribute.format === 'enum') { -%>
86136
<% if (attribute.array) { -%>
87137
(map['<%= attribute.key %>'] as List<dynamic>?)?.map((e) => <%- toPascalCase(attribute.key) %>.values.firstWhere((element) => element.name == e)).toList()<% if (!attribute.required) { %> ?? []<% } -%>
@@ -130,21 +180,27 @@ map['<%= attribute.key %>'] != null ? <%- toPascalCase(attribute.relatedCollecti
130180

131181
Map<String, dynamic> toMap() {
132182
return {
183+
"\\$id": $id,
184+
"\\$collectionId": $collectionId,
185+
"\\$databaseId": $databaseId,
186+
"\\$createdAt": $createdAt,
187+
"\\$updatedAt": $updatedAt,
188+
"\\$permissions": $permissions,
133189
<% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
134190
"<%= attribute.key %>": <% if (attribute.type === 'relationship') { -%>
135191
<% if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') { -%>
136-
<%= toCamelCase(attribute.key) %><% if (!attribute.required) { %>?<% } %>.map((e) => e.toMap()).toList()<% if (!attribute.required) { %> ?? []<% } -%>
192+
<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.map((e) => e.toMap()).toList()<% if (!attribute.required) { %> ?? []<% } -%>
137193
<% } else { -%>
138-
<%= toCamelCase(attribute.key) %><% if (!attribute.required) { %>?<% } %>.toMap()<% if (!attribute.required) { %> ?? {}<% } -%>
194+
<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.toMap()<% if (!attribute.required) { %> ?? {}<% } -%>
139195
<% } -%>
140196
<% } else if (attribute.format === 'enum') { -%>
141197
<% if (attribute.array) { -%>
142-
<%= toCamelCase(attribute.key) %><% if (!attribute.required) { %>?<% } %>.map((e) => e.name).toList()<% if (!attribute.required) { %> ?? []<% } -%>
198+
<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.map((e) => e.name).toList()<% if (!attribute.required) { %> ?? []<% } -%>
143199
<% } else { -%>
144-
<%= toCamelCase(attribute.key) %><% if (!attribute.required) { %>?<% } %>.name<% if (!attribute.required) { %> ?? null<% } -%>
200+
<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.name<% if (!attribute.required) { %> ?? null<% } -%>
145201
<% } -%>
146202
<% } else { -%>
147-
<%= toCamelCase(attribute.key) -%>
203+
<%= strict ? toCamelCase(attribute.key) : attribute.key -%>
148204
<% } -%><% if (index < collection.attributes.length - 1) { %>,<% } %>
149205
<% } -%>
150206
};

templates/cli/lib/type-generation/languages/java.js.twig

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -61,63 +61,63 @@ public class <%- toPascalCase(collection.name) %> {
6161
<% for (const attribute of collection.attributes) { -%>
6262
<% if (attribute.format === 'enum') { -%>
6363

64-
public enum <%- toPascalCase(attribute.key) %> {
64+
public enum <%- toPascalCase(attribute.key) %> {
6565
<% for (const [index, element] of Object.entries(attribute.elements)) { -%>
66-
<%- toSnakeCase(element) %><%- index < attribute.elements.length - 1 ? ',' : ';' %>
66+
<%- strict ? toSnakeCase(element) : element %><%- index < attribute.elements.length - 1 ? ',' : ';' %>
6767
<% } -%>
68-
}
68+
}
6969

7070
<% } -%>
7171
<% } -%>
7272
<% for (const attribute of collection.attributes) { -%>
73-
private <%- getType(attribute) %> <%- toCamelCase(attribute.key) %>;
73+
private <%- getType(attribute) %> <%- strict ? toCamelCase(attribute.key) : attribute.key %>;
7474
<% } -%>
7575

76-
public <%- toPascalCase(collection.name) %>() {
77-
}
76+
public <%- toPascalCase(collection.name) %>() {
77+
}
7878

79-
public <%- toPascalCase(collection.name) %>(
79+
public <%- toPascalCase(collection.name) %>(
8080
<% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
81-
<%- getType(attribute) %> <%= toCamelCase(attribute.key) %><%- index < collection.attributes.length - 1 ? ',' : '' %>
81+
<%- getType(attribute) %> <%= strict ? toCamelCase(attribute.key) : attribute.key %><%- index < collection.attributes.length - 1 ? ',' : '' %>
8282
<% } -%>
83-
) {
83+
) {
8484
<% for (const attribute of collection.attributes) { -%>
85-
this.<%= toCamelCase(attribute.key) %> = <%= toCamelCase(attribute.key) %>;
85+
this.<%= strict ? toCamelCase(attribute.key) : attribute.key %> = <%= strict ? toCamelCase(attribute.key) : attribute.key %>;
8686
<% } -%>
87-
}
87+
}
8888

8989
<% for (const attribute of collection.attributes) { -%>
90-
public <%- getType(attribute) %> get<%- toPascalCase(attribute.key) %>() {
91-
return <%= toCamelCase(attribute.key) %>;
92-
}
90+
public <%- getType(attribute) %> get<%- toPascalCase(attribute.key) %>() {
91+
return <%= strict ? toCamelCase(attribute.key) : attribute.key %>;
92+
}
9393

94-
public void set<%- toPascalCase(attribute.key) %>(<%- getType(attribute) %> <%= toCamelCase(attribute.key) %>) {
95-
this.<%= toCamelCase(attribute.key) %> = <%= toCamelCase(attribute.key) %>;
96-
}
94+
public void set<%- toPascalCase(attribute.key) %>(<%- getType(attribute) %> <%= strict ? toCamelCase(attribute.key) : attribute.key %>) {
95+
this.<%= strict ? toCamelCase(attribute.key) : attribute.key %> = <%= strict ? toCamelCase(attribute.key) : attribute.key %>;
96+
}
9797

9898
<% } -%>
99-
@Override
100-
public boolean equals(Object obj) {
101-
if (this == obj) return true;
102-
if (obj == null || getClass() != obj.getClass()) return false;
103-
<%- toPascalCase(collection.name) %> that = (<%- toPascalCase(collection.name) %>) obj;
104-
return <% collection.attributes.forEach((attr, index) => { %>Objects.equals(<%= toCamelCase(attr.key) %>, that.<%= toCamelCase(attr.key) %>)<% if (index < collection.attributes.length - 1) { %> &&
105-
<% } }); %>;
106-
}
99+
@Override
100+
public boolean equals(Object obj) {
101+
if (this == obj) return true;
102+
if (obj == null || getClass() != obj.getClass()) return false;
103+
<%- toPascalCase(collection.name) %> that = (<%- toPascalCase(collection.name) %>) obj;
104+
return <% collection.attributes.forEach((attr, index) => { %>Objects.equals(<%= toCamelCase(attr.key) %>, that.<%= toCamelCase(attr.key) %>)<% if (index < collection.attributes.length - 1) { %> &&
105+
<% } }); %>;
106+
}
107107

108-
@Override
109-
public int hashCode() {
110-
return Objects.hash(<%= collection.attributes.map(attr => toCamelCase(attr.key)).join(', ') %>);
111-
}
108+
@Override
109+
public int hashCode() {
110+
return Objects.hash(<%= collection.attributes.map(attr => toCamelCase(attr.key)).join(', ') %>);
111+
}
112112

113-
@Override
114-
public String toString() {
115-
return "<%- toPascalCase(collection.name) %>{" +
116-
<% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
117-
"<%= toCamelCase(attribute.key) %>=" + <%= toCamelCase(attribute.key) %> +
113+
@Override
114+
public String toString() {
115+
return "<%- toPascalCase(collection.name) %>{" +
116+
<% for (const attribute of collection.attributes) { -%>
117+
"<%= strict ? toCamelCase(attribute.key) : attribute.key %>=" + <%= strict ? toCamelCase(attribute.key) : attribute.key %> +
118118
<% } -%>
119-
'}';
120-
}
119+
'}';
120+
}
121121
}
122122
`;
123123
}

templates/cli/lib/type-generation/languages/javascript.js.twig

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class JavaScript extends LanguageMeta {
1616
case AttributeType.URL:
1717
type = "string";
1818
if (attribute.format === AttributeType.ENUM) {
19-
type = `"${attribute.elements.join('"|"')}"`;
19+
type = LanguageMeta.toPascalCase(attribute.key);
2020
}
2121
break;
2222
case AttributeType.INTEGER:
@@ -31,7 +31,7 @@ class JavaScript extends LanguageMeta {
3131
case AttributeType.RELATIONSHIP:
3232
type = LanguageMeta.toPascalCase(attribute.relatedCollection);
3333
if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') {
34-
type = `Array<${type}>`;
34+
type = `${type}[]`;
3535
}
3636
break;
3737
default:
@@ -65,21 +65,32 @@ class JavaScript extends LanguageMeta {
6565
}
6666

6767
getTemplate() {
68-
return `/**
68+
return `
69+
// This file is auto-generated by the Appwrite CLI.
70+
// You can regenerate it by running \`appwrite types -l js ${this.getCurrentDirectory()}\`.
71+
72+
/**
6973
* @typedef {import('${this._getAppwriteDependency()}').Models.Document} Document
7074
*/
7175

76+
<% for (const collection of collections) { -%>
77+
<% for (const attribute of collection.attributes) { -%>
78+
<% if (attribute.format === 'enum') { -%>
7279
/**
73-
* This file is auto-generated by the Appwrite CLI.
74-
* You can regenerate it by running \`appwrite types -l js ${this.getCurrentDirectory()}\`.
80+
* @typedef {"<%- attribute.elements.join('"|"') %>"} <%- toPascalCase(attribute.key) %>
7581
*/
76-
<% for (const collection of collections) { %>
77-
/**
78-
* @typedef {Object} <%- toPascalCase(collection.name) %>
82+
83+
<% } -%>
84+
<% } -%>
85+
<% } -%>
86+
<% for (const collection of collections) { %>/**
87+
* @typedef {Document & {
7988
<% for (const attribute of collection.attributes) { -%>
80-
* @property {<%- getType(attribute) %>} <%- toCamelCase(attribute.key) %>
89+
* <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- getType(attribute) %>;
8190
<% } -%>
91+
* }} <%- toPascalCase(collection.name) %>
8292
*/
93+
8394
<% } %>`;
8495
}
8596

templates/cli/lib/type-generation/languages/kotlin.js.twig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,15 @@ import <%- toPascalCase(attribute.relatedCollection) %>
6363
<% if (attribute.format === 'enum') { -%>
6464
enum class <%- toPascalCase(attribute.key) %> {
6565
<% for (const [index, element] of Object.entries(attribute.elements)) { -%>
66-
<%- toUpperSnakeCase(element) %><%- index < attribute.elements.length - 1 ? ',' : '' %>
66+
<%- strict ? toUpperSnakeCase(element) : element %><%- index < attribute.elements.length - 1 ? ',' : '' %>
6767
<% } -%>
6868
}
6969

7070
<% } -%>
7171
<% } -%>
7272
data class <%- toPascalCase(collection.name) %>(
7373
<% for (const [index, attribute] of Object.entries(collection.attributes)) { -%>
74-
val <%- toCamelCase(attribute.key) %>: <%- getType(attribute) %><% if (index < collection.attributes.length - 1) { %>,<% } %>
74+
val <%- strict ? toCamelCase(attribute.key) : attribute.key %>: <%- getType(attribute) %><% if (index < collection.attributes.length - 1) { %>,<% } %>
7575
<% } -%>
7676
)`;
7777
}

0 commit comments

Comments
 (0)