Skip to content
This repository was archived by the owner on Apr 20, 2024. It is now read-only.

Commit 1a74c7b

Browse files
Merge pull request #18 from nodes-vapor/feature/forms
Add Forms support
2 parents f7d470a + 9c7bd3d commit 1a74c7b

2 files changed

Lines changed: 121 additions & 2 deletions

File tree

Forms/Forms.stencil

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{# One file per Form #}
2+
3+
{% for type in types.based.Form|!protocol|annotated:"form" %}
4+
// sourcery:file:Forms/{{ type.localName }}/{{ type.localName }}+Form.generated.swift
5+
import Forms
6+
7+
extension {{ type.localName }} {
8+
{{ type.accessLevel }} var fields: [FieldType] {
9+
return [
10+
{% for variable in type.variables where variable.typeName|hasPrefix:"FormField<" and variable|!annotated:"ignoreField" %}
11+
{{ variable.name }}{% if not forloop.last %},{% endif %}
12+
{% endfor %}
13+
]
14+
}
15+
}
16+
17+
extension {{ type.localName }} {
18+
{% for variable in type.variables where variable.typeName|hasPrefix:"FormField<" and variable|!annotated:"ignoreField" %}
19+
{{ type.accessLevel }} var {{ variable.name|replace:"Field",""}}: {{variable.typeName.name|replace:"FormField<",""|replace:">",""}}? {
20+
return {{ variable.name }}.value
21+
}
22+
{% endfor %}
23+
}
24+
25+
{% if type|!annotated:"ignoreAssertValues" %}
26+
extension {{ type.localName }} {
27+
{{ type.accessLevel }} func assertValues(errorOnNil: Error = Abort(.internalServerError)) throws -> (
28+
{% for variable in type.variables where variable.typeName|hasPrefix:"FormField<" and variable|!annotated:"ignoreAssertValues" and variable|!annotated:"ignoreField" %}
29+
{%if not forloop.last or not forloop.first %}{{ variable.name|replace:"Field",""}}: {% endif %}{{variable.typeName.name|replace:"FormField<",""|replace:">",""}}{% if not forloop.last %},{% endif %}
30+
{% endfor %}
31+
) {
32+
guard
33+
{% for variable in type.variables where variable.typeName|hasPrefix:"FormField<" and variable|!annotated:"ignoreAssertValues" and variable|!annotated:"ignoreField" %}
34+
let {{ variable.name|replace:"Field",""}} = {{ variable.name|replace:"Field",""}}{% if not forloop.last %},{% endif %}
35+
{% endfor %}
36+
else {
37+
throw errorOnNil
38+
}
39+
40+
return (
41+
{% for variable in type.variables where variable.typeName|hasPrefix:"FormField<" and variable|!annotated:"ignoreAssertValues" and variable|!annotated:"ignoreField" %}
42+
{{ variable.name|replace:"Field",""}}{% if not forloop.last %},{% endif %}
43+
{% endfor %}
44+
)
45+
}
46+
}
47+
48+
{% endif %}
49+
// sourcery:end
50+
{% endfor %}

README.md

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,14 @@ final class User: Model {
4646
- [Controllers](#controllers)
4747
- [RouteCollection](#routecollection)
4848
- [Annotations](#annotations-4)
49+
- [Forms](#forms)
50+
- [Annotations](#annotations-5)
4951
- [Tests](#tests)
5052
- [LinuxMain](#linuxmain)
51-
- [Annotations](#annotations-5)
53+
- [Annotations](#annotations-6)
5254
- [General](#general)
5355
- [Enums](#enums)
54-
- [Annotations](#annotations-6)
56+
- [Annotations](#annotations-7)
5557
- [Configuration](#configuration)
5658
- [Options](#options)
5759
- [Credits](#credits)
@@ -367,6 +369,73 @@ extension UserController: RouteCollection {
367369
| `method` | The method of the route. |
368370
| `path` | The path for the route. |
369371

372+
## Forms
373+
374+
This template makes working with [Forms](https://github.com/nodes-vapor/forms) more convenient by annotating them with "form".
375+
376+
| Note: Make sure to postfix your field properties with "Field" so that the generated value accessors don't conflict with the field names.
377+
378+
Example:
379+
380+
```swift
381+
// sourcery: form
382+
struct UserForm: Form {
383+
let nameField: FormField<String>
384+
let ageField: FormField<Int>
385+
386+
...
387+
}
388+
```
389+
390+
Becomes:
391+
392+
```swift
393+
extension UserForm {
394+
var fields: [FieldType] {
395+
return [
396+
nameField,
397+
ageField
398+
]
399+
}
400+
}
401+
402+
extension UserForm {
403+
var name: String? {
404+
return nameField.value
405+
}
406+
var age: Int? {
407+
return ageField.value
408+
}
409+
}
410+
411+
extension UserForm {
412+
internal func assertValues(errorOnNil: Error = Abort(.internalServerError)) throws -> (
413+
name: String,
414+
age: Int
415+
) {
416+
guard
417+
let name = name,
418+
let age = age
419+
else {
420+
throw errorOnNil
421+
}
422+
423+
return (
424+
name,
425+
age
426+
)
427+
}
428+
}
429+
```
430+
431+
### Annotations
432+
433+
| Key | Description |
434+
| --- | --- |
435+
| `form` | Opt-in a type conforming to `Form` to use this template. |
436+
| `ignoreField` | Opt-out a specific field from all extensions |
437+
| `ignoreAssertValues` | Opt-out a specific field from being included in the `assertValues` function. |
438+
370439
## Tests
371440
These templates are related to unit testing with XCTest.
372441

0 commit comments

Comments
 (0)