From f4832549265550add3c08b43ff26df8e3f3d2b29 Mon Sep 17 00:00:00 2001 From: Fellmonkey <90258055+Fellmonkey@users.noreply.github.com> Date: Mon, 15 Sep 2025 12:09:07 +0300 Subject: [PATCH 1/3] more --- .../type-generation/languages/dart.js.twig | 89 +++++++++---------- 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/templates/cli/lib/type-generation/languages/dart.js.twig b/templates/cli/lib/type-generation/languages/dart.js.twig index 5161a18f1..803418ab9 100644 --- a/templates/cli/lib/type-generation/languages/dart.js.twig +++ b/templates/cli/lib/type-generation/languages/dart.js.twig @@ -83,104 +83,101 @@ class Dart extends LanguageMeta { } getTemplate() { - return `<% for (const attribute of collection.attributes) { -%> -<% if (attribute.type === 'relationship') { -%> -import '<%- toSnakeCase(collections.find(c => c.$id === attribute.relatedCollection).name) %>.dart'; - -<% } -%> -<% } -%> -/// This file is auto-generated by the Appwrite CLI. -/// You can regenerate it by running \`appwrite ${process.argv.slice(2).join(' ')}\`. - -<% for (const attribute of collection.attributes) { -%> + return `// This file is auto-generated by the Appwrite CLI. +// You can regenerate it by running \`appwrite ${process.argv.slice(2).join(' ')}\`. +<% const __relatedImportsSeen = new Set(); + const sortedAttributes = collection.attributes.slice().sort((a, b) => { + if (a.required === b.required) return 0; + return a.required ? -1 : 1; + }); -%> +<% const __attrs = strict ? sortedAttributes : collection.attributes; -%> +<% for (const attribute of __attrs) { -%> +<% if (attribute.type === 'relationship') { -%> +<% const related = collections.find(c => c.$id === attribute.relatedCollection); -%> +<% if (related && !__relatedImportsSeen.has(toSnakeCase(related.name))) { -%> +import '<%- toSnakeCase(related.name) %>.dart'; +<% __relatedImportsSeen.add(toSnakeCase(related.name)); -%> +<% } -%> +<% } -%> +<% } -%> + +<% for (const attribute of __attrs) { -%> <% if (attribute.format === 'enum') { -%> enum <%- toPascalCase(attribute.key) %> { <% for (const [index, element] of Object.entries(attribute.elements)) { -%> - <%- strict ? toCamelCase(element) : element %><% if (index < attribute.elements.length - 1) { %>,<% } %> + <%- strict ? toCamelCase(element) : element %><% if (index < attribute.elements.length - 1) { -%>,<% } %> <% } -%> } <% } -%> <% } -%> class <%= toPascalCase(collection.name) %> { -<% for (const [index, attribute] of Object.entries(collection.attributes)) { -%> +<% for (const [index, attribute] of Object.entries(__attrs)) { -%> <%- getType(attribute, collections) %> <%= strict ? toCamelCase(attribute.key) : attribute.key %>; <% } -%> <%= toPascalCase(collection.name) %>({ - <% for (const [index, attribute] of Object.entries(collection.attributes)) { -%> - <% if (attribute.required) { %>required <% } %>this.<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (index < collection.attributes.length - 1) { %>,<% } %> + <% for (const [index, attribute] of Object.entries(__attrs)) { -%> + <% if (attribute.required) { %>required <% } %>this.<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (index < __attrs.length - 1) { -%>,<% } %> <% } -%> }); factory <%= toPascalCase(collection.name) %>.fromMap(Map map) { return <%= toPascalCase(collection.name) %>( -<% for (const [index, attribute] of Object.entries(collection.attributes)) { -%> +<% for (const [index, attribute] of Object.entries(__attrs)) { -%> <%= strict ? toCamelCase(attribute.key) : attribute.key %>: <% if (attribute.type === 'string' || attribute.type === 'email' || attribute.type === 'datetime') { -%> <% if (attribute.format === 'enum') { -%> <% if (attribute.array) { -%> -(map['<%= attribute.key %>'] as List?)?.map((e) => <%- toPascalCase(attribute.key) %>.values.firstWhere((element) => element.name == e)).toList()<% if (!attribute.required) { %> ?? []<% } -%> -<% } else { -%> +(map['<%= attribute.key %>'] as List?)?.map((e) => <%- toPascalCase(attribute.key) %>.values.firstWhere((element) => element.name == e)).toList()<% } else { -%> <% if (!attribute.required) { -%> map['<%= attribute.key %>'] != null ? <%- toPascalCase(attribute.key) %>.values.where((e) => e.name == map['<%= attribute.key %>']).firstOrNull : null<% } else { -%> <%- toPascalCase(attribute.key) %>.values.firstWhere((e) => e.name == map['<%= attribute.key %>'])<% } -%> <% } -%> <% } else { -%> <% if (attribute.array) { -%> -List.from(map['<%= attribute.key %>'] ?? [])<% if (!attribute.required) { %> ?? []<% } -%> -<% } else { -%> -map['<%= attribute.key %>']<% if (!attribute.required) { %>?<% } %>.toString()<% if (!attribute.required) { %> ?? null<% } -%> -<% } -%> +List.from(map['<%= attribute.key %>'] ?? [])<% } else { -%> +map['<%= attribute.key %>']<% if (!attribute.required) { %>?<% } %>.toString()<% } -%> <% } -%> <% } else if (attribute.type === 'integer') { -%> <% if (attribute.array) { -%> -List.from(map['<%= attribute.key %>'] ?? [])<% if (!attribute.required) { %> ?? []<% } -%> -<% } else { -%> -map['<%= attribute.key %>']<% if (!attribute.required) { %> ?? null<% } -%> -<% } -%> -<% } else if (attribute.type === 'float') { -%> +List.from(map['<%= attribute.key %>'] ?? [])<% } else { -%> +map['<%= attribute.key %>']<% } -%> +<% } else if (attribute.type === 'double') { -%> <% if (attribute.array) { -%> -List.from(map['<%= attribute.key %>'] ?? [])<% if (!attribute.required) { %> ?? []<% } -%> -<% } else { -%> -map['<%= attribute.key %>']<% if (!attribute.required) { %> ?? null<% } -%> -<% } -%> +List.from(map['<%= attribute.key %>'] ?? [])<% } else { -%> +map['<%= attribute.key %>']<% } -%> <% } else if (attribute.type === 'boolean') { -%> <% if (attribute.array) { -%> -List.from(map['<%= attribute.key %>'] ?? [])<% if (!attribute.required) { %> ?? []<% } -%> -<% } else { -%> -map['<%= attribute.key %>']<% if (!attribute.required) { %> ?? null<% } -%> -<% } -%> +List.from(map['<%= attribute.key %>'] ?? [])<% } else { -%> +map['<%= attribute.key %>']<% } -%> <% } else if (attribute.type === 'relationship') { -%> <% if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') { -%> -(map['<%= attribute.key %>'] as List?)?.map((e) => <%- toPascalCase(collections.find(c => c.$id === attribute.relatedCollection).name) %>.fromMap(e)).toList()<% if (!attribute.required) { %> ?? []<% } -%> +(map['<%= attribute.key %>'] as List?)?.map((e) => <%- toPascalCase(collections.find(c => c.$id === attribute.relatedCollection).name) %>.fromMap(e)).toList() <% } else { -%> <% if (!attribute.required) { -%> map['<%= attribute.key %>'] != null ? <%- toPascalCase(collections.find(c => c.$id === attribute.relatedCollection).name) %>.fromMap(map['<%= attribute.key %>']) : null<% } else { -%> <%- toPascalCase(collections.find(c => c.$id === attribute.relatedCollection).name) %>.fromMap(map['<%= attribute.key %>'])<% } -%> <% } -%> -<% } -%><% if (index < collection.attributes.length - 1) { %>,<% } %> +<% } -%><% if (index < __attrs.length - 1) { -%>,<% } %> <% } -%> ); } Map toMap() { return { -<% for (const [index, attribute] of Object.entries(collection.attributes)) { -%> - "<%= attribute.key %>": <% if (attribute.type === 'relationship') { -%> +<% for (const [index, attribute] of Object.entries(__attrs)) { -%> + '<%= attribute.key %>': <% if (attribute.type === 'relationship') { -%> <% if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') { -%> -<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.map((e) => e.toMap()).toList()<% if (!attribute.required) { %> ?? []<% } -%> +<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.map((e) => e.toMap()).toList() <% } else { -%> -<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.toMap()<% if (!attribute.required) { %> ?? {}<% } -%> -<% } -%> +<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.toMap()<% } -%> <% } else if (attribute.format === 'enum') { -%> <% if (attribute.array) { -%> -<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.map((e) => e.name).toList()<% if (!attribute.required) { %> ?? []<% } -%> -<% } else { -%> -<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.name<% if (!attribute.required) { %> ?? null<% } -%> -<% } -%> +<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.map((e) => e.name).toList()<% } else { -%> +<%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.name<% } -%> <% } else { -%> <%= strict ? toCamelCase(attribute.key) : attribute.key -%> -<% } -%><% if (index < collection.attributes.length - 1) { %>,<% } %> +<% } -%><% if (index < __attrs.length - 1) { -%>,<% } %> <% } -%> }; } From 888a7c68ccdcae57d074e741b7d22734b8d97a04 Mon Sep 17 00:00:00 2001 From: Fellmonkey <90258055+Fellmonkey@users.noreply.github.com> Date: Thu, 18 Sep 2025 17:28:54 +0300 Subject: [PATCH 2/3] Refactor Dart template to use AttributeType constants --- .../type-generation/languages/dart.js.twig | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/templates/cli/lib/type-generation/languages/dart.js.twig b/templates/cli/lib/type-generation/languages/dart.js.twig index 803418ab9..5e367acc4 100644 --- a/templates/cli/lib/type-generation/languages/dart.js.twig +++ b/templates/cli/lib/type-generation/languages/dart.js.twig @@ -92,7 +92,7 @@ class Dart extends LanguageMeta { }); -%> <% const __attrs = strict ? sortedAttributes : collection.attributes; -%> <% for (const attribute of __attrs) { -%> -<% if (attribute.type === 'relationship') { -%> +<% if (attribute.type === '${AttributeType.RELATIONSHIP}') { -%> <% const related = collections.find(c => c.$id === attribute.relatedCollection); -%> <% if (related && !__relatedImportsSeen.has(toSnakeCase(related.name))) { -%> import '<%- toSnakeCase(related.name) %>.dart'; @@ -102,7 +102,7 @@ import '<%- toSnakeCase(related.name) %>.dart'; <% } -%> <% for (const attribute of __attrs) { -%> -<% if (attribute.format === 'enum') { -%> +<% if (attribute.format === '${AttributeType.ENUM}') { -%> enum <%- toPascalCase(attribute.key) %> { <% for (const [index, element] of Object.entries(attribute.elements)) { -%> <%- strict ? toCamelCase(element) : element %><% if (index < attribute.elements.length - 1) { -%>,<% } %> @@ -125,8 +125,8 @@ class <%= toPascalCase(collection.name) %> { factory <%= toPascalCase(collection.name) %>.fromMap(Map map) { return <%= toPascalCase(collection.name) %>( <% for (const [index, attribute] of Object.entries(__attrs)) { -%> - <%= strict ? toCamelCase(attribute.key) : attribute.key %>: <% if (attribute.type === 'string' || attribute.type === 'email' || attribute.type === 'datetime') { -%> -<% if (attribute.format === 'enum') { -%> + <%= strict ? toCamelCase(attribute.key) : attribute.key %>: <% if (attribute.type === '${AttributeType.STRING}' || attribute.type === '${AttributeType.EMAIL}' || attribute.type === '${AttributeType.DATETIME}') { -%> +<% if (attribute.format === '${AttributeType.ENUM}') { -%> <% if (attribute.array) { -%> (map['<%= attribute.key %>'] as List?)?.map((e) => <%- toPascalCase(attribute.key) %>.values.firstWhere((element) => element.name == e)).toList()<% } else { -%> <% if (!attribute.required) { -%> @@ -138,19 +138,19 @@ map['<%= attribute.key %>'] != null ? <%- toPascalCase(attribute.key) %>.values. List.from(map['<%= attribute.key %>'] ?? [])<% } else { -%> map['<%= attribute.key %>']<% if (!attribute.required) { %>?<% } %>.toString()<% } -%> <% } -%> -<% } else if (attribute.type === 'integer') { -%> +<% } else if (attribute.type === '${AttributeType.INTEGER}') { -%> <% if (attribute.array) { -%> List.from(map['<%= attribute.key %>'] ?? [])<% } else { -%> map['<%= attribute.key %>']<% } -%> -<% } else if (attribute.type === 'double') { -%> +<% } else if (attribute.type === '${AttributeType.FLOAT}') { -%> <% if (attribute.array) { -%> List.from(map['<%= attribute.key %>'] ?? [])<% } else { -%> map['<%= attribute.key %>']<% } -%> -<% } else if (attribute.type === 'boolean') { -%> +<% } else if (attribute.type === '${AttributeType.BOOLEAN}') { -%> <% if (attribute.array) { -%> List.from(map['<%= attribute.key %>'] ?? [])<% } else { -%> map['<%= attribute.key %>']<% } -%> -<% } else if (attribute.type === 'relationship') { -%> +<% } else if (attribute.type === '${AttributeType.RELATIONSHIP}') { -%> <% if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') { -%> (map['<%= attribute.key %>'] as List?)?.map((e) => <%- toPascalCase(collections.find(c => c.$id === attribute.relatedCollection).name) %>.fromMap(e)).toList() <% } else { -%> @@ -166,12 +166,12 @@ map['<%= attribute.key %>'] != null ? <%- toPascalCase(collections.find(c => c.$ Map toMap() { return { <% for (const [index, attribute] of Object.entries(__attrs)) { -%> - '<%= attribute.key %>': <% if (attribute.type === 'relationship') { -%> + '<%= attribute.key %>': <% if (attribute.type === '${AttributeType.RELATIONSHIP}') { -%> <% if ((attribute.relationType === 'oneToMany' && attribute.side === 'parent') || (attribute.relationType === 'manyToOne' && attribute.side === 'child') || attribute.relationType === 'manyToMany') { -%> <%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.map((e) => e.toMap()).toList() <% } else { -%> <%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.toMap()<% } -%> -<% } else if (attribute.format === 'enum') { -%> +<% } else if (attribute.format === '${AttributeType.ENUM}') { -%> <% if (attribute.array) { -%> <%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.map((e) => e.name).toList()<% } else { -%> <%= strict ? toCamelCase(attribute.key) : attribute.key %><% if (!attribute.required) { %>?<% } %>.name<% } -%> From 89bb1858fae9c855df4d561350b9233e75abd6cc Mon Sep 17 00:00:00 2001 From: Fellmonkey <90258055+Fellmonkey@users.noreply.github.com> Date: Thu, 18 Sep 2025 17:33:25 +0300 Subject: [PATCH 3/3] Always use sortedAttributes in Dart type generation --- templates/cli/lib/type-generation/languages/dart.js.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/cli/lib/type-generation/languages/dart.js.twig b/templates/cli/lib/type-generation/languages/dart.js.twig index 5e367acc4..73ea972a4 100644 --- a/templates/cli/lib/type-generation/languages/dart.js.twig +++ b/templates/cli/lib/type-generation/languages/dart.js.twig @@ -90,7 +90,7 @@ class Dart extends LanguageMeta { if (a.required === b.required) return 0; return a.required ? -1 : 1; }); -%> -<% const __attrs = strict ? sortedAttributes : collection.attributes; -%> +<% const __attrs = sortedAttributes; -%> <% for (const attribute of __attrs) { -%> <% if (attribute.type === '${AttributeType.RELATIONSHIP}') { -%> <% const related = collections.find(c => c.$id === attribute.relatedCollection); -%>