Hello \(name)
") + } +} +``` + +```leaf +#hello("John") +``` + +#### Usando i Dati + +Possiamo accedere al valore del nome usando la chiave "name" dentro la proprietà dei dati. + +```swift +enum HelloTagError: Error { + case nameNotFound +} + +struct HelloTag: UnsafeUnescapedLeafTag { + func render(_ ctx: LeafContext) throws -> LeafData { + guard let name = ctx.data["name"]?.string else { + throw HelloTagError.nameNotFound + } + + return LeafData.string("Hello \(name)
") + } +} +``` + +```leaf +#hello() +``` + +_Controller_: + +```swift +return try await req.view.render("home", ["name": "John"]) +``` diff --git a/docs/leaf/getting-started.it.md b/docs/leaf/getting-started.it.md new file mode 100644 index 00000000..799c044d --- /dev/null +++ b/docs/leaf/getting-started.it.md @@ -0,0 +1,96 @@ +# Leaf + +Leaf è un potente linguaggio di templating con la sintassi ispirata a Swift. Puoi usarlo per generare pagine HTML dinamiche per un sito front-end o per generare email abbellite da inviare con una API. + +## Pacchetto + +Il primo passo per usare Leaf è aggiungerlo come una dipendenza al tuo progetto nel tuo file di manifesto del pacchetto SPM. + +```swift +// swift-tools-version:5.2 +import PackageDescription + +let package = Package( + name: "MyApp", + platforms: [ + .macOS(.v10_15) + ], + dependencies: [ + /// Qualsiasi altra dipendenza ... + .package(url: "https://github.com/vapor/leaf.git", from: "4.0.0"), + ], + targets: [ + .target(name: "App", dependencies: [ + .product(name: "Leaf", package: "leaf"), + // Qualsiasi altra dipendenza + ]), + // Altri target + ] +) +``` + +## Configura + +Non appena hai aggiunto il pacchetto al tuo progetto, puoi configurare Vapor per usarlo. Di solito si fa in [`configure.swift`](../getting-started/folder-structure.md#configureswift). + +```swift +import Leaf + +app.views.use(.leaf) +``` + +Questo dice a Vapor di usare `LeafRenderer` quando chiami `req.view` nel tuo codice. + +!!! note + Leaf ha una cache interna per renderizzare le pagine. Quando l'ambiente di `Application` è impostato su `.development` questa cache è disabilitata, così che i cambiamenti ai template abbiano effetto immediatamente. In `.production` e tutti gli altri ambienti la cache è abilitata di default; qualsiasi cambiamento fatto ai template non avrà effetto finché l'applicazione non viene riavviata. + +!!! warning + Per fare in modo che Leaf trovi i template quando gira su Xcode, devi impostare la [directory di lavoro personalizzata](../getting-started/xcode.md#custom-working-directory) per il tuo ambiente di lavoro Xcode. +## Struttura della Cartella + +Non appena hai configurato Leaf, devi assicurarti di avere una cartella `Views` dove salvare i tuoi file `.leaf`. Di default, Leaf si aspetta che la cartella delle view sia `./Resources/Views`, relativamente alla radice del tuo progetto. + +Probabilmente vorrai abilitare anche il [`FileMiddleware`](https://api.vapor.codes/vapor/documentation/vapor/filemiddleware) di Vapor per servire file dalla tua cartella `/Public` se hai in mente di servire file Javascript e CSS per esempio. + +``` +VaporApp +├── Package.swift +├── Resources +│ ├── Views +│ │ └── hello.leaf +├── Public +│ ├── images (immagini) +│ ├── styles (risorse css) +└── Sources + └── ... +``` + +## Renderizzare una View + +Adesso che Leaf è configurato, renderizziamo il tuo primo template. Dentro la cartella `Resources/Views`, crea un nuovo file chiamato `hello.leaf` con il seguente contenuto: + +```leaf +Hello, #(name)! +``` + +!!! tip + Se usi VSCode come editor di testo, raccomandiamo di installare l'estensione Leaf per abilitare l'evidenziazione della sintassi: [Leaf HTML](https://marketplace.visualstudio.com/items?itemName=Francisco.html-leaf). + +Quindi, registra una route (di solito fatto in `routes.swift` o un controller) per renderizzare la view. + +```swift +app.get("hello") { req -> EventLoopFuture#(number)
+#endfor +``` + +## Utilizzo + +Ecco alcuni esempi di utilizzo comune di Leaf. + +### Condizioni + +Leaf è capace di valutare una serie di condizioni usando il suo tag `#if`. Per esempio, se gli fornisci una variabile controllerà che la variabile esista nel suo contesto: + +```leaf +#if(title): + The title is #(title) +#else: + No title was provided. +#endif +``` + +Puoi anche utilizzare confronti, per esempio: + +```leaf +#if(title == "Welcome"): + This is a friendly web page. +#else: + No strangers allowed! +#endif +``` + +Se vuoi usare un altro tag come parte della tua condizione, dovresti omettere il `#` per il tag interno. Per esempio: + +```leaf +#if(count(users) > 0): + You have users! +#else: + There are no users yet :( +#endif +``` + +Puoi usare anche dichiarazioni `#elseif`: + +```leaf +#if(title == "Welcome"): + Hello new user! +#elseif(title == "Welcome back!"): + Hello old user +#else: + Unexpected page! +#endif +``` + +### Cicli + +Se fornisci un array di oggetti, Leaf può iterare su di essi e permetterti di manipolare ciascun oggetto individualmente usando il suo tag `#for`. + +Per esempio, possiamo aggiornare il nostro codice Swift per fornire una lista di pianeti: + +```swift +struct SolarSystem: Codable { + let planets = ["Venus", "Earth", "Mars"] +} + +return req.view.render("solarSystem", SolarSystem()) +``` + +In Leaf, possiamo iterare su di essi così: + +```leaf +Planets: +Welcome to Vapor!
+ #endexport +#endextend +``` + +Chiamiamo `#export` per salvare dell'HTML e renderlo disponibile al template che stiamo estendendo al momento. Poi renderizziamo `master.leaf` e usiamo i dati esportati quando richiesto insieme a qualsiasi altra variabile di contesto passata da Swift. Per esempio, `master.leaf` potrebbe essere così: + +```leaf + + +Welcome to Vapor!
+ +``` + +### Altri tag + +#### `#count` + +Il tag `#count` ritorna il numero di oggetti in un array. Per esempio: + +```leaf +Your search matched #count(matches) pages. +``` + +#### `#lowercased` + +Il tag `#lowercased` mette in minuscolo tutte le lettere in una stringa. + +```leaf +#lowercased(name) +``` + +#### `#uppercased` + +Il tag `#uppercased` mette in maiuscolo tutte le lettere in una stringa. + +```leaf +#uppercased(name) +``` + +#### `#capitalized` + +Il tag `#capitalized` mette in maiuscolo la prima lettera in ogni parola di una stringa e mette in minuscolo le altre. Guarda [`String.capitalized`](https://developer.apple.com/documentation/foundation/nsstring/1416784-capitalized) per più informazioni. + +```leaf +#capitalized(name) +``` + +#### `#contains` + +Il tag `#contains` accetta un array e un valore come parametri, e ritorna true se l'array nel primo parametro contiene il valore nel secondo parametro. + +```leaf +#if(contains(planets, "Earth")): + Earth is here! +#else: + Earth is not in this array. +#endif +``` + +#### `#date` + +Il tag `#date` formatta le date in una stringa leggibile. Di default usa il formato ISO8601. + +```swift +render(..., ["now": Date()]) +``` + +```leaf +The time is #date(now) +``` + +Puoi passare una stringa in un formato di data personalizzato come secondo argomento. Guarda il [`DateFormatter`](https://developer.apple.com/documentation/foundation/dateformatter) di Swift per più informazioni. + +```leaf +The date is #date(now, "yyyy-MM-dd") +``` + +#### `#unsafeHTML` + +Il tag `#unsafeHTML` agisce come un tag di variabile - p.es. `#(variable)`. Però non evade nessun HTML che `variable` potrebbe contenere: + +```leaf +The time is #unsafeHTML(styledTitle) +``` + +!!! note + Dovresti fare attenzione quando usi questo tag per assicurarti che la variabile che gli fornisci non esponga i tuoi utenti a un attacco XSS. + +#### `#dumpContext` + +Il tag `#dumpContext` renderizza l'intero contesto in una stringa leggibile. Usa questo tag per debuggare cosa viene fornito come contesto al rendering corrente. + +```leaf +Hello, world! +#dumpContext +``` \ No newline at end of file diff --git a/docs/leaf/overview.md b/docs/leaf/overview.md index 5b582e95..b1035189 100644 --- a/docs/leaf/overview.md +++ b/docs/leaf/overview.md @@ -14,7 +14,7 @@ There are #count(users) users. Leaf tags are made up of four elements: -- Token `#`: This signals the leaf parser to begin looking for a tag. +- Token `#`: This signals the Leaf parser to begin looking for a tag. - Name `count`: that identifies the tag. - Parameter List `(users)`: May accept zero or more arguments. - Body: An optional body can be supplied to some tags using a colon and a closing tag diff --git a/mkdocs.yml b/mkdocs.yml index 0120683a..7aaa0285 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -274,6 +274,7 @@ plugins: Content: Contenuto Contributing: Contribuire Contributing Guide: Guida alla Contribuzione + Controllers: Controller Crypto: Crittografia Custom Tags: Tag Personalizzati Deploy: Deploy From 3fa1e50c1d5649ca85b6fcda5efebc95bc682faf Mon Sep 17 00:00:00 2001 From: Paul Toffoloni <69189821+ptoffy@users.noreply.github.com> Date: Tue, 3 Oct 2023 09:32:57 +0200 Subject: [PATCH 04/18] Translate authentication to Italian (#919) Co-authored-by: Francesco Paolo Severino <96546612+fpseverino@users.noreply.github.com> --- docs/security/authentication.it.md | 896 +++++++++++++++++++++++++++++ 1 file changed, 896 insertions(+) create mode 100644 docs/security/authentication.it.md diff --git a/docs/security/authentication.it.md b/docs/security/authentication.it.md new file mode 100644 index 00000000..c4a18c86 --- /dev/null +++ b/docs/security/authentication.it.md @@ -0,0 +1,896 @@ +# Autenticazione + +L'autenticazione è la verifica dell'identità di un utente. Ciò può avvenire attraverso la verifica di credenziali come un nome utente e una password o un tramite un token. L'autenticazione (talvolta chiamata auth/c) si distingue dall'autorizzazione (auth/z), che è l'atto di verificare i permessi di un utente precedentemente autenticato per permettergli di eseguire determinate operazioni. + +## Introduzione + +Le API di autenticazione di Vapor supportano l'autenticazione di un utente tramite l'intestazione `Authorization` della richiesta, utilizzando le autorizzazioni [Basic](https://tools.ietf.org/html/rfc7617) e [Bearer](https://tools.ietf.org/html/rfc6750). È supportata anche l'autenticazione di un utente tramite la decodifica dei dati dall'API [Content](../basics/content.md). + +L'autenticazione viene implementata creando un `Authenticator` che contiene la logica di verifica. Un autenticatore può essere utilizzato per proteggere singoli gruppi di route o un'intera applicazione. Vapor fornisce i seguenti autenticatori: + +|Protocollo|Descrizione| +|-|-| +|`RequestAuthenticator`/`AsyncRequestAuthenticator`|Autenticatore di base in grado di creare middleware.| +|[`BasicAuthenticator`/`AsyncBasicAuthenticator`](#basic)|Autenticatore che verifica l'header Basic.| +|[`BearerAuthenticator`/`AsyncBearerAuthenticator`](#bearer)|Autenticatore che verifica l'header Bearer.| +|[`CredentialsAuthenticator`/`AsyncCredentialsAuthenticator`](#credentials)|Autenticatore che verifica le credenziali decodificate dal contenuto della richiesta.| + +Se l'autenticazione ha successo, l'autenticatore aggiunge l'utente verificato a `req.auth`. Si può quindi accedere a questo utente usando `req.auth.get(_:)` nelle route protette dall'autenticatore. Se l'autenticazione fallisce, l'utente non viene aggiunto a `req.auth` e qualsiasi tentativo di accesso fallirà. + +## Authenticatable + +Per utilizzare l'API di autenticazione, ti occorre innanzitutto un tipo di utente conforme ad `Authenticatable`. Questo può essere una `struct`, una `class` o anche un `Model` Fluent. Gli esempi seguenti assumono una semplice struttura `User` che ha una sola proprietà: `name`. + +```swift +import Vapor + +struct User: Authenticatable { + var name: String +} +``` + + +Ogni esempio che segue utilizzerà un'istanza di un autenticatore che abbiamo creato. In questi esempi, lo abbiamo chiamato `UserAuthenticator`. + +### Route + +Gli autenticatori sono middleware e possono essere utilizzati per proteggere le route. + +```swift +let protected = app.grouped(UserAuthenticator()) +protected.get("me") { req -> String in + try req.auth.require(User.self).name +} +``` + +Per recuperare l'utente autenticato, viene usato il metodo `req.auth.require`. Se l'autenticazione fallisce, questo metodo lancia un errore, proteggendo la route. + +### Middleware di Guardia + +Puoi anche usare `GuardMiddleware` nel gruppo di route, per assicurarsi che un utente sia stato autenticato prima di raggiungere il gestore di route. + +```swift +let protected = app.grouped(UserAuthenticator()) + .grouped(User.guardMiddleware()) +``` + +La richiesta di autenticazione non viene effettuata dal middleware dell'autenticatore per consentire la composizione degli autenticatori. Per saperne di più sulla [composizione](#composition) leggi più sotto. + +## Basic + +L'autenticazione di base invia un nome utente e una password nell'intestazione `Authorization`. Il nome utente e la password sono concatenati con i due punti (ad esempio, `test:secret`), codificati in base 64 e preceduti da `"Basic"`. La seguente richiesta di esempio codifica il nome utente `test` con la password `secret`. + +```http +GET /me HTTP/1.1 +Authorization: Basic dGVzdDpzZWNyZXQ= +``` + +In genere, l'autenticazione di base viene utilizzata una sola volta per registrare un utente e generare un token. Questo riduce al minimo la frequenza di invio della password sensibile dell'utente. Non si dovrebbe mai inviare l'autorizzazione di base in chiaro o su una connessione TLS non verificata. + +Per implementare l'autenticazione di base nella tua applicazione, puoi creare un nuovo autenticatore conforme a `BasicAuthenticator`. Di seguito è riportato un esempio di autenticatore codificato per verificare la richiesta di cui sopra. + +```swift +import Vapor + +struct UserAuthenticator: BasicAuthenticator { + typealias User = App.User + + func authenticate( + basic: BasicAuthorization, + for request: Request + ) -> EventLoopFuture
+Except where otherwise noted, Vapor Documentation by Vapor is licensed under CC BY-NC-SA 4.0
+
Sourced from actions/checkout's releases.
v4.0.0
What's Changed
- Update default runtime to node20 by
@takostin actions/checkout#1436- Support fetching without the --progress option by
@simonbairdin actions/checkout#1067- Release 4.0.0 by
@takostin actions/checkout#1447New Contributors
@takostmade their first contribution in actions/checkout#1436@simonbairdmade their first contribution in actions/checkout#1067Full Changelog: https://github.com/actions/checkout/compare/v3...v4.0.0
v3.6.0
What's Changed
- Mark test scripts with Bash'isms to be run via Bash by
@dschoin actions/checkout#1377- Add option to fetch tags even if fetch-depth > 0 by
@RobertWieczoreckin actions/checkout#579- Release 3.6.0 by
@luketomlinsonin actions/checkout#1437New Contributors
@RobertWieczoreckmade their first contribution in actions/checkout#579@luketomlinsonmade their first contribution in actions/checkout#1437Full Changelog: https://github.com/actions/checkout/compare/v3.5.3...v3.6.0
v3.5.3
What's Changed
- Fix: Checkout Issue in self hosted runner due to faulty submodule check-ins by
@megamanicsin actions/checkout#1196- Fix typos found by codespell by
@DimitriPapadopoulosin actions/checkout#1287- Add support for sparse checkouts by
@dschoand@dfdezin actions/checkout#1369- Release v3.5.3 by
@TingluoHuangin actions/checkout#1376New Contributors
@megamanicsmade their first contribution in actions/checkout#1196@DimitriPapadopoulosmade their first contribution in actions/checkout#1287@dfdezmade their first contribution in actions/checkout#1369Full Changelog: https://github.com/actions/checkout/compare/v3...v3.5.3
v3.5.2
What's Changed
- Fix: Use correct API url / endpoint in GHES by
@fhammerlin actions/checkout#1289 based on #1286 by@1newsrFull Changelog: https://github.com/actions/checkout/compare/v3.5.1...v3.5.2
v3.5.1
What's Changed
- Improve checkout performance on Windows runners by upgrading
@actions/githubdependency by@BrettDongin actions/checkout#1246New Contributors
@BrettDongmade their first contribution in actions/checkout#1246
... (truncated)
Sourced from actions/checkout's changelog.
Changelog
v4.1.0
v4.0.0
v3.6.0
- Fix: Mark test scripts with Bash'isms to be run via Bash
- Add option to fetch tags even if fetch-depth > 0
v3.5.3
- Fix: Checkout fail in self-hosted runners when faulty submodule are checked-in
- Fix typos found by codespell
- Add support for sparse checkouts
v3.5.2
v3.5.1
v3.5.0
v3.4.0
v3.3.0
- Implement branch list using callbacks from exec function
- Add in explicit reference to private checkout options
- [Fix comment typos (that got added in #770)](actions/checkout#1057)
v3.2.0
- Add GitHub Action to perform release
- Fix status badge
- Replace datadog/squid with ubuntu/squid Docker image
- Wrap pipeline commands for submoduleForeach in quotes
- Update
@actions/ioto 1.1.2- Upgrading version to 3.2.0
v3.1.0
v3.0.2
... (truncated)
8ade135
Prepare 4.1.0 release (#1496)c533a0a
Add support for partial checkout filters (#1396)72f2cec
Update README.md for V4 (#1452)3df4ab1
Release 4.0.0 (#1447)8b5e8b7
Support fetching without the --progress option (#1067)97a652b
Update default runtime to node20 (#1436)Sourced from aws-actions/configure-aws-credentials's releases.
v4
This tag tracks the latest v4.x.x release
v3.0.2
See the changelog for details about the changes included in this release.
v3.0.1
See the changelog for details about the changes included in this release.
v3.0.0
See the changelog for details about the changes included in this release.
v3
This tag tracks the latest v3.x.x release
v2.2.0
See the changelog for details about the changes included in this release.
v2.1.0
See the changelog for details about the changes included in this release.
v2.0.0
See the changelog for details about the changes included in this release.
v2
This tag tracks the latest v2.x.x release.
v1.7.0
See the changelog for details about the changes included in this release.
v1.6.1
See the changelog for details about the changes included in this release.
v1.6.0
See the changelog for details about the changes included in this release.
v1.5.11
See the changelog for details about the changes included in this release.
v1.5.10
See the changelog for details about the changes included in this release.
v1.5.9
See the changelog for details about the changes included in this release.
v1.5.8
See the changelog for details about the changes included in this release.
v1.5.7
See the changelog for details about the changes included in this release.
... (truncated)
Sourced from aws-actions/configure-aws-credentials's changelog.
4.0.1 (2023-10-03)
Documentation
- Throw a warning when customers use long-term credentials.
4.0.0 (2023-09-11)
- Upgraded runtime to
node20fromnode163.0.2 (2023-09-07)
Bug Fixes
3.0.1 (2023-08-24)
Features
- Can configure
special-characters-workaroundto keep retrying credentials if the returned credentials have special characters (Fixes #599)Bug Fixes
- Fixes #792: Action fails when intending to use existing credentials
- Minor typo fix from
@ubaid-ansari21Changes to existing functionality
- Special characters are now allowed in returned credential variables unless you configure the
special-characters-workaroundoption3.0.0 (2023-08-21)
Features
- Can configure
max-retriesanddisable-retryto modify retry functionality when the assume role call fails- Set returned credentials as step outputs with
output-credentials- Clear AWS related environment variables at the start of the action with
unset-current-credentials- Unique role identifier is now printed in the workflow logs
Bug Fixes
- Can't use credentials if they contain a special character
- Retry functionality added when generating the JWT fails
- Can now use
webIdentityTokenFileoption- Branch name validation too strict
- JS SDK v2 deprecation warning in workflow logs
Changes to existing functionality
- Default session duration is now 1 hour in all cases (from 6 hours in some cases)
- Account ID will not be masked by default in logs
2.2.0 (2023-05-31)
Features
... (truncated)
010d0da
chore: release v4.0.1 (#876)b48e2ee
chore: Bump @types/node from 20.7.0 to 20.8.2 (#875)183b94a
chore: Update dist1d4ae37
chore: Bump @aws-sdk/client-sts from 3.418.0 to 3.423.0
(#873)6a430ce
chore: Bump @smithy/node-http-handler from 2.1.5 to 2.1.6
(#872)8402193
chore: Bump @smithy/property-provider from 2.0.10 to
2.0.11 (#874)f31c158
feat: Recommending using OIDC (#871)164817a
chore: Update diste2c335e
chore: Bump @aws-sdk/client-sts from 3.414.0 to 3.418.0
(#870)a1a09b7
chore: Bump eslint from 8.49.0 to 8.50.0 (#867)Sourced from aws-actions/aws-cloudformation-github-deploy's releases.
v1.2.0
See the CHANGELOG for more details on the release.
v1.1.0
See the CHANGELOG for more details on the release.
v1.0.4
See the CHANGELOG for more details on the release.
e675be1
Merge pull request #89
from kddejong/fix/action/parameter-override-description00a0dee
Remove context variables from descriptionb887c44
Merge pull request #83
from karm435/masterc60e0f1
Merge pull request #85
from jongwooo/docs/replace-deprecated-command-with-env...d0a23b7
Merge pull request #88
from kddejong/feature/parameters/commalisttest3f22dbe
update check action13c7c1f
Support comma delimited lists for parameter overrides87a972c
Merge pull request #82
from asifma/patch-1d60b709
Replace deprecated command with environment file75af353
Updated the link to Cloudformation best practices#(number)
+#endfor +``` + +## Uso + +Aquí hay algunos ejemplos comunes del uso de Leaf. + +### Condiciones + +Leaf puede evaluar una serie de condiciones usando su etiqueta `#if`. Por ejemplo, si proporcionas una variable, comprobará si esa variable existe en su contexto: + +```leaf +#if(title): + The title is #(title) +#else: + No title was provided. +#endif +``` + +También puedes escribir comparaciones, por ejemplo: + +```leaf +#if(title == "Welcome"): + This is a friendly web page. +#else: + No strangers allowed! +#endif +``` + +Si deseas usar otra etiqueta como parte de tu condición, debes omitir el `#` para la etiqueta interna. Por ejemplo: + +```leaf +#if(count(users) > 0): + You have users! +#else: + There are no users yet :( +#endif +``` + +También puedes usar declaraciones `#elseif`: + +```leaf +#if(title == "Welcome"): + Hello new user! +#elseif(title == "Welcome back!"): + Hello old user +#else: + Unexpected page! +#endif +``` + +### Bucles + +Si proporcionas un array de elementos, Leaf puede recorrerlos y te permite manipular cada elemento individualmente usando su etiqueta `#for`. + +Por ejemplo, podríamos actualizar nuestro código Swift para proporcionar una lista de planetas: + +```swift +struct SolarSystem: Codable { + let planets = ["Venus", "Earth", "Mars"] +} + +return req.view.render("solarSystem", SolarSystem()) +``` + +Luego podríamos recorrerlos en Leaf de la siguiente manera: + +```leaf +Planets: +Welcome to Vapor!
+ #endexport +#endextend +``` + +Llamamos `#export` para almacenar algo de HTML y hacerlo disponible para la plantilla que estamos extendiendo actualmente. Luego renderizamos `master.leaf` y usamos los datos exportados cuando sea necesario, junto con cualquier otra variable de contexto pasada desde Swift. Por ejemplo, `master.leaf` podría verse así: + +```leaf + + +Welcome to Vapor!
+ +``` + +### Otras etiquetas + +#### `#count` + +La etiqueta `#count` devuelve el número de elementos en un array. Por ejemplo: + +```leaf +Your search matched #count(matches) pages. +``` + +#### `#lowercased` + +La etiqueta `#lowercased` convierte todas las letras de una cadena a minúsculas. + +```leaf +#lowercased(name) +``` + +#### `#uppercased` + +La etiqueta `#uppercased` convierte todas las letras de una cadena a mayúsculas. + +```leaf +#uppercased(name) +``` + +#### `#capitalized` + +La etiqueta `#capitalized` convierte a mayúsculas la primera letra de cada palabra de una cadena y el resto a minúsculas. Puedes ver [`String.capitalized`](https://developer.apple.com/documentation/foundation/nsstring/1416784-capitalized) para más información. + +```leaf +#capitalized(name) +``` + +#### `#contains` + +La etiqueta `#contains` acepta un array y un valor como sus dos parámetros y devuelve verdadero si el array en el primer parámetro contiene el valor en el segundo parámetro. + +```leaf +#if(contains(planets, "Earth")): + Earth is here! +#else: + Earth is not in this array. +#endif +``` + +#### `#date` + +La etiqueta `#date` formatea las fechas a una cadena legible. Por defecto utiliza el formato ISO8601. + +```swift +render(..., ["now": Date()]) +``` + +```leaf +The time is #date(now) +``` + +Puede pasar una cadena de formateado de fecha personalizada como segundo argumento. Ve a [`DateFormatter`](https://developer.apple.com/documentation/foundation/dateformatter) de Swift para más información. + +```leaf +The date is #date(now, "yyyy-MM-dd") +``` + +#### `#unsafeHTML` + +La etiqueta `#unsafeHTML` actúa como una etiqueta variable - p. ej. `#(variable)`. Sin embargo, no escapa ningún HTML que `variable` pueda contener: + +```leaf +The time is #unsafeHTML(styledTitle) +``` + +!!! note "Nota" + Debes tener cuidado al usar esta etiqueta para asegurarte de que la variable proporcionada no exponga a sus usuarios a un ataque XSS. + +#### `#dumpContext` + +La etiqueta `#dumpContext` renderiza todo el contexto a una cadena legible por humanos. Usa esta etiqueta para depurar lo que se está proporcionando como contexto para el renderizado actual. + +```leaf +Hello, world! +#dumpContext +``` From 81fb2b2b35f2af38e943aa33a57e53b93a66d46b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=20Mohamad=20=E2=8C=98?=Hello \(name)
") + } +} +``` + +```leaf +#hello("John") +``` + +#### Usando Data + +Podemos acceder al valor `name` usando la clave "name" dentro de la propiedad data. + +```swift +enum HelloTagError: Error { + case nameNotFound +} + +struct HelloTag: UnsafeUnescapedLeafTag { + func render(_ ctx: LeafContext) throws -> LeafData { + guard let name = ctx.data["name"]?.string else { + throw HelloTagError.nameNotFound + } + + return LeafData.string("Hello \(name)
") + } +} +``` + +```leaf +#hello() +``` + +_Controlador_: + +```swift +return try await req.view.render("home", ["name": "John"]) +``` From 33812d6933b42e23d08ad748c9405227a04f8f14 Mon Sep 17 00:00:00 2001 From: A 40 years old student