@static-pages/core 6.0.0 → 7.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +190 -58
- package/cjs/autoparse.d.ts +1 -0
- package/cjs/autoparse.js +24 -0
- package/cjs/create-reader.d.ts +15 -0
- package/cjs/create-reader.js +67 -0
- package/cjs/create-writer.d.ts +14 -0
- package/cjs/create-writer.js +98 -0
- package/cjs/helpers.d.ts +34 -0
- package/cjs/helpers.js +11 -0
- package/cjs/index.d.ts +4 -15
- package/cjs/index.js +10 -36
- package/cjs/static-pages.d.ts +54 -0
- package/cjs/static-pages.js +67 -0
- package/esm/autoparse.d.ts +1 -0
- package/esm/autoparse.js +17 -0
- package/esm/create-reader.d.ts +15 -0
- package/esm/create-reader.js +60 -0
- package/esm/create-writer.d.ts +14 -0
- package/esm/create-writer.js +71 -0
- package/esm/helpers.d.ts +34 -0
- package/esm/helpers.js +4 -0
- package/esm/index.d.ts +4 -15
- package/esm/index.js +3 -32
- package/esm/static-pages.d.ts +54 -0
- package/esm/static-pages.js +63 -0
- package/package.json +37 -24
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 7.0.0-alpha.0
|
|
4
|
+
- New `CreateReader` and `CreateWriter` utilities available as `from` and `to` prop values.
|
|
5
|
+
- Writers now recieve an AsyncIterable as the previous method made too much confusion.
|
|
6
|
+
- Type defintion improvements.
|
|
7
|
+
- Test suite switched from tap to mocha for now.
|
|
8
|
+
- Coverage reports switched from nyc to c8.
|
|
9
|
+
|
|
10
|
+
|
|
3
11
|
## 6.0.0
|
|
4
12
|
- Adopt JS iterator protocol for the writer callbacks.
|
|
5
13
|
- Removed the `.teardown()` call on the writer when iteration finished. The iterator protocol gives better tools to express these logic.
|
package/README.md
CHANGED
|
@@ -1,70 +1,76 @@
|
|
|
1
1
|
# Static Pages / Core
|
|
2
2
|
|
|
3
|
-
[](https://github.com/staticpagesjs/core/actions/workflows/build.yaml)
|
|
4
4
|
[](https://coveralls.io/github/staticpagesjs/core?branch=master)
|
|
5
5
|

|
|
6
|
-

|
|
10
7
|
|
|
11
8
|
Yet another static pages generator?
|
|
12
9
|
Yes! Because I browsed the whole jamstack scene, but could not find one which
|
|
13
|
-
1.
|
|
14
|
-
2. can
|
|
15
|
-
3.
|
|
16
|
-
4.
|
|
17
|
-
5.
|
|
18
|
-
6.
|
|
19
|
-
7.
|
|
20
|
-
8. easy to extend with JS code
|
|
21
|
-
9. learning and using is easy (Gatsby, Hugo, Jekyll, Eleventy etc. are so cool but harder to learn and configure)
|
|
10
|
+
1. can read input from any source (YAML, JSON, front-matter style markdowns, database etc.)
|
|
11
|
+
2. can render with any template engine (Twig, ejs, Pug, Mustache etc.)
|
|
12
|
+
3. written in JS (preferably TypeScript)
|
|
13
|
+
4. easy to extend with JS code
|
|
14
|
+
5. supports incremental builds
|
|
15
|
+
6. uses MVC pattern
|
|
16
|
+
7. learning and using is easy (Gatsby, Hugo, Jekyll, Eleventy etc. are so cool but harder to learn and configure)
|
|
22
17
|
|
|
23
18
|
And because I wrote a ton of custom static generators before; I tought I can improve the concepts to a point where its (hopefully) useful for others.
|
|
24
19
|
|
|
25
20
|
## Where should I use this?
|
|
26
|
-
|
|
21
|
+
|
|
22
|
+
This project targets small and medium sized websites. The rendering process tries to be as fast as possible so its also useful when you need performance.
|
|
27
23
|
|
|
28
24
|
## Documentation
|
|
29
|
-
|
|
25
|
+
|
|
26
|
+
For detailed information, visit the [project page](https://staticpagesjs.github.io/).
|
|
30
27
|
|
|
31
28
|
## Usage
|
|
32
|
-
- __Readers__ provides an iterable list of page data.
|
|
33
|
-
- __Controllers__ can manipulate and extend each data object.
|
|
34
|
-
- __Writers__ render the final output for you.
|
|
35
29
|
|
|
36
30
|
```js
|
|
37
31
|
import staticPages from '@static-pages/core';
|
|
38
|
-
import
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
view: "content.html.twig",
|
|
48
|
-
viewsDir: "path/to/views/folder",
|
|
49
|
-
outDir: "path/to/output/folder",
|
|
50
|
-
}),
|
|
51
|
-
controller(data) {
|
|
52
|
-
data.timestamp = new Date().toJSON(); // adds a "timestamp" variable
|
|
53
|
-
return data; // returning the data is required if you want to send it to the renderer
|
|
54
|
-
}
|
|
55
|
-
}, {
|
|
56
|
-
from: yamlReader({ // assume we have the home page data in yaml format.
|
|
57
|
-
pattern: "home/*.yaml" // <-- reads home/en.yaml, home/de.yaml, home/fr.yaml etc.
|
|
58
|
-
}),
|
|
59
|
-
to: twigWriter({
|
|
60
|
-
view: "home.html.twig",
|
|
61
|
-
viewsDir: "path/to/views/folder",
|
|
62
|
-
outDir: "path/to/output/folder",
|
|
63
|
-
}),
|
|
32
|
+
import twig from '@static-pages/twig';
|
|
33
|
+
|
|
34
|
+
// Default options for every `Route` via .with() call.
|
|
35
|
+
const generate = staticPages.with({
|
|
36
|
+
to: {
|
|
37
|
+
render: twig({
|
|
38
|
+
viewsDir: 'path/to/views/folder'
|
|
39
|
+
}),
|
|
40
|
+
},
|
|
64
41
|
controller(data) {
|
|
65
|
-
|
|
42
|
+
// adds a 'now' variable to the template context
|
|
43
|
+
data.now = new Date().toJSON();
|
|
44
|
+
|
|
45
|
+
// returning the data is required
|
|
66
46
|
return data;
|
|
67
47
|
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Generate every document type as a page.
|
|
51
|
+
// One route equals one batch of similar pages.
|
|
52
|
+
generate({
|
|
53
|
+
from: {
|
|
54
|
+
cwd: 'pages',
|
|
55
|
+
pattern: '**/*.md',
|
|
56
|
+
},
|
|
57
|
+
}, {
|
|
58
|
+
// Any Iterable or AsyncIterable also accepted eg. an array
|
|
59
|
+
from: [
|
|
60
|
+
{ title: 'About', url: 'about', body: 'About us content' },
|
|
61
|
+
{ title: 'Privacy', url: 'privacy', body: 'Privacy content' },
|
|
62
|
+
],
|
|
63
|
+
}, {
|
|
64
|
+
from: {
|
|
65
|
+
cwd: 'home',
|
|
66
|
+
pattern: '*.yaml',
|
|
67
|
+
},
|
|
68
|
+
to: {
|
|
69
|
+
render: twig({
|
|
70
|
+
view: 'home.html.twig',
|
|
71
|
+
viewsDir: 'path/to/views/folder',
|
|
72
|
+
}),
|
|
73
|
+
},
|
|
68
74
|
})
|
|
69
75
|
.catch(error => {
|
|
70
76
|
console.error('Error:', error);
|
|
@@ -72,24 +78,150 @@ staticPages({
|
|
|
72
78
|
});
|
|
73
79
|
```
|
|
74
80
|
|
|
75
|
-
|
|
81
|
+
### Notes
|
|
76
82
|
|
|
77
|
-
|
|
83
|
+
> The `controller` may return with multiple documents, each will be rendered as a separate page. Alternatively it may return `undefined` to prevent the rendering of the current document.
|
|
84
|
+
|
|
85
|
+
> The `from` parameter can also recieve an `Iterable` or an `AsyncIterable` type!
|
|
86
|
+
|
|
87
|
+
> The `to` parameter can also recieve a `function` that handles the document rendering and storing!
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
## `staticPages(...routes: Route[]): Promise<void>`
|
|
91
|
+
|
|
92
|
+
Each route consists of a `from`, `to` and a `controller` property matching the definition below.
|
|
78
93
|
|
|
79
94
|
```ts
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
95
|
+
interface Route<F, T> {
|
|
96
|
+
from?: Iterable<F> | AsyncIterable<F> | CreateReaderOptions<F>;
|
|
97
|
+
to?: { (data: AsyncIterable<T>): MaybePromise<void>; } | CreateWriterOptions<T>;
|
|
98
|
+
controller?(data: F): MaybePromise<undefined | T | Iterable<T> | AsyncIterable<T>>;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
102
|
+
|
|
103
|
+
interface CreateReaderOptions<T> {
|
|
104
|
+
// Handles file operations, defaults to nodejs `fs` module
|
|
105
|
+
fs?: Filesystem;
|
|
106
|
+
// Current working directory
|
|
107
|
+
cwd?: string;
|
|
108
|
+
// File patterns to include
|
|
109
|
+
pattern?: string | string[];
|
|
110
|
+
// File patterns to exclude
|
|
111
|
+
ignore?: string | string[];
|
|
112
|
+
// Callback to parse a file content into an object
|
|
113
|
+
parse?(content: Uint8Array | string, filename: string): MaybePromise<T>;
|
|
114
|
+
// Called on error
|
|
115
|
+
onError?(error: unknown): MaybePromise<void>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
interface CreateWriterOptions<T> {
|
|
119
|
+
// Handles file operations, defaults to nodejs `fs` module
|
|
120
|
+
fs?: Filesystem;
|
|
121
|
+
// Current working directory
|
|
122
|
+
cwd?: string;
|
|
123
|
+
// Callback that renders the document into a page
|
|
124
|
+
render?(data: T): MaybePromise<Uint8Array | string>;
|
|
125
|
+
// Callback that retrieves the filename (URL) of a page
|
|
126
|
+
name?(data: T): MaybePromise<string>;
|
|
127
|
+
// Called on error
|
|
128
|
+
onError?(error: unknown): MaybePromise<void>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
interface Stats {
|
|
132
|
+
isFile(): boolean;
|
|
133
|
+
isDirectory(): boolean;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
interface Dirent {
|
|
137
|
+
name: string;
|
|
138
|
+
path: string;
|
|
139
|
+
isFile(): boolean;
|
|
140
|
+
isDirectory(): boolean;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
interface Filesystem {
|
|
144
|
+
readdir(
|
|
145
|
+
path: string | URL,
|
|
146
|
+
options: {
|
|
147
|
+
encoding: 'utf8';
|
|
148
|
+
withFileTypes: false;
|
|
149
|
+
recursive: boolean;
|
|
150
|
+
},
|
|
151
|
+
callback: (err: Error | null, files: string[]) => void,
|
|
152
|
+
): void;
|
|
153
|
+
|
|
154
|
+
readdir(
|
|
155
|
+
path: string | URL,
|
|
156
|
+
options: {
|
|
157
|
+
encoding: 'utf8';
|
|
158
|
+
withFileTypes: true;
|
|
159
|
+
recursive: boolean;
|
|
160
|
+
},
|
|
161
|
+
callback: (err: Error | null, files: Dirent[]) => void,
|
|
162
|
+
): void;
|
|
163
|
+
|
|
164
|
+
readFile(
|
|
165
|
+
path: string | URL,
|
|
166
|
+
options: {
|
|
167
|
+
encoding: 'utf8';
|
|
168
|
+
},
|
|
169
|
+
callback: (err: Error | null, data: string) => void
|
|
170
|
+
): void;
|
|
171
|
+
|
|
172
|
+
readFile(
|
|
173
|
+
path: string | URL,
|
|
174
|
+
options: null,
|
|
175
|
+
callback: (err: Error | null, data: Uint8Array) => void
|
|
176
|
+
): void;
|
|
177
|
+
|
|
178
|
+
stat(
|
|
179
|
+
path: string | URL,
|
|
180
|
+
callback: (err: Error | null, stats: Stats) => void
|
|
181
|
+
): void;
|
|
182
|
+
|
|
183
|
+
mkdir(
|
|
184
|
+
path: string | URL,
|
|
185
|
+
options: {
|
|
186
|
+
recursive: true;
|
|
187
|
+
},
|
|
188
|
+
callback: (err: Error | null, path?: string) => void
|
|
189
|
+
): void;
|
|
190
|
+
|
|
191
|
+
writeFile(
|
|
192
|
+
path: string | URL,
|
|
193
|
+
data: string | Uint8Array,
|
|
194
|
+
callback: (err: Error | null) => void
|
|
195
|
+
): void;
|
|
196
|
+
}
|
|
86
197
|
```
|
|
87
198
|
|
|
88
|
-
###
|
|
199
|
+
### `Filesystem` interface
|
|
200
|
+
|
|
201
|
+
When you use the `createReader` and `createWriter` interfaces to read and write documents, you can provide a `Filesystem` implementation. This interface is a minimal subset of the [NodeJS FS API](https://nodejs.org/api/fs.html). By default we use the built-in `node:fs` module.
|
|
202
|
+
|
|
203
|
+
### `CreateReaderOptions` default parameters
|
|
204
|
+
- `fs`: the nodejs `fs` module
|
|
205
|
+
- `cwd`: `'pages'`
|
|
206
|
+
- `parse`: automatically parse `json`, `yaml`, `yml`, `md` or `markdown` extensions with `yaml` and `gray-matter` packages.
|
|
207
|
+
- `onError`: `(err) => { throw err; }`
|
|
208
|
+
|
|
209
|
+
### `CreateWriterOptions` default parameters
|
|
210
|
+
- `fs`: the nodejs `fs` module
|
|
211
|
+
- `cwd`: `'public'`
|
|
212
|
+
- `name`: `(data) => data.url`
|
|
213
|
+
- `render`: `(data) => data.content`
|
|
214
|
+
- `onError`: `(err) => { throw err; }`
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
## `staticPages.with(defaults: Partial<Route>): { (...routes: Partial<Route>[]): Promise<void>; }`
|
|
218
|
+
|
|
219
|
+
Preconfigures a separate instance of the `staticPages` call with the given default parameters.
|
|
220
|
+
These only works as fallback values, you can override every value later.
|
|
89
221
|
|
|
90
|
-
|
|
222
|
+
If a `from` or `to` parameter is a plain object in both defaults and later at the route definition they will be merged (see usage example).
|
|
91
223
|
|
|
92
|
-
- The writer function provided in the `to` property is expected to conform to the JavaScript iterator protocol in order to work. Specifically, this means that the function will be invoked with a `{ value: Data }` parameter for each data object, and will receive a `{ done: true }` parameter when it has finished processing the data and there is no more pages to write.
|
|
93
224
|
|
|
94
225
|
## Missing a feature?
|
|
95
|
-
Create an issue describing your needs
|
|
226
|
+
Create an issue describing your needs!
|
|
227
|
+
If it fits the scope of the project I will implement it.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function autoparse(content: string | Uint8Array, filename: string): any;
|
package/cjs/autoparse.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.autoparse = void 0;
|
|
7
|
+
const yaml_1 = require("yaml");
|
|
8
|
+
const gray_matter_1 = __importDefault(require("gray-matter"));
|
|
9
|
+
function autoparse(content, filename) {
|
|
10
|
+
const extension = filename.split('.').pop().toLowerCase();
|
|
11
|
+
switch (extension) {
|
|
12
|
+
case 'json':
|
|
13
|
+
return JSON.parse(content.toString());
|
|
14
|
+
case 'yaml':
|
|
15
|
+
case 'yml':
|
|
16
|
+
return (0, yaml_1.parse)(content.toString());
|
|
17
|
+
case 'md':
|
|
18
|
+
case 'markdown':
|
|
19
|
+
const { data, content: markdownContent } = (0, gray_matter_1.default)(content.toString());
|
|
20
|
+
return { ...data, content: markdownContent };
|
|
21
|
+
}
|
|
22
|
+
throw new Error(`Could not parse document with '${extension}' extension.`);
|
|
23
|
+
}
|
|
24
|
+
exports.autoparse = autoparse;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { MaybePromise, Filesystem } from './helpers.js';
|
|
2
|
+
export declare namespace createReader {
|
|
3
|
+
interface Options<T> {
|
|
4
|
+
fs?: Filesystem;
|
|
5
|
+
cwd?: string;
|
|
6
|
+
pattern?: string | string[];
|
|
7
|
+
ignore?: string | string[];
|
|
8
|
+
parse?(content: Uint8Array | string, filename: string): MaybePromise<T>;
|
|
9
|
+
onError?(error: unknown): MaybePromise<void>;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export declare function createReader<T>({ fs, cwd, pattern, ignore, parse, onError, }?: createReader.Options<T>): AsyncGenerator<Awaited<T>, void, unknown>;
|
|
13
|
+
export declare namespace createReader {
|
|
14
|
+
var isOptions: <T>(x: unknown) => x is Options<T>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createReader = void 0;
|
|
7
|
+
const picomatch_1 = __importDefault(require("picomatch"));
|
|
8
|
+
const autoparse_js_1 = require("./autoparse.js");
|
|
9
|
+
const helpers_js_1 = require("./helpers.js");
|
|
10
|
+
const node_path_1 = require("node:path");
|
|
11
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
12
|
+
async function* createReader({ fs = node_fs_1.default, cwd = 'pages', pattern, ignore, parse = autoparse_js_1.autoparse, onError = (error) => { throw error; }, } = {}) {
|
|
13
|
+
if (!(0, helpers_js_1.isFilesystem)(fs))
|
|
14
|
+
throw new TypeError(`Expected Node FS compatible implementation at 'fs' property.`);
|
|
15
|
+
if (typeof cwd !== 'string')
|
|
16
|
+
throw new TypeError(`Expected 'string', recieved '${(0, helpers_js_1.getType)(cwd)}' at 'cwd' property.`);
|
|
17
|
+
if (!cwd)
|
|
18
|
+
throw new TypeError(`Expected non-empty string at 'cwd'.`);
|
|
19
|
+
if (typeof pattern !== 'undefined' && typeof pattern !== 'string' && !Array.isArray(pattern))
|
|
20
|
+
throw new TypeError(`Expected 'string' or 'string[]', recieved '${(0, helpers_js_1.getType)(pattern)}' at 'pattern' property.`);
|
|
21
|
+
if (typeof ignore !== 'undefined' && typeof ignore !== 'string' && !Array.isArray(ignore))
|
|
22
|
+
throw new TypeError(`Expected 'string' or 'string[]', recieved '${(0, helpers_js_1.getType)(ignore)}' at 'ignore' property.`);
|
|
23
|
+
if (typeof parse !== 'function')
|
|
24
|
+
throw new TypeError(`Expected 'function', recieved '${(0, helpers_js_1.getType)(parse)}' at 'parse' property.`);
|
|
25
|
+
if (typeof onError !== 'function')
|
|
26
|
+
throw new TypeError(`Expected 'function', recieved '${(0, helpers_js_1.getType)(onError)}' at 'onError' property.`);
|
|
27
|
+
let filenames = await new Promise((resolve, reject) => {
|
|
28
|
+
fs.readdir(cwd, { encoding: 'utf8', recursive: true, withFileTypes: true }, (err, files) => {
|
|
29
|
+
if (err)
|
|
30
|
+
reject(err);
|
|
31
|
+
else
|
|
32
|
+
resolve(files
|
|
33
|
+
.filter(x => x.isFile())
|
|
34
|
+
.map(x => (0, node_path_1.join)((0, node_path_1.relative)(cwd, x.path), x.name)));
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
if (typeof pattern !== 'undefined' || typeof ignore !== 'undefined') {
|
|
38
|
+
const filteredFilenames = [];
|
|
39
|
+
const isMatch = (0, picomatch_1.default)(pattern !== null && pattern !== void 0 ? pattern : '**/*', { ignore });
|
|
40
|
+
for (const filename of filenames) {
|
|
41
|
+
if (isMatch(filename)) {
|
|
42
|
+
filteredFilenames.push(filename);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
filenames = filteredFilenames;
|
|
46
|
+
}
|
|
47
|
+
for (const filename of filenames) {
|
|
48
|
+
try {
|
|
49
|
+
const content = await new Promise((resolve, reject) => {
|
|
50
|
+
fs.readFile((0, node_path_1.join)(cwd, filename), (err, data) => {
|
|
51
|
+
if (err)
|
|
52
|
+
reject(err);
|
|
53
|
+
else
|
|
54
|
+
resolve(data);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
yield await parse(content, filename);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
await onError(error);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.createReader = createReader;
|
|
65
|
+
createReader.isOptions = (x) => {
|
|
66
|
+
return x == undefined || (!!x && typeof x === 'object' && !(0, helpers_js_1.isIterable)(x) && !(0, helpers_js_1.isAsyncIterable)(x));
|
|
67
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { MaybePromise, Filesystem } from './helpers.js';
|
|
2
|
+
export declare namespace createWriter {
|
|
3
|
+
interface Options<T> {
|
|
4
|
+
fs?: Filesystem;
|
|
5
|
+
cwd?: string;
|
|
6
|
+
name?(data: T): MaybePromise<string>;
|
|
7
|
+
render?(data: T): MaybePromise<Uint8Array | string>;
|
|
8
|
+
onError?(error: unknown): MaybePromise<void>;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export declare function createWriter<T>({ fs, cwd, name, render, onError, }?: createWriter.Options<T>): (iterable: Iterable<T> | AsyncIterable<T>) => Promise<void>;
|
|
12
|
+
export declare namespace createWriter {
|
|
13
|
+
var isOptions: <T>(x: unknown) => x is Options<T>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.createWriter = void 0;
|
|
27
|
+
const helpers_js_1 = require("./helpers.js");
|
|
28
|
+
const node_path_1 = require("node:path");
|
|
29
|
+
const nodeFs = __importStar(require("node:fs"));
|
|
30
|
+
const defaultNamer = (data) => {
|
|
31
|
+
if (!!data && typeof data === 'object' && 'url' in data && typeof data.url === 'string') {
|
|
32
|
+
return data.url.concat('.html');
|
|
33
|
+
}
|
|
34
|
+
throw new Error(`Missing 'url' field in the document.`);
|
|
35
|
+
};
|
|
36
|
+
const defaultRenderer = (data) => {
|
|
37
|
+
if (!!data && typeof data === 'object' && 'content' in data) {
|
|
38
|
+
return '' + data.content;
|
|
39
|
+
}
|
|
40
|
+
throw new Error(`Missing 'content' field in the document.`);
|
|
41
|
+
};
|
|
42
|
+
function createWriter({ fs = nodeFs, cwd = 'public', name = defaultNamer, render = defaultRenderer, onError = (error) => { throw error; }, } = {}) {
|
|
43
|
+
if (!(0, helpers_js_1.isFilesystem)(fs))
|
|
44
|
+
throw new TypeError(`Expected Node FS compatible implementation at 'fs' property.`);
|
|
45
|
+
if (typeof cwd !== 'string')
|
|
46
|
+
throw new TypeError(`Expected 'string', recieved '${(0, helpers_js_1.getType)(cwd)}' at 'cwd' property.`);
|
|
47
|
+
if (!cwd)
|
|
48
|
+
throw new TypeError(`Expected non-empty string at 'cwd'.`);
|
|
49
|
+
if (typeof render !== 'function')
|
|
50
|
+
throw new TypeError(`Expected 'function', recieved '${(0, helpers_js_1.getType)(render)}' at 'render' property.`);
|
|
51
|
+
if (typeof name !== 'function')
|
|
52
|
+
throw new TypeError(`Expected 'function', recieved '${(0, helpers_js_1.getType)(name)}' at 'name' property.`);
|
|
53
|
+
if (typeof onError !== 'function')
|
|
54
|
+
throw new TypeError(`Expected 'function', recieved '${(0, helpers_js_1.getType)(onError)}' at 'onError' property.`);
|
|
55
|
+
return async function (iterable) {
|
|
56
|
+
if (!(0, helpers_js_1.isIterable)(iterable) && !(0, helpers_js_1.isAsyncIterable)(iterable))
|
|
57
|
+
throw new TypeError(`Expected 'Iterable' or 'AsyncIterable' at callback.`);
|
|
58
|
+
for await (const data of iterable) {
|
|
59
|
+
try {
|
|
60
|
+
const filepath = cwd + '/' + await name(data);
|
|
61
|
+
const dirpath = (0, node_path_1.dirname)(filepath);
|
|
62
|
+
await new Promise((resolve, reject) => {
|
|
63
|
+
fs.stat(dirpath, (err, stats) => {
|
|
64
|
+
if (err) {
|
|
65
|
+
fs.mkdir(dirpath, { recursive: true }, (err) => {
|
|
66
|
+
if (err) {
|
|
67
|
+
reject(err);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
resolve(undefined);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
resolve(undefined);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
const content = await render(data);
|
|
80
|
+
await new Promise((resolve, reject) => {
|
|
81
|
+
fs.writeFile(filepath, content, (err) => {
|
|
82
|
+
if (err)
|
|
83
|
+
reject(err);
|
|
84
|
+
else
|
|
85
|
+
resolve(undefined);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
await onError(error);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
exports.createWriter = createWriter;
|
|
96
|
+
createWriter.isOptions = (x) => {
|
|
97
|
+
return x == undefined || (!!x && typeof x === 'object');
|
|
98
|
+
};
|
package/cjs/helpers.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type MaybePromise<T> = T | Promise<T>;
|
|
2
|
+
interface Stats {
|
|
3
|
+
isFile(): boolean;
|
|
4
|
+
isDirectory(): boolean;
|
|
5
|
+
}
|
|
6
|
+
interface Dirent {
|
|
7
|
+
name: string;
|
|
8
|
+
path: string;
|
|
9
|
+
isFile(): boolean;
|
|
10
|
+
isDirectory(): boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface Filesystem {
|
|
13
|
+
readdir(path: string | URL, options: {
|
|
14
|
+
encoding: 'utf8';
|
|
15
|
+
withFileTypes: false;
|
|
16
|
+
recursive: boolean;
|
|
17
|
+
}, callback: (err: Error | null, files: string[]) => void): void;
|
|
18
|
+
readdir(path: string | URL, options: {
|
|
19
|
+
encoding: 'utf8';
|
|
20
|
+
withFileTypes: true;
|
|
21
|
+
recursive: boolean;
|
|
22
|
+
}, callback: (err: Error | null, files: Dirent[]) => void): void;
|
|
23
|
+
stat(path: string | URL, callback: (err: Error | null, stats: Stats) => void): void;
|
|
24
|
+
mkdir(path: string | URL, options: {
|
|
25
|
+
recursive: true;
|
|
26
|
+
}, callback: (err: Error | null, path?: string) => void): void;
|
|
27
|
+
readFile(path: string | URL, callback: (err: Error | null, data: Uint8Array) => void): void;
|
|
28
|
+
writeFile(path: string | URL, data: string | Uint8Array, callback: (err: Error | null) => void): void;
|
|
29
|
+
}
|
|
30
|
+
export declare const isFilesystem: (x: unknown) => x is Filesystem;
|
|
31
|
+
export declare const isIterable: <T>(x: unknown) => x is Iterable<T>;
|
|
32
|
+
export declare const isAsyncIterable: <T>(x: unknown) => x is AsyncIterable<T>;
|
|
33
|
+
export declare const getType: (x: unknown) => string;
|
|
34
|
+
export {};
|
package/cjs/helpers.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getType = exports.isAsyncIterable = exports.isIterable = exports.isFilesystem = void 0;
|
|
4
|
+
const isFilesystem = (x) => !!x && typeof x === 'object' && 'stat' in x && 'mkdir' in x && 'readFile' in x && 'writeFile' in x;
|
|
5
|
+
exports.isFilesystem = isFilesystem;
|
|
6
|
+
const isIterable = (x) => !!x && typeof x === 'object' && Symbol.iterator in x && typeof x[Symbol.iterator] === 'function';
|
|
7
|
+
exports.isIterable = isIterable;
|
|
8
|
+
const isAsyncIterable = (x) => !!x && typeof x === 'object' && Symbol.asyncIterator in x && typeof x[Symbol.asyncIterator] === 'function';
|
|
9
|
+
exports.isAsyncIterable = isAsyncIterable;
|
|
10
|
+
const getType = (x) => typeof x === 'object' ? (x ? (Array.isArray(x) ? 'array' : 'object') : 'null') : typeof x;
|
|
11
|
+
exports.getType = getType;
|
package/cjs/index.d.ts
CHANGED
|
@@ -1,15 +1,4 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
controller?(data: R): void | W | W[] | Promise<void | W | W[]>;
|
|
6
|
-
};
|
|
7
|
-
}
|
|
8
|
-
export declare function staticPages<R1 extends Record<string, unknown> = Record<string, unknown>, W1 extends Record<string, unknown> = Record<string, unknown>>(...routes: [staticPages.Route<R1, W1>]): Promise<void>;
|
|
9
|
-
export declare function staticPages<R1 extends Record<string, unknown> = Record<string, unknown>, W1 extends Record<string, unknown> = Record<string, unknown>, R2 extends Record<string, unknown> = Record<string, unknown>, W2 extends Record<string, unknown> = Record<string, unknown>>(...routes: [staticPages.Route<R1, W1>, staticPages.Route<R2, W2>]): Promise<void>;
|
|
10
|
-
export declare function staticPages<R1 extends Record<string, unknown> = Record<string, unknown>, W1 extends Record<string, unknown> = Record<string, unknown>, R2 extends Record<string, unknown> = Record<string, unknown>, W2 extends Record<string, unknown> = Record<string, unknown>, R3 extends Record<string, unknown> = Record<string, unknown>, W3 extends Record<string, unknown> = Record<string, unknown>>(...routes: [staticPages.Route<R1, W1>, staticPages.Route<R2, W2>, staticPages.Route<R3, W3>]): Promise<void>;
|
|
11
|
-
export declare function staticPages<R1 extends Record<string, unknown> = Record<string, unknown>, W1 extends Record<string, unknown> = Record<string, unknown>, R2 extends Record<string, unknown> = Record<string, unknown>, W2 extends Record<string, unknown> = Record<string, unknown>, R3 extends Record<string, unknown> = Record<string, unknown>, W3 extends Record<string, unknown> = Record<string, unknown>, R4 extends Record<string, unknown> = Record<string, unknown>, W4 extends Record<string, unknown> = Record<string, unknown>>(...routes: [staticPages.Route<R1, W1>, staticPages.Route<R2, W2>, staticPages.Route<R3, W3>, staticPages.Route<R4, W4>]): Promise<void>;
|
|
12
|
-
export declare function staticPages<R1 extends Record<string, unknown> = Record<string, unknown>, W1 extends Record<string, unknown> = Record<string, unknown>, R2 extends Record<string, unknown> = Record<string, unknown>, W2 extends Record<string, unknown> = Record<string, unknown>, R3 extends Record<string, unknown> = Record<string, unknown>, W3 extends Record<string, unknown> = Record<string, unknown>, R4 extends Record<string, unknown> = Record<string, unknown>, W4 extends Record<string, unknown> = Record<string, unknown>, R5 extends Record<string, unknown> = Record<string, unknown>, W5 extends Record<string, unknown> = Record<string, unknown>>(...routes: [staticPages.Route<R1, W1>, staticPages.Route<R2, W2>, staticPages.Route<R3, W3>, staticPages.Route<R4, W4>, staticPages.Route<R5, W5>]): Promise<void>;
|
|
13
|
-
export declare function staticPages<R1 extends Record<string, unknown> = Record<string, unknown>, W1 extends Record<string, unknown> = Record<string, unknown>, R2 extends Record<string, unknown> = Record<string, unknown>, W2 extends Record<string, unknown> = Record<string, unknown>, R3 extends Record<string, unknown> = Record<string, unknown>, W3 extends Record<string, unknown> = Record<string, unknown>, R4 extends Record<string, unknown> = Record<string, unknown>, W4 extends Record<string, unknown> = Record<string, unknown>, R5 extends Record<string, unknown> = Record<string, unknown>, W5 extends Record<string, unknown> = Record<string, unknown>, R6 extends Record<string, unknown> = Record<string, unknown>, W6 extends Record<string, unknown> = Record<string, unknown>>(...routes: [staticPages.Route<R1, W1>, staticPages.Route<R2, W2>, staticPages.Route<R3, W3>, staticPages.Route<R4, W4>, staticPages.Route<R5, W5>, staticPages.Route<R6, W6>]): Promise<void>;
|
|
14
|
-
export declare function staticPages(...routes: staticPages.Route[]): Promise<void>;
|
|
15
|
-
export default staticPages;
|
|
1
|
+
export { staticPages, staticPages as default } from './static-pages.js';
|
|
2
|
+
export { createReader } from './create-reader.js';
|
|
3
|
+
export { createWriter } from './create-writer.js';
|
|
4
|
+
export type { Filesystem } from './helpers.js';
|
package/cjs/index.js
CHANGED
|
@@ -1,36 +1,10 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.staticPages = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const { from, to, controller } = route;
|
|
12
|
-
if (!isIterable(from) && !isAsyncIterable(from))
|
|
13
|
-
throw new Error('Argument type mismatch, \'from\' exptects \'iterable\' or \'asyncIterable\'.');
|
|
14
|
-
if (typeof to !== 'function')
|
|
15
|
-
throw new Error(`Argument type mismatch, 'to' expects 'function', got '${getType(to)}'.`);
|
|
16
|
-
if (typeof controller !== 'undefined' && typeof controller !== 'function')
|
|
17
|
-
throw new Error(`Argument type mismatch, 'controller' expects 'function', got '${getType(controller)}'.`);
|
|
18
|
-
const isController = typeof controller === 'function';
|
|
19
|
-
for await (const data of from) {
|
|
20
|
-
const results = isController ? await controller(data) : data;
|
|
21
|
-
if (typeof results === 'object' && results) {
|
|
22
|
-
if (Array.isArray(results)) {
|
|
23
|
-
for (const result of results) {
|
|
24
|
-
await to({ value: result });
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
await to({ value: results });
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
await to({ done: true, value: undefined });
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
exports.staticPages = staticPages;
|
|
36
|
-
exports.default = staticPages;
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createWriter = exports.createReader = exports.default = exports.staticPages = void 0;
|
|
4
|
+
var static_pages_js_1 = require("./static-pages.js");
|
|
5
|
+
Object.defineProperty(exports, "staticPages", { enumerable: true, get: function () { return static_pages_js_1.staticPages; } });
|
|
6
|
+
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return static_pages_js_1.staticPages; } });
|
|
7
|
+
var create_reader_js_1 = require("./create-reader.js");
|
|
8
|
+
Object.defineProperty(exports, "createReader", { enumerable: true, get: function () { return create_reader_js_1.createReader; } });
|
|
9
|
+
var create_writer_js_1 = require("./create-writer.js");
|
|
10
|
+
Object.defineProperty(exports, "createWriter", { enumerable: true, get: function () { return create_writer_js_1.createWriter; } });
|