@sphido/core 1.0.11 → 2.0.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/LICENSE.md +1 -1
- package/lib/all-pages.js +13 -0
- package/lib/get-pages.js +30 -10
- package/lib/index.js +3 -1
- package/lib/is-page.js +20 -0
- package/lib/read-file.js +10 -0
- package/lib/write-file.js +18 -0
- package/package.json +6 -4
- package/readme.md +129 -26
- package/lib/get-page.js +0 -29
package/LICENSE.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
-----------
|
|
3
3
|
|
|
4
|
-
Copyright (c)
|
|
4
|
+
Copyright (c) 2022 Roman Ožana (https://ozana.cz/)
|
|
5
5
|
Permission is hereby granted, free of charge, to any person
|
|
6
6
|
obtaining a copy of this software and associated documentation
|
|
7
7
|
files (the "Software"), to deal in the Software without
|
package/lib/all-pages.js
ADDED
package/lib/get-pages.js
CHANGED
|
@@ -1,13 +1,33 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {join, parse} from 'node:path';
|
|
2
|
+
import {readdir} from 'node:fs/promises';
|
|
3
|
+
import {isPage} from './is-page.js';
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
|
-
*
|
|
5
|
-
* @param {
|
|
6
|
-
* @param {
|
|
7
|
-
* @
|
|
6
|
+
* Retrieve an array tree of pages from path
|
|
7
|
+
* @param {string} path
|
|
8
|
+
* @param {Function} include
|
|
9
|
+
* @param extenders
|
|
10
|
+
* @returns {Promise<Awaited<unknown>[{name, path}]>}
|
|
8
11
|
*/
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
export async function getPages({path = 'content', include = isPage} = {}, ...extenders) {
|
|
13
|
+
const dir = await readdir(path, {withFileTypes: true});
|
|
14
|
+
|
|
15
|
+
return Promise.all(
|
|
16
|
+
dir
|
|
17
|
+
.filter(dirent => include(dirent))
|
|
18
|
+
.map(async dirent => {
|
|
19
|
+
// Page
|
|
20
|
+
const page = {name: parse(dirent.name).name, path: join(path, dirent.name)};
|
|
21
|
+
|
|
22
|
+
// Read subdirectory recursively
|
|
23
|
+
if (dirent.isDirectory()) {
|
|
24
|
+
page.children = await getPages({path: page.path, isPage: include}, ...extenders);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Calling callbacks
|
|
28
|
+
await Promise.all(extenders.filter(f => typeof f === 'function').map(f => f(page, dirent, path)));
|
|
29
|
+
|
|
30
|
+
// Assign objects with page
|
|
31
|
+
return Object.assign(page, ...extenders.filter(o => typeof o === 'object'));
|
|
32
|
+
}));
|
|
33
|
+
}
|
package/lib/index.js
CHANGED
package/lib/is-page.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default page filter
|
|
3
|
+
*
|
|
4
|
+
* - skip hidden files (starts with .)
|
|
5
|
+
* - skip and directories (starts with .)
|
|
6
|
+
* - skip drafts files with underscore at the beginning
|
|
7
|
+
* - accept only *.html and *.md files
|
|
8
|
+
*
|
|
9
|
+
* @param {object} dirent
|
|
10
|
+
* @returns {boolean}
|
|
11
|
+
*/
|
|
12
|
+
export function isPage(dirent) {
|
|
13
|
+
// Accept only *.md, *.html files
|
|
14
|
+
if (dirent.isFile() && !dirent.name.startsWith('_') && !dirent.name.startsWith('.')) {
|
|
15
|
+
return dirent.name.endsWith('.md') || dirent.name.endsWith('.html');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Or not hidden directory
|
|
19
|
+
return dirent.isDirectory() && !dirent.name.startsWith('.');
|
|
20
|
+
}
|
package/lib/read-file.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {mkdir, writeFile as writeFileAsync} from 'node:fs/promises';
|
|
2
|
+
import {existsSync} from 'node:fs';
|
|
3
|
+
import {dirname} from 'node:path';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Write content to the file and create directory if not exists
|
|
7
|
+
*
|
|
8
|
+
* @param {string} file
|
|
9
|
+
* @param {string} content
|
|
10
|
+
* @returns {Promise<*>}
|
|
11
|
+
*/
|
|
12
|
+
export async function writeFile(file, content) {
|
|
13
|
+
if (!existsSync(dirname(file))) {
|
|
14
|
+
await mkdir(dirname(file), {recursive: true});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return writeFileAsync(file, content);
|
|
18
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sphido/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Roman Ožana",
|
|
6
6
|
"email": "roman@ozana.cz",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"type": "module",
|
|
12
12
|
"exports": "./lib/index.js",
|
|
13
13
|
"engines": {
|
|
14
|
-
"node": ">=
|
|
14
|
+
"node": ">=14"
|
|
15
15
|
},
|
|
16
16
|
"keywords": [
|
|
17
17
|
"markdown",
|
|
@@ -33,10 +33,12 @@
|
|
|
33
33
|
"url": "git@github.com:sphido/sphido.git"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"
|
|
36
|
+
"@sindresorhus/slugify": "^2.1.0",
|
|
37
|
+
"ava": "^4.2.0",
|
|
38
|
+
"marked": "^4.0.17"
|
|
37
39
|
},
|
|
38
40
|
"scripts": {
|
|
39
41
|
"test": "ava"
|
|
40
42
|
},
|
|
41
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "75cf4126bc6027237f192873c51c0d636aacd0ab"
|
|
42
44
|
}
|
package/readme.md
CHANGED
|
@@ -1,25 +1,117 @@
|
|
|
1
1
|
# @sphido/core
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Sphido core package contains two most important function `getPages()` and `allPages()`.
|
|
4
|
+
The `getPages()` function scans directories for all `*.md` and `*.html` files.
|
|
5
|
+
Second function `allPages()` is [generator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator)
|
|
6
|
+
that allow to iterate over all pages.
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
```javascript
|
|
9
|
+
const pages = await getPages({path: 'content'}, /* ...exteners */);
|
|
10
|
+
```
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
Returned structure is very simple and looks like follow:
|
|
10
13
|
|
|
11
14
|
```json
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
[
|
|
16
|
+
{
|
|
17
|
+
"name": "Main page",
|
|
18
|
+
"path": "content/Main page.md"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "Directory",
|
|
22
|
+
"children": [
|
|
23
|
+
{
|
|
24
|
+
"name": "Subpage one",
|
|
25
|
+
"path": "content/Directory/Subpage one.md"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"name": "Subpage two",
|
|
29
|
+
"path": "content/Directory/Subpage two.md"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Then iterate over pages like follow:
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
for (const page of allPages(pages)) {
|
|
40
|
+
console.log(page);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Extend
|
|
45
|
+
|
|
46
|
+
Every single `page` object inside structure can be modified with extender. Extenders are set as additional parameters of the `getPages()` function.
|
|
47
|
+
There are two types of extenders:
|
|
48
|
+
|
|
49
|
+
### *callback* extenders
|
|
50
|
+
|
|
51
|
+
Callback extender is a function that is called during recursion over each page with three
|
|
52
|
+
parameters passed to the function `page`, `path` and [`dirent`](https://nodejs.org/api/fs.html#class-fsdirent).
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
const callbackExtender = (page, path, dirent) => {
|
|
56
|
+
// do anything with page object
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const pages = await getPages({path: 'content'}, callbackExtender);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### *object* extenders
|
|
63
|
+
|
|
64
|
+
This extender is just a simple JavaScript object that is combined with the `page` object using the [Object.assign()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) function.
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
const objectExtender = {
|
|
68
|
+
author: 'Roman Ožana'
|
|
17
69
|
}
|
|
70
|
+
|
|
71
|
+
const pages = await getPages({path: 'content'}, objectExtender);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
There is no limit to the number of extenders, you can combine as many as you want.
|
|
75
|
+
Let's have the following code:
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
const extenders = [
|
|
79
|
+
// callback extender will be called during iteration
|
|
80
|
+
(page) => {
|
|
81
|
+
// add property
|
|
82
|
+
page.title = `${page.name} | my best website`;
|
|
83
|
+
// or function
|
|
84
|
+
page.getDate = () => new Date();
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
// object extender will be merged with page object
|
|
88
|
+
{
|
|
89
|
+
"author": "Roman Ožana",
|
|
90
|
+
"getLink": function () {
|
|
91
|
+
return this.path.replace('content', 'public');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
const pages = getPages({path: 'content'}, ...extenders);
|
|
18
97
|
```
|
|
19
98
|
|
|
20
|
-
|
|
99
|
+
then you get this structure:
|
|
21
100
|
|
|
22
|
-
|
|
101
|
+
```json
|
|
102
|
+
[
|
|
103
|
+
{
|
|
104
|
+
"name": "Main page",
|
|
105
|
+
"path": "content/Main page.md",
|
|
106
|
+
"title": "Main page | my best website",
|
|
107
|
+
"author": "Roman Ožana",
|
|
108
|
+
"getDate": "[Function: getDate]",
|
|
109
|
+
"getLink": "[Function: getLink]"
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Installation
|
|
23
115
|
|
|
24
116
|
```bash
|
|
25
117
|
yarn add @sphido/core
|
|
@@ -27,25 +119,36 @@ yarn add @sphido/core
|
|
|
27
119
|
|
|
28
120
|
## Example
|
|
29
121
|
|
|
122
|
+
Following example read all `*.md` files in `content` directory and process them with [marked](https://github.com/markedjs/marked) to HTML files
|
|
123
|
+
|
|
30
124
|
```javascript
|
|
31
|
-
|
|
32
|
-
import {getPages} from '@sphido/core';
|
|
125
|
+
#!/usr/bin/env node
|
|
33
126
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
})();
|
|
39
|
-
```
|
|
127
|
+
import {dirname, relative, join} from 'node:path';
|
|
128
|
+
import {getPages, allPages, readFile, writeFile} from '@sphido/core';
|
|
129
|
+
import slugify from '@sindresorhus/slugify';
|
|
130
|
+
import {marked} from 'marked';
|
|
40
131
|
|
|
41
|
-
|
|
132
|
+
function getHtml({name, content, path}) {
|
|
133
|
+
return `<!DOCTYPE html>
|
|
134
|
+
<html lang="cs" dir="ltr">
|
|
135
|
+
<head>
|
|
136
|
+
<meta charset="UTF-8">
|
|
137
|
+
<script src="https://cdn.tailwindcss.com?plugins=typography"></script>
|
|
138
|
+
<title>${name} | Sphido Example page</title>
|
|
139
|
+
</head>
|
|
140
|
+
<body class="prose mx-auto my-6">${content}</body>
|
|
141
|
+
<!-- Generated with Sphido from ${path} -->
|
|
142
|
+
</html>`;
|
|
143
|
+
}
|
|
42
144
|
|
|
43
|
-
|
|
44
|
-
import {getPage} from '@sphido/core';
|
|
145
|
+
const pages = await getPages({path: 'content'});
|
|
45
146
|
|
|
46
|
-
(
|
|
47
|
-
|
|
48
|
-
|
|
147
|
+
for (const page of allPages(pages)) {
|
|
148
|
+
page.output = join('public', relative('content', dirname(page.path)), slugify(page.name) + '.html');
|
|
149
|
+
page.content = marked(await readFile(page.path));
|
|
150
|
+
await writeFile(page.output, getHtml(page));
|
|
151
|
+
}
|
|
49
152
|
```
|
|
50
153
|
|
|
51
154
|
## Source codes
|
package/lib/get-page.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import {promisify} from 'node:util';
|
|
4
|
-
|
|
5
|
-
const readFile = promisify(fs.readFile);
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Return {page} object
|
|
9
|
-
* @param {String} file
|
|
10
|
-
* @param {Object.<string, number>} extenders
|
|
11
|
-
* @returns {Promise<*>}
|
|
12
|
-
*/
|
|
13
|
-
export async function getPage(file, ...extenders) {
|
|
14
|
-
const ext = path.extname(file);
|
|
15
|
-
|
|
16
|
-
const page = {
|
|
17
|
-
file,
|
|
18
|
-
dir: path.relative('.', path.dirname(file)),
|
|
19
|
-
ext,
|
|
20
|
-
base: path.basename(file, ext),
|
|
21
|
-
content: await readFile(file, 'utf8'),
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
// Callbacks only
|
|
25
|
-
extenders.filter(f => typeof f === 'function').map(f => f(page));
|
|
26
|
-
|
|
27
|
-
// Assign objects
|
|
28
|
-
return Object.assign(page, ...extenders.filter(f => typeof f === 'object'));
|
|
29
|
-
}
|