@rettangoli/sites 1.0.0-rc1 → 1.0.0-rc3

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 CHANGED
@@ -115,10 +115,14 @@ Available in YAML templates/pages without extra setup:
115
115
  - `jsonStringify(value, space = 0)`
116
116
  - `formatDate(value, format = "YYYYMMDDHHmmss", useUtc = true)`
117
117
  - `now(format = "YYYYMMDDHHmmss", useUtc = true)`
118
+ - `sort(list, key, order = "asc")`
119
+ - `md(content)`
118
120
  - `toQueryString(object)`
119
121
 
120
122
  `formatDate` tokens: `YYYY`, `MM`, `DD`, `HH`, `mm`, `ss`.
121
123
  `decodeURI`/`decodeURIComponent` return the original input when decoding fails.
124
+ `sort` supports `order` as `asc` or `desc` and returns a new array.
125
+ `md` returns raw rendered HTML from Markdown for template insertion.
122
126
 
123
127
  ## Screenshots
124
128
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rettangoli/sites",
3
- "version": "1.0.0-rc1",
3
+ "version": "1.0.0-rc3",
4
4
  "description": "Generate static sites using Markdown and YAML for docs, blogs, and marketing sites.",
5
5
  "author": {
6
6
  "name": "Luciano Hanyon Wu",
@@ -1,3 +1,7 @@
1
+ import MarkdownIt from 'markdown-it';
2
+
3
+ const markdownRenderer = new MarkdownIt();
4
+
1
5
  function toDate(value) {
2
6
  if (value instanceof Date) {
3
7
  return value;
@@ -71,6 +75,48 @@ function safeDecode(value, decoder) {
71
75
  }
72
76
  }
73
77
 
78
+ function sortImpl(value, key, order = 'asc') {
79
+ if (!Array.isArray(value)) {
80
+ return [];
81
+ }
82
+ const normalizedOrder = String(order ?? 'asc').toLowerCase() === 'desc' ? 'desc' : 'asc';
83
+ const factor = normalizedOrder === 'asc' ? 1 : -1;
84
+ return [...value].sort((left, right) => {
85
+ const leftRaw = key == null ? left : left?.[key];
86
+ const rightRaw = key == null ? right : right?.[key];
87
+
88
+ if (leftRaw == null && rightRaw == null) return 0;
89
+ if (leftRaw == null) return 1;
90
+ if (rightRaw == null) return -1;
91
+
92
+ const leftDate = Date.parse(String(leftRaw));
93
+ const rightDate = Date.parse(String(rightRaw));
94
+ const canCompareAsDate = !Number.isNaN(leftDate) && !Number.isNaN(rightDate);
95
+
96
+ if (canCompareAsDate) {
97
+ if (leftDate === rightDate) return 0;
98
+ return leftDate > rightDate ? factor : -factor;
99
+ }
100
+
101
+ if (typeof leftRaw === 'number' && typeof rightRaw === 'number') {
102
+ if (leftRaw === rightRaw) return 0;
103
+ return leftRaw > rightRaw ? factor : -factor;
104
+ }
105
+
106
+ const leftText = String(leftRaw);
107
+ const rightText = String(rightRaw);
108
+ const result = leftText.localeCompare(rightText);
109
+ if (result === 0) return 0;
110
+ return result > 0 ? factor : -factor;
111
+ });
112
+ }
113
+
114
+ function mdImpl(content) {
115
+ return {
116
+ __html: markdownRenderer.render(String(content ?? '')),
117
+ };
118
+ }
119
+
74
120
  export const builtinTemplateFunctions = {
75
121
  encodeURI: (value) => encodeURI(String(value ?? '')),
76
122
  encodeURIComponent: (value) => encodeURIComponent(String(value ?? '')),
@@ -79,6 +125,8 @@ export const builtinTemplateFunctions = {
79
125
  jsonStringify,
80
126
  formatDate: formatDateImpl,
81
127
  now: (format = 'YYYYMMDDHHmmss', useUtc = true) => formatDateImpl(new Date(), format, useUtc),
128
+ sort: sortImpl,
129
+ md: mdImpl,
82
130
  toQueryString,
83
131
  };
84
132
 
package/src/cli/watch.js CHANGED
@@ -54,6 +54,25 @@ export function createClientScript(reloadMode = 'body') {
54
54
  `;
55
55
  }
56
56
 
57
+ export function getContentType(ext) {
58
+ const types = {
59
+ '.html': 'text/html; charset=utf-8',
60
+ '.css': 'text/css; charset=utf-8',
61
+ '.js': 'application/javascript; charset=utf-8',
62
+ '.json': 'application/json; charset=utf-8',
63
+ '.txt': 'text/plain; charset=utf-8',
64
+ '.md': 'text/plain; charset=utf-8',
65
+ '.png': 'image/png',
66
+ '.jpg': 'image/jpeg',
67
+ '.jpeg': 'image/jpeg',
68
+ '.gif': 'image/gif',
69
+ '.svg': 'image/svg+xml',
70
+ '.ico': 'image/x-icon',
71
+ '.webp': 'image/webp'
72
+ };
73
+ return types[ext] || 'application/octet-stream';
74
+ }
75
+
57
76
  function createLogger(quiet = false) {
58
77
  return {
59
78
  log: (...args) => {
@@ -163,7 +182,7 @@ class DevServer {
163
182
 
164
183
  serveFile(filePath, res) {
165
184
  const ext = path.extname(filePath);
166
- const contentType = this.getContentType(ext);
185
+ const contentType = getContentType(ext);
167
186
 
168
187
  try {
169
188
  let content = fs.readFileSync(filePath);
@@ -181,7 +200,11 @@ class DevServer {
181
200
  }
182
201
  }
183
202
 
184
- res.writeHead(200, { 'Content-Type': contentType });
203
+ const headers = { 'Content-Type': contentType };
204
+ if (ext === '.md' || ext === '.txt') {
205
+ headers['Content-Disposition'] = 'inline';
206
+ }
207
+ res.writeHead(200, headers);
185
208
  res.end(content);
186
209
  } catch (err) {
187
210
  this.logger.error('Error serving file:', err);
@@ -190,21 +213,6 @@ class DevServer {
190
213
  }
191
214
  }
192
215
 
193
- getContentType(ext) {
194
- const types = {
195
- '.html': 'text/html',
196
- '.css': 'text/css',
197
- '.js': 'application/javascript',
198
- '.json': 'application/json',
199
- '.png': 'image/png',
200
- '.jpg': 'image/jpeg',
201
- '.gif': 'image/gif',
202
- '.svg': 'image/svg+xml',
203
- '.ico': 'image/x-icon'
204
- };
205
- return types[ext] || 'application/octet-stream';
206
- }
207
-
208
216
  reloadAll() {
209
217
  // Send a simple reload command to all clients
210
218
  const message = JSON.stringify({
@@ -227,10 +227,14 @@ Use these directly in `${...}` expressions:
227
227
  - `jsonStringify(value, space = 0)`
228
228
  - `formatDate(value, format = "YYYYMMDDHHmmss", useUtc = true)`
229
229
  - `now(format = "YYYYMMDDHHmmss", useUtc = true)`
230
+ - `sort(list, key, order = "asc")`
231
+ - `md(content)`
230
232
  - `toQueryString(object)`
231
233
 
232
234
  Date format tokens: `YYYY`, `MM`, `DD`, `HH`, `mm`, `ss`.
233
235
  `decodeURI`/`decodeURIComponent` return the original input when decoding fails.
236
+ `sort` supports `order` as `asc` or `desc` and returns a new array.
237
+ `md` returns raw rendered HTML from Markdown for template insertion.
234
238
 
235
239
  ## Static Files
236
240