enonic-wizardry
Advanced tools
Comparing version 0.3.0 to 0.3.1
{ | ||
"name": "enonic-wizardry", | ||
"sideEffects": false, | ||
"version": "0.3.0", | ||
"version": "0.3.1", | ||
"description": "Functional utility library for Enonic XP", | ||
@@ -29,3 +29,3 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"enonic-fp": "^0.3.0", | ||
"enonic-fp": "^0.3.1", | ||
"enonic-types": "^0.1.2", | ||
@@ -40,4 +40,4 @@ "fp-ts": "2.8.2", | ||
"rimraf": "^3.0.2", | ||
"typescript": "^4.0.2" | ||
"typescript": "^4.0.3" | ||
} | ||
} |
@@ -5,11 +5,14 @@ # Enonic Wizardry | ||
Functional utility library for Enonic XP. This library is intended to house reusable and tested code blocks based on [enonic-fp](https://github.com/ItemConsulting/enonic-fp) that can be used in every project. | ||
Functional utility library for Enonic XP. This library is intended to house reusable and tested code blocks based on | ||
[enonic-fp](https://github.com/ItemConsulting/enonic-fp) that can be used in every project. | ||
## Enonic-fp | ||
*Enonic-wizardry* is intended to supplement *enonic-fp* with common patterns. It would be very uncommon to use this library without also using *enonic-fp*. | ||
*Enonic-wizardry* is intended to supplement *enonic-fp* with common patterns. | ||
## Code generation | ||
We recommend using this library together with its sister library: [enonic-ts-codegen](https://github.com/ItemConsulting/enonic-ts-codegen). *enonic-ts-codegen* will create TypeScript `interfaces` for your content-types. Those interfaces will be very useful together with this library. | ||
We recommend using this library together with its sister library: | ||
[enonic-ts-codegen](https://github.com/ItemConsulting/enonic-ts-codegen). *enonic-ts-codegen* will create TypeScript | ||
`interfaces` for your content-types. Those interfaces will be very useful together with this library. | ||
@@ -30,18 +33,17 @@ ## Building the project | ||
```typescript | ||
import { fold, map } from "fp-ts/lib/IOEither"; | ||
import { pipe } from "fp-ts/lib/pipeable"; | ||
import { Request, Response } from "enonic-types/lib/controller"; | ||
import { get as getContent } from "enonic-fp/lib/content"; | ||
import { errorResponse, ok } from "enonic-wizardry/lib/controller"; | ||
import { getContentDataWithId } from "enonic-wizardry/lib/content"; | ||
import { Article } from "../../site/content-types/article/article"; // 1 | ||
import {fold} from "fp-ts/lib/IOEither"; | ||
import {pipe} from "fp-ts/lib/pipeable"; | ||
import {Request, Response} from "enonic-types/controller"; | ||
import {errorResponse, ok} from "enonic-fp/controller"; | ||
import {Article} from "../../site/content-types/article/article"; // 1 | ||
import {getContentByIds} from "enonic-wizardry/content"; | ||
import {forceArray} from "enonic-fp/array"; | ||
export function get(req: Request): Response { // 2 | ||
const keys: Array<string> = forceArray(req.params.key); // ["key1", "key2", "key3"] | ||
const program = pipe( // 3 | ||
getContent<Article>({ // 4 | ||
key: req.params.key! | ||
}), | ||
map(getContentDataWithId), // 5 | ||
fold( // 6 | ||
errorResponse('article.error'), // 7 | ||
getContentByIds<Article>(keys), // 4 | ||
fold( // 5 | ||
errorResponse(req), // 7 | ||
ok // 8 | ||
@@ -53,13 +55,21 @@ ) | ||
} | ||
``` | ||
1. We import an `interface Article { ... }` generated by [enonic-ts-codegen](https://github.com/ItemConsulting/enonic-ts-codegen). | ||
1. We import an `interface Article { ... }` generated by | ||
[enonic-ts-codegen](https://github.com/ItemConsulting/enonic-ts-codegen). | ||
2. We use the imported `Request` and `Response` to control the shape of our controller. | ||
3. We use the `pipe` function from *fp-ts* to pipe the result of one function into the next one. | ||
4. We use the `get` function from `content` – here renamed `getContent` so it won't collide with the `get` function in the controller – to return some content where the type is `IOEither<EnonicError, Content<Article>>`. | ||
5. If we don't want to expose too much about the internal system, maybe we just want to return the `data` of the `Content`. But if we want to do operations on this data, we are going to need the `_id` of the content. The `getContentDataWithId<A>(content: Content<A>): WithId<A>` function takes content as input, and returns the union of the `data` and `{ _id: string }`. | ||
6. The last thing we usually do in a controller is to unpack the `IOEither`. This is done with `fold(handleError, handleSuccess)`. | ||
7. The `errorResponse(i18nPrefix: string)` function returns a new function that can be used as a _callback_ by `fold`. This "new function", takes the `EnonicError` object as a parameter, and creates a Json response with the correct status number, based on the `errorKey` of the `EnonicError`. | ||
8. We pass the `ok` function to `fold` as the second parameter. The `ok` creates a `Response` where the `status` is `200`, and the parameter is the `body`. The content-type dependent on whether the parameter is a `string` (text/html), or anything else (application/json). | ||
9. We have so far constructed a constant `program` of type `IO<Response>`, but we have not yet performed a single sideeffect. It's time to perform those side effects, so we run the `IO` by calling it. | ||
4. We can use the `getContentByIds` function from `content` that query for the `Content<Article>` where the id is one | ||
of the strings in the `keys`-Array. The return type here is `IOEither<EnonicError, ReadonlyArray<Content<Article>>>` | ||
6. The last thing we usually do in `pipe` is to unpack the `IOEither`. This is done with | ||
`fold(handleError, handleSuccess)`. | ||
7. The `errorResponse(req: Request)` function returns a new function that can be used as a _callback_ by `fold`. | ||
This "new function", takes the `EnonicError` object as a parameter, and creates a Json `Response` with the correct | ||
status number, based on the `errorKey` of the `EnonicError`. | ||
8. We pass the `ok` function to `fold` as the second parameter. The `ok` creates a `Response` where the `status` is | ||
`200`, and the parameter is the `body`. In this case the `ReadonlyArray<Content<Article>>` is assigned to the`body`. | ||
9. We have so far constructed a constant `program` of type `IO<Response>`, but we have not yet performed a single | ||
side effect. It's time to perform those side effects, so we run the `IO` by calling it, and a `Response` is returned | ||
which out controller function can return. | ||
@@ -69,9 +79,8 @@ ## API | ||
* [Content](./src/content.ts) | ||
* `publishFromDraftToMaster` | ||
* `publishContentByKey` | ||
* `applyChangesToData` | ||
* `getContentByIds` | ||
* `createAll` | ||
* `createAndPublish` | ||
* `deleteAndPublish` | ||
* `modifyAndPublish` | ||
* `getContentDataWithId` | ||
* `applyChangesToData` | ||
* `createMediaFromAttachment` | ||
@@ -83,27 +92,6 @@ | ||
* [Controller](./src/controller.ts) | ||
* `status` | ||
* `errorResponse` | ||
* `unsafeRenderErrorPage` | ||
* `ok` | ||
* `created` | ||
* `noContent` | ||
* `redirect` | ||
* `badRequest` | ||
* `unauthorized` | ||
* `forbidden` | ||
* `notFound` | ||
* `methodNotAllowed` | ||
* `internalServerError` | ||
* `badGateway` | ||
* [Menu](./src/menu.ts) | ||
* `getSubMenuByKey` | ||
* [Utils](src/array.ts) | ||
* `substringAfter` | ||
* `json` | ||
* `getUuidFromPath` | ||
* `forceArray` | ||
* `forceReadonlyArray` | ||
* `uuidv4` | ||
* [Validation](./src/validation.ts) | ||
* `validate` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
15977
93
Updatedenonic-fp@^0.3.1