@moonwave99/goffre 0.0.4 → 0.0.5

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.
Files changed (2) hide show
  1. package/lib/goffre.js +246 -228
  2. package/package.json +1 -1
package/lib/goffre.js CHANGED
@@ -17,281 +17,299 @@ const DEFAULT_DATA_PATH = path.join(process.cwd(), "data");
17
17
  const DEFAULT_VIEWS_PATH = path.join(process.cwd(), "src", "views");
18
18
  const DEFAULT_BUILD_PATH = path.join(process.cwd(), "dist");
19
19
  const MAX_SLUG_LOG_LENGTH = 40;
20
+ const DEFAULT_BLOCK_SEPARATOR = "<!-- block -->";
20
21
 
21
22
  function log() {
22
- console.log.apply(
23
- null,
24
- ["[goffre]", ...arguments].map((x) => chalk.cyan(x))
25
- );
23
+ console.log.apply(
24
+ null,
25
+ ["[goffre]", ...arguments].map((x) => chalk.cyan(x)),
26
+ );
26
27
  }
27
28
 
28
29
  function getEnv() {
29
- return {
30
- mode: process.env.MODE || "dev",
31
- };
30
+ return {
31
+ mode: process.env.MODE || "dev",
32
+ };
32
33
  }
33
34
 
34
35
  function stringify(token) {
35
- if (token instanceof Date) {
36
- return token.toISOString().split("T")[0];
37
- }
38
- return token;
36
+ if (token instanceof Date) {
37
+ return token.toISOString().split("T")[0];
38
+ }
39
+ return token;
39
40
  }
40
41
 
41
42
  export function getSlug(slug, params) {
42
- return slug
43
- .split("/")
44
- .reduce(
45
- (memo, x) =>
46
- !x.startsWith(":")
47
- ? [...memo, x]
48
- : [
49
- ...memo,
50
- slugify(stringify(params[x.slice(1)]), {
51
- lower: true,
52
- strict: true,
53
- }),
54
- ],
55
- []
56
- )
57
- .join("/");
43
+ return slug
44
+ .split("/")
45
+ .reduce(
46
+ (memo, x) =>
47
+ !x.startsWith(":")
48
+ ? [...memo, x]
49
+ : [
50
+ ...memo,
51
+ slugify(stringify(params[x.slice(1)]), {
52
+ lower: true,
53
+ strict: true,
54
+ }),
55
+ ],
56
+ [],
57
+ )
58
+ .join("/");
58
59
  }
59
60
 
60
61
  export function getTemplate({ page, templates, defaultTemplate = "_default" }) {
61
- if (page.template) {
62
- return page.template;
63
- }
64
- if (templates.find((x) => x.startsWith(page.slug))) {
65
- return page.slug;
66
- }
67
- return defaultTemplate;
62
+ if (page.template) {
63
+ return page.template;
64
+ }
65
+ if (templates.find((x) => x.startsWith(page.slug))) {
66
+ return page.slug;
67
+ }
68
+ return defaultTemplate;
68
69
  }
69
70
 
