├── .gitignore
├── .prettierrc
├── .travis.yml
├── README.md
├── lib
├── elements.ts
├── express-helpers.ts
├── extended-readable.ts
├── index.ts
├── map.ts
└── util
│ ├── pipe-into.ts
│ └── to-string.ts
├── package-lock.json
├── package.json
├── test
├── helpers.js
├── sanity.js
├── test-attributes.js
├── test-lists.js
├── test-textnodes.js
└── test.js
├── tsconfig.json
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .node_repl_history
3 | .config
4 | .npm
5 | .idea
6 | .DS_Store
7 |
8 | **/*.js
9 |
10 | **/*.js.map
11 | *.d.ts
12 | /.log/
13 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 4,
4 | "useTabs": true
5 | }
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - node
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # flora
2 |
3 | > __flora-tmpl__ on npm.
4 |
5 | [](https://en.wikipedia.org/wiki/Flora_Finch)
6 |
7 | Streaming templates.
8 |
9 | 
10 |
11 | # Why
12 |
13 | HTML is a format that can be streamed. Meaning the browser can start parsing and showing parts of a web page before the full thing has been downloaded. Your application probably has things it needs to do that take some time; like make database requests.
14 |
15 | Parts of your page depend on this data, but much of it does not. Flora allows you to write templates that get to the client as quickly as possible, because only the parts that need to wait, do wait.
16 |
17 | ## Install
18 |
19 | ```shell
20 | yarn add flora-tmpl
21 | ```
22 |
23 | ## Usage
24 |
25 | ```js
26 | const { html, map } = require('flora-tmpl');
27 | const streamArray = require('stream-array');
28 |
29 | function template({items}) {
30 | return html`
31 |
Todos
32 |
33 | ${map(items, item => (
34 | html`- Item ${item}
`
35 | ))}
36 |
37 | `;
38 | }
39 |
40 | template({
41 | items: streamArray([1, 2, 3])
42 | })
43 | .pipe(...)
44 | ```
45 |
46 | ## License
47 |
48 | BSD 2 Clause
49 |
--------------------------------------------------------------------------------
/lib/elements.ts:
--------------------------------------------------------------------------------
1 | import { PathLike } from "fs";
2 | import { html } from ".";
3 | import ExtendedReadable from "./extended-readable";
4 | import { map } from "./map";
5 | import * as fs from "fs";
6 | import { v4 as uuid } from "uuid";
7 |
8 | type StringLike = string | number | boolean | ReadableStream | ExtendedReadable;
9 |
10 | export type Attributes = {
11 | [attribute: string]: StringLike | Promise | undefined;
12 | };
13 |
14 | export function refresh(timeout: number = 0) {
15 | return html/* HTML */ ` `;
16 | }
17 |
18 | export function redirect(url: string): string {
19 | return /* HTML */ ``;
20 | }
21 |
22 | export function document(content: ExtendedReadable): ExtendedReadable {
23 | return html/* HTML */ `
24 |
25 |
26 | ${content}
27 | `;
28 | }
29 |
30 | export function link(text: string | ExtendedReadable, href: string) {
31 | return html/* HTML */ `${text}`;
32 | }
33 |
34 | const sanitizeAttribute = (value?: string) =>
35 | value ? value.replace(/"/g, """) : "";
36 |
37 | export function attributes(attrs: Attributes = {}) {
38 | return map(Object.entries(attrs), async ([attr, value_promise]) => {
39 | let value = await value_promise;
40 | if (typeof value === "string") {
41 | value = sanitizeAttribute(value);
42 | // TODO: think of a way to replace also within streams
43 | }
44 | return value ? html`${attr}="${value}" ` : "";
45 | });
46 | }
47 |
48 | type Option = {
49 | name: string;
50 | value: string;
51 | attrs?: Attributes;
52 | };
53 |
54 | export function select(
55 | name: string,
56 | options: Promise