mikel-press 0.29.0 → 0.30.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/README.md +29 -0
- package/index.js +116 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,6 +98,7 @@ Each HTML file processed by **mikel-press** will be handled by the mikel templat
|
|
|
98
98
|
| Variable | Description |
|
|
99
99
|
|----------|-------------|
|
|
100
100
|
| `site.pages` | A list containing all pages processed by **mikel-press**. |
|
|
101
|
+
| `site.assets` | A list containing all assets files loaded by the `AssetsPlugin`. |
|
|
101
102
|
| `site.data` | An object containing all data items loaded by `DataPlugin`. |
|
|
102
103
|
| `site.partials` | A list containing all partials files loaded by the `PartialsPlugin`. |
|
|
103
104
|
| `site.layouts` | A list containing all layout files loaded by the `LayoutsPlugin`. |
|
|
@@ -110,9 +111,22 @@ Each HTML file processed by **mikel-press** will be handled by the mikel templat
|
|
|
110
111
|
| `page.content` | The raw content of the page before begin processed by **mikel**. |
|
|
111
112
|
| `page.title` | The title of the page. |
|
|
112
113
|
| `page.path` | The path to the page. Example: `about/index.html`. |
|
|
114
|
+
| `page.dir` | The directory of the page. Example: `about`. |
|
|
115
|
+
| `page.name` | The name of the page without extension. Example: `index`. |
|
|
116
|
+
| `page.ext` | The file extension of the page. Example: `.html`. |
|
|
113
117
|
| `page.url` | The path to the page including the leading `/`. Example: `/about/index.html`. |
|
|
114
118
|
| `page.attributes` | An object containing all the frontmatter variables in the page processed by `FrontmatterPlugin`. |
|
|
115
119
|
|
|
120
|
+
#### Asset variables
|
|
121
|
+
|
|
122
|
+
| Variable | Description |
|
|
123
|
+
|----------|-------------|
|
|
124
|
+
| `asset.path` | The path to the asset file. Example: `images/logo.png`. |
|
|
125
|
+
| `asset.dir` | The directory of the asset file. Example: `images`. |
|
|
126
|
+
| `asset.name` | The name of the asset file without extension. Example: `logo`. |
|
|
127
|
+
| `asset.ext` | The file extension of the asset file. Example: `.png`. |
|
|
128
|
+
| `asset.url` | The path to the asset file including the leading `/`. Example: `/images/logo.png`. |
|
|
129
|
+
|
|
116
130
|
## Plugins
|
|
117
131
|
|
|
118
132
|
**mikel-press** relies on plugins to handle file reading, transformation, and rendering. The following plugins are built-in:
|
|
@@ -187,6 +201,21 @@ This plugin copies static files from the source to the destination.
|
|
|
187
201
|
Options:
|
|
188
202
|
- `options.patterns` (array): List of file patterns to copy. Each pattern should have `from` and `to`.
|
|
189
203
|
|
|
204
|
+
### `press.RedirectsPlugin(options)`
|
|
205
|
+
|
|
206
|
+
The RedirectsPlugin lets you define URL redirects. For each redirect rule, the plugin generates a small HTML file that forwards visitors to the target URL using both HTML and JavaScript fallbacks.
|
|
207
|
+
|
|
208
|
+
Options:
|
|
209
|
+
- `options.redirects` (array): list of redirections. Each redirection should have `from` and `to`.
|
|
210
|
+
|
|
211
|
+
```javascript
|
|
212
|
+
press.RedirectsPlugin({
|
|
213
|
+
redirects: [
|
|
214
|
+
{ from: "/socials/github.html", to: "https://github.com/jmjuanes" },
|
|
215
|
+
],
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
190
219
|
## API
|
|
191
220
|
|
|
192
221
|
**mikel-press** exposes a single function that triggers the build with the given configuration object provided as an argument.
|
package/index.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import * as crypto from "node:crypto";
|
|
4
|
+
|
|
5
|
+
// @description internal method to get the first node that ends with the provided string
|
|
6
|
+
const getNodeFromSource = (nodes = [], endingStr = "") => {
|
|
7
|
+
return (nodes || []).find(node => (node.source || "").endsWith(endingStr || ""));
|
|
8
|
+
};
|
|
3
9
|
|
|
4
10
|
// @description get all plugins of the given type
|
|
5
11
|
const getPlugins = (context, name) => {
|
|
@@ -11,6 +17,26 @@ const applyLayout = page => {
|
|
|
11
17
|
return `{{>>layout:${page.attributes.layout}}}\n\n${page.content}\n\n{{/layout:${page.attributes.layout}}}\n`;
|
|
12
18
|
};
|
|
13
19
|
|
|
20
|
+
// @description generate the content for the redirection page
|
|
21
|
+
const generateRedirectHTML = (to, status) => {
|
|
22
|
+
const content = [
|
|
23
|
+
`<!DOCTYPE html>`,
|
|
24
|
+
`<html lang="en">`,
|
|
25
|
+
`<head>`,
|
|
26
|
+
` <meta charset="utf-8" />`,
|
|
27
|
+
` <title>Redirecting...</title>`,
|
|
28
|
+
` <meta http-equiv="refresh" content="0; url=${to}" />`,
|
|
29
|
+
` <link rel="canonical" href="${to}" />`,
|
|
30
|
+
` <script>window.location.replace("${to}");</script>`,
|
|
31
|
+
`</head>`,
|
|
32
|
+
`<body>`,
|
|
33
|
+
` <p>Redirectig to <a href="${to}">${to}</a>...</p>`,
|
|
34
|
+
`</body>`,
|
|
35
|
+
`</html>`,
|
|
36
|
+
];
|
|
37
|
+
return content.join("\n");
|
|
38
|
+
};
|
|
39
|
+
|
|
14
40
|
// @description press main function
|
|
15
41
|
// @param {Object} config - configuration object
|
|
16
42
|
// @param {String} config.source - source folder
|
|
@@ -41,6 +67,26 @@ press.createContext = (config = {}) => {
|
|
|
41
67
|
nodes: [],
|
|
42
68
|
actions: {},
|
|
43
69
|
});
|
|
70
|
+
// register helpers and funcions
|
|
71
|
+
context.template.addFunction("getPageUrl", params => {
|
|
72
|
+
return getNodeFromSource(params?.variables?.root?.site?.pages || [], params.args[0])?.url || "";
|
|
73
|
+
});
|
|
74
|
+
context.template.addFunction("getAssetUrl", params => {
|
|
75
|
+
return getNodeFromSource(params?.variables?.root?.site?.assets || [], params.args[0])?.url || "";
|
|
76
|
+
});
|
|
77
|
+
context.template.addHelper("pages", params => {
|
|
78
|
+
const draft = params?.options?.draft ?? params?.opt?.draft;
|
|
79
|
+
const collection = params?.opt?.collection || params?.options?.collection || null;
|
|
80
|
+
const items = (params.data?.site?.pages || []).filter(page => {
|
|
81
|
+
if (typeof draft === "boolean" && draft !== !!page?.attributes?.draft) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return !collection || page.attributes?.collection === collection;
|
|
85
|
+
});
|
|
86
|
+
const limit = Math.min(items.length, params.options?.limit || params.opt?.limit || items.length);
|
|
87
|
+
return items.slice(0, limit).reverse().map((c, i) => params.fn(c, {index: i})).join("");
|
|
88
|
+
});
|
|
89
|
+
// initialize plugins
|
|
44
90
|
getPlugins(context, "init").forEach(plugin => {
|
|
45
91
|
return plugin.init(context);
|
|
46
92
|
});
|
|
@@ -117,6 +163,18 @@ press.watchContext = (context, options = {}) => {
|
|
|
117
163
|
|
|
118
164
|
// @description general utilities
|
|
119
165
|
press.utils = {
|
|
166
|
+
// @description generate the md5 hash of the given content
|
|
167
|
+
// @param {String} content - content to hash
|
|
168
|
+
// @returns {String} md5 hash
|
|
169
|
+
md5: content => {
|
|
170
|
+
return crypto.createHash("md5").update(content).digest("hex");
|
|
171
|
+
},
|
|
172
|
+
// @description generate a random identifier
|
|
173
|
+
// @param {Number} length - length of the identifier
|
|
174
|
+
// @returns {String} random identifier
|
|
175
|
+
randomId: (length = 20) => {
|
|
176
|
+
return crypto.randomBytes(Math.ceil(length / 2)).toString("hex").slice(0, length);
|
|
177
|
+
},
|
|
120
178
|
// @description read a file from disk
|
|
121
179
|
// @param {String} file path to the file to read
|
|
122
180
|
read: (file, encoding = "utf8") => {
|
|
@@ -149,6 +207,26 @@ press.utils = {
|
|
|
149
207
|
.filter(file => (extensions === "*" || extensions.includes(path.extname(file))) && !exclude.includes(file))
|
|
150
208
|
.filter(file => fs.statSync(path.join(folder, file)).isFile());
|
|
151
209
|
},
|
|
210
|
+
// @description walk through the given folder and get all files
|
|
211
|
+
// @params {String} folder folder to walk through
|
|
212
|
+
// @params {Array|String} extensions extensions to include. Default: "*"
|
|
213
|
+
walkdir: (folder, extensions = "*", exclude = []) => {
|
|
214
|
+
const walkSync = (currentFolder, files = []) => {
|
|
215
|
+
const fullFolderPath = path.join(folder, currentFolder);
|
|
216
|
+
fs.readdirSync(fullFolderPath).forEach(file => {
|
|
217
|
+
const filePath = path.join(currentFolder, file);
|
|
218
|
+
const fullFilePath = path.join(fullFolderPath, file);
|
|
219
|
+
if (fs.statSync(fullFilePath).isDirectory()) {
|
|
220
|
+
return walkSync(filePath, files);
|
|
221
|
+
}
|
|
222
|
+
if (extensions === "*" || extensions.includes(path.extname(file))) {
|
|
223
|
+
files.push(filePath);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
return files;
|
|
227
|
+
};
|
|
228
|
+
return walkSync("./", []);
|
|
229
|
+
},
|
|
152
230
|
// @description watch for file changes
|
|
153
231
|
// @param {String} filePath path to the file to watch
|
|
154
232
|
// @param {Function} listener method to listen for file changes
|
|
@@ -199,7 +277,6 @@ press.SourcePlugin = (options = {}) => {
|
|
|
199
277
|
source: path.join(folder, file),
|
|
200
278
|
label: options.label || press.LABEL_PAGE,
|
|
201
279
|
path: path.join(options?.basePath || ".", file),
|
|
202
|
-
url: path.normalize("/" + path.join(options?.basePath || ".", file)),
|
|
203
280
|
};
|
|
204
281
|
});
|
|
205
282
|
},
|
|
@@ -273,10 +350,7 @@ press.FrontmatterPlugin = () => {
|
|
|
273
350
|
node.content = result.body || "";
|
|
274
351
|
node.attributes = result.attributes || {};
|
|
275
352
|
node.title = node.attributes?.title || node.path;
|
|
276
|
-
|
|
277
|
-
node.path = node.attributes.permalink;
|
|
278
|
-
node.url = path.normalize("/" + node.path);
|
|
279
|
-
}
|
|
353
|
+
node.path = node.attributes?.permalink || node.path;
|
|
280
354
|
}
|
|
281
355
|
},
|
|
282
356
|
};
|
|
@@ -324,6 +398,15 @@ press.ContentPagePlugin = (siteData = {}) => {
|
|
|
324
398
|
}
|
|
325
399
|
});
|
|
326
400
|
}
|
|
401
|
+
// 5. fix pages and assets variables
|
|
402
|
+
[...siteData.pages, ...siteData.assets].forEach(node => {
|
|
403
|
+
return Object.assign(node, {
|
|
404
|
+
ext: path.extname(node.path),
|
|
405
|
+
name: path.basename(node.path, path.extname(node.path)),
|
|
406
|
+
dir: path.dirname(node.path),
|
|
407
|
+
url: path.normalize(path.join("/", node.path)),
|
|
408
|
+
});
|
|
409
|
+
});
|
|
327
410
|
},
|
|
328
411
|
transform: (context, node) => {
|
|
329
412
|
if (node.label === press.LABEL_PAGE && typeof node.content === "string") {
|
|
@@ -343,19 +426,34 @@ press.UsePlugin = mikelPlugin => {
|
|
|
343
426
|
};
|
|
344
427
|
|
|
345
428
|
// @description copy plugin
|
|
346
|
-
press.CopyAssetsPlugin = (options = {}) => {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
};
|
|
429
|
+
press.CopyAssetsPlugin = (options = {}) => ({
|
|
430
|
+
name: "CopyAssetsPlugin",
|
|
431
|
+
load: () => {
|
|
432
|
+
const filesToCopy = (options?.patterns || []).filter(item => {
|
|
433
|
+
return item.from && fs.existsSync(path.resolve(item.from));
|
|
434
|
+
});
|
|
435
|
+
return filesToCopy.map(item => {
|
|
436
|
+
return {
|
|
437
|
+
source: path.resolve(item.from),
|
|
438
|
+
path: path.join(options?.basePath || ".", item.to || path.basename(item.from)),
|
|
439
|
+
label: options?.label || press.LABEL_ASSET,
|
|
440
|
+
};
|
|
441
|
+
});
|
|
442
|
+
},
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
// @description redirections plugin
|
|
446
|
+
press.RedirectsPlugin = (options = {}) => ({
|
|
447
|
+
name: "RedirectsPlugin",
|
|
448
|
+
load: () => {
|
|
449
|
+
return (options.redirects || []).map(redirection => ({
|
|
450
|
+
source: redirection.from,
|
|
451
|
+
path: path.join(options?.basePath || ".", redirection.from),
|
|
452
|
+
label: press.LABEL_ASSET,
|
|
453
|
+
content: generateRedirectHTML(redirection.to),
|
|
454
|
+
}));
|
|
455
|
+
},
|
|
456
|
+
});
|
|
359
457
|
|
|
360
458
|
// export press generator
|
|
361
459
|
export default press;
|