70
- function renderPage({ app, templates, buildPath, maxSlugLogLength, ...page }) {
71
- return new Promise((resolve, reject) => {
72
- const template = getTemplate({ page, templates });
71
+ function renderPage({
72
+ app,
73
+ templates,
74
+ buildPath,
75
+ maxSlugLogLength,
76
+ blockSeparator,
77
+ ...page
78
+ }) {
79
+ return new Promise((resolve, reject) => {
80
+ const template = getTemplate({ page, templates });
81
+
82
+ switch (app.locals.options.logLevel) {
83
+ case "silent":
84
+ break;
85
+ case "verbose":
86
+ log(
87
+ `Generating ${chalk.yellow(
88
+ page.slug.padEnd(maxSlugLogLength, " "),
89
+ )} with template ${chalk.green(template)}...`,
90
+ );
91
+ break;
92
+ case "normal":
93
+ default:
94
+ log(`Generating ${chalk.yellow(page.slug)}...`);
95
+ }
73
96
 
74
- switch (app.locals.options.logLevel) {
75
- case "silent":
76
- break;
77
- case "verbose":
78
- log(
79
- `Generating ${chalk.yellow(
80
- page.slug.padEnd(maxSlugLogLength, " ")
81
- )} with template ${chalk.green(template)}...`
82
- );
83
- break;
84
- case "normal":
85
- default:
86
- log(`Generating ${chalk.yellow(page.slug)}...`);
97
+ app.render(
98
+ template,
99
+ {
100
+ ...page,
101
+ layout: typeof page.layout === "undefined" ? "main" : page.layout,
102
+ content: page.content ? marked.parse(page.content) : null,
103
+ blocks: getPageBlocks(page.content, blockSeparator),
104
+ },
105
+ async (error, html) => {
106
+ if (error) {
107
+ reject(error);
108
+ return;
87
109
  }
110
+ const outputFileName = `${page.slug}${page.extname || ".html"}`;
111
+ await outputFile(path.join(buildPath, outputFileName), html);
112
+ resolve({
113
+ ...page,
114
+ outputFileName,
115
+ });
116
+ },
117
+ );
118
+ });
119
+ }
88
120
 
89
- app.render(
90
- template,
91
- {
92
- ...page,
93
- layout:
94
- typeof page.layout === "undefined" ? "main" : page.layout,
95
- content: page.content ? marked.parse(page.content) : null,
96
- },
97
- async (error, html) => {
98
- if (error) {
99
- reject(error);
100
- return;
101
- }
102
- const outputFileName = `${page.slug}${page.extname || ".html"}`;
103
- await outputFile(path.join(buildPath, outputFileName), html);
104
- resolve({
105
- ...page,
106
- outputFileName,
107
- });
108
- }
109
- );
110
- });
121
+ function getPageBlocks(content = "", separator) {
122
+ if (!content.includes(separator)) {
123
+ return [];
124
+ }
125
+ const blocks = content.split(separator).map((x) => marked.parse(x));
126
+ return blocks.filter(Boolean);
111
127
  }
112
128
 
113
129
  export async function load({ dataPath } = {}) {
114
- return {
115
- json: await loadJSON(dataPath || DEFAULT_DATA_PATH),
116
- pages: await loadMarkdown(dataPath || DEFAULT_DATA_PATH),
117
- };
130
+ return {
131
+ json: await loadJSON(dataPath || DEFAULT_DATA_PATH),
132
+ pages: await loadMarkdown(dataPath || DEFAULT_DATA_PATH),
133
+ };
118
134
  }
119
135
 
120
136
  export async function loadJSON(cwd) {
121
- const files = await globby("**/*.json", { cwd });
122
- return files.reduce(
123
- (memo, x) => ({
124
- ...memo,
125
- [path.basename(x, ".json")]: require(path.join(cwd, x)),
126
- }),
127
- {}
128
- );
137
+ const files = await globby("**/*.json", { cwd });
138
+ return files.reduce(
139
+ (memo, x) => ({
140
+ ...memo,
141
+ [path.basename(x, ".json")]: require(path.join(cwd, x)),
142
+ }),
143
+ {},
144
+ );
129
145
  }
130
146
 
131
147
  function excerpt(file) {
132
- file.excerpt = file.content.split("\n")[1];
148
+ file.excerpt = file.content.split("\n")[1];
133
149
  }
134
150
 
135
151
  export async function loadMarkdown(cwd) {
136
- const files = await globby("**/*.md", { cwd });
137
- return Promise.all(
138
- files.map(async (fileName) => {
139
- const fullPath = path.join(cwd, fileName);
140
- const contents = await readFile(fullPath, "utf-8");
141
- const parsed = matter(contents, { excerpt });
142
- const outputFileName = fileName.replace(".md", "");
143
- const slug = !parsed.data.slug
144
- ? outputFileName
145
- : getSlug(parsed.data.slug, parsed.data);
146
- return {
147
- ...parsed.data,
148
- excerpt: parsed.excerpt,
149
- slug,
150
- description: parsed.data.description || parsed.excerpt,
151
- content: parsed.content,
152
- };
153
- })
154
- );
152
+ const files = await globby("**/*.md", { cwd });
153
+ return Promise.all(
154
+ files.map(async (fileName) => {
155
+ const fullPath = path.join(cwd, fileName);
156
+ const contents = await readFile(fullPath, "utf-8");
157
+ const parsed = matter(contents, { excerpt });
158
+ const outputFileName = fileName.replace(".md", "");
159
+ const slug = !parsed.data.slug
160
+ ? outputFileName
161
+ : getSlug(parsed.data.slug, parsed.data);
162
+ return {
163
+ ...parsed.data,
164
+ excerpt: parsed.excerpt,
165
+ slug,
166
+ description: parsed.data.description || parsed.excerpt,
167
+ content: parsed.content,
168
+ };
169
+ }),
170
+ );
155
171
  }
156
172
 
157
173
  export const getSorter =
158
- ({ sortBy, order }) =>
159
- (a, b) => {
160
- let output;
161
- if (a[sortBy] instanceof Date) {
162
- output = new Date(a[sortBy]) - new Date(b[sortBy]);
163
- } else {
164
- output = a[sortBy] - b[sortBy];
165
- }
166
- return order === "desc" ? -output : output;
167
- };
174
+ ({ sortBy, order }) =>
175
+ (a, b) => {
176
+ let output;
177
+ if (a[sortBy] instanceof Date) {
178
+ output = new Date(a[sortBy]) - new Date(b[sortBy]);
179
+ } else {
180
+ output = a[sortBy] - b[sortBy];
181
+ }
182
+ return order === "desc" ? -output : output;
183
+ };
168
184
 
169
185
  export async function render({
170
- pages,
171
- viewsPath = DEFAULT_VIEWS_PATH,
172
- buildPath = DEFAULT_BUILD_PATH,
173
- domain,
174
- uglyUrls = false,
175
- logLevel = "normal",
176
- locals = {},
177
- markdown = {},
178
- handlebars = {},
179
- sitemap = {},
180
- env = {},
186
+ pages,
187
+ viewsPath = DEFAULT_VIEWS_PATH,
188
+ buildPath = DEFAULT_BUILD_PATH,
189
+ blockSeparator = DEFAULT_BLOCK_SEPARATOR,
190
+ domain,
191
+ uglyUrls = false,
192
+ logLevel = "normal",
193
+ locals = {},
194
+ markdown = {},
195
+ handlebars = {},
196
+ sitemap = {},
197
+ env = {},
181
198
  }) {
182
- const extname = handlebars.extname || ".handlebars";
183
- const app = express();
184
- app.engine(
185
- extname,
186
- engine({
187
- ...handlebars,
188
- helpers: {
189
- ...defaultHelpers,
190
- ...handlebars.helpers,
191
- },
192
- })
193
- );
194
- app.set("view engine", "handlebars");
195
- app.set("layoutsDir", path.join(viewsPath, "layouts"));
196
- app.set("views", viewsPath);
199
+ const extname = handlebars.extname || ".handlebars";
200
+ const app = express();
201
+ app.engine(
202
+ extname,
203
+ engine({
204
+ ...handlebars,
205
+ helpers: {
206
+ ...defaultHelpers,
207
+ ...handlebars.helpers,
208
+ },
209
+ }),
210
+ );
211
+ app.set("view engine", "handlebars");
212
+ app.set("layoutsDir", path.join(viewsPath, "layouts"));
213
+ app.set("views", viewsPath);
197
214
 
198
- const templates = await globby(`**/*${extname}`, {
199
- cwd: viewsPath,
200
- });
215
+ const templates = await globby(`**/*${extname}`, {
216
+ cwd: viewsPath,
217
+ });
201
218
 
202
- app.locals = {
203
- ...app.locals,
204
- ...locals,
205
- options: {
206
- domain,
207
- uglyUrls,
208
- logLevel,
209
- },
210
- env: { ...getEnv(), ...env },
211
- };
219
+ app.locals = {
220
+ ...app.locals,
221
+ ...locals,
222
+ options: {
223
+ domain,
224
+ uglyUrls,
225
+ logLevel,
226
+ },
227
+ env: { ...getEnv(), ...env },
228
+ };
212
229
 
213
- marked.use(markdown);
230
+ marked.use(markdown);
214
231
 
215
- switch (logLevel) {
216
- case "silent":
217
- break;
218
- case "verbose":
219
- case "normal":
220
- default:
221
- log(`Start generation...`);
222
- }
232
+ switch (logLevel) {
233
+ case "silent":
234
+ break;
235
+ case "verbose":
236
+ case "normal":
237
+ default:
238
+ log(`Start generation...`);
239
+ }
223
240
 
224
- const results = await Promise.all(
225
- pages.map((x) =>
226
- renderPage({
227
- ...x,
228
- buildPath,
229
- app,
230
- templates,
231
- maxSlugLogLength: Math.min(
232
- Math.max.call(null, ...pages.map((x) => x.slug.length)),
233
- MAX_SLUG_LOG_LENGTH
234
- ),
235
- })
236
- )
237
- );
241
+ const results = await Promise.all(
242
+ pages.map((x) =>
243
+ renderPage({
244
+ ...x,
245
+ buildPath,
246
+ app,
247
+ templates,
248
+ blockSeparator,
249
+ maxSlugLogLength: Math.min(
250
+ Math.max.call(null, ...pages.map((x) => x.slug.length)),
251
+ MAX_SLUG_LOG_LENGTH,
252
+ ),
253
+ }),
254
+ ),
255
+ );
238
256
 
239
- switch (logLevel) {
240
- case "silent":
241
- break;
242
- case "verbose":
243
- case "normal":
244
- default:
245
- log(`Generated ${results.length} pages`);
246
- }
257
+ switch (logLevel) {
258
+ case "silent":
259
+ break;
260
+ case "verbose":
261
+ case "normal":
262
+ default:
263
+ log(`Generated ${results.length} pages`);
264
+ }
247
265
 
248
- if (sitemap.generate) {
249
- renderPage({
250
- slug: "sitemap",
251
- template: sitemap.template || "sitemap",
252
- extname: ".xml",
253
- layout: null,
254
- pages: results,
255
- buildPath,
256
- app,
257
- templates,
258
- });
259
- }
266
+ if (sitemap.generate) {
267
+ renderPage({
268
+ slug: "sitemap",
269
+ template: sitemap.template || "sitemap",
270
+ extname: ".xml",
271
+ layout: null,
272
+ pages: results,
273
+ buildPath,
274
+ app,
275
+ templates,
276
+ });
277
+ }
260
278
 
261
- return results;
279
+ return results;
262
280
  }
263
281
 
264
282
  export function paginate({
265
- collection,
266
- size = 10,
267
- sortBy = "slug",
268
- order = "asc",
283
+ collection,
284
+ size = 10,
285
+ sortBy = "slug",
286
+ order = "asc",
269
287
  }) {
270
- const total = Math.ceil(collection.length / size);
271
- return collection
272
- .sort(getSorter({ sortBy, order }))
273
- .reduce((memo, x, index) => {
274
- if (index % size === 0) {
275
- const page = Math.floor(index / size) + 1;
276
- return [
277
- ...memo,
278
- {
279
- pagination: {
280
- page,
281
- prev: page > 1 ? page - 1 : null,
282
- next: page < total ? page + 1 : null,
283
- total,
284
- },
285
- items: [x],
286
- },
287
- ];
288
- }
289
- return [
290
- ...memo.slice(0, -1),
291
- {
292
- ...memo[memo.length - 1],
293
- items: [...memo[memo.length - 1].items, x],
294
- },
295
- ];
296
- }, []);
288
+ const total = Math.ceil(collection.length / size);
289
+ return collection
290
+ .sort(getSorter({ sortBy, order }))
291
+ .reduce((memo, x, index) => {
292
+ if (index % size === 0) {
293
+ const page = Math.floor(index / size) + 1;
294
+ return [
295
+ ...memo,
296
+ {
297
+ pagination: {
298
+ page,
299
+ prev: page > 1 ? page - 1 : null,
300
+ next: page < total ? page + 1 : null,
301
+ total,
302
+ },
303
+ items: [x],
304
+ },
305
+ ];
306
+ }
307
+ return [
308
+ ...memo.slice(0, -1),
309
+ {
310
+ ...memo[memo.length - 1],
311
+ items: [...memo[memo.length - 1].items, x],
312
+ },
313
+ ];
314
+ }, []);
297
315
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moonwave99/goffre",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Mini static site generator",
5
5
  "author": {
6
6
  "name": "Diego Caponera",