ghtml 1.5.0 → 1.5.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 +18 -2
- package/package.json +2 -2
- package/src/html.js +69 -81
- package/src/includeFile.js +4 -6
- package/test.js +27 -0
package/README.md
CHANGED
|
@@ -86,10 +86,14 @@ import { htmlGenerator as html } from "ghtml";
|
|
|
86
86
|
import { Readable } from "node:stream";
|
|
87
87
|
import http from "node:http";
|
|
88
88
|
|
|
89
|
+
const generator = function* () {
|
|
90
|
+
yield "Hello, World!";
|
|
91
|
+
};
|
|
92
|
+
|
|
89
93
|
http
|
|
90
94
|
.createServer((req, res) => {
|
|
91
95
|
const htmlContent = html`<html>
|
|
92
|
-
<p>${
|
|
96
|
+
<p>${generator()}</p>
|
|
93
97
|
</html>`;
|
|
94
98
|
const readableStream = Readable.from(htmlContent);
|
|
95
99
|
res.writeHead(200, { "Content-Type": "text/html;charset=utf-8" });
|
|
@@ -102,14 +106,26 @@ http
|
|
|
102
106
|
|
|
103
107
|
```js
|
|
104
108
|
import { htmlAsyncGenerator as html } from "ghtml";
|
|
109
|
+
import { createReadStream } from "node:fs";
|
|
105
110
|
import { readFile } from "node:fs/promises";
|
|
106
111
|
import { Readable } from "node:stream";
|
|
107
112
|
import http from "node:http";
|
|
108
113
|
|
|
114
|
+
const asyncGenerator = async function* () {
|
|
115
|
+
const Hello = await new Promise((resolve) => {
|
|
116
|
+
setTimeout(() => {
|
|
117
|
+
resolve("Hello");
|
|
118
|
+
}, 1000);
|
|
119
|
+
});
|
|
120
|
+
yield `${Hello}!`;
|
|
121
|
+
};
|
|
122
|
+
|
|
109
123
|
http
|
|
110
124
|
.createServer((req, res) => {
|
|
111
125
|
const htmlContent = html`<html>
|
|
112
|
-
<
|
|
126
|
+
<p>${asyncGenerator()}</p>
|
|
127
|
+
<code>${readFile("./README.md", "utf8")}</code>
|
|
128
|
+
<code>${createReadStream("./README.md", "utf8")}</code>
|
|
113
129
|
</html>`;
|
|
114
130
|
const readableStream = Readable.from(htmlContent);
|
|
115
131
|
res.writeHead(200, { "Content-Type": "text/html;charset=utf-8" });
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Replace your template engine with fast JavaScript by leveraging the power of tagged templates.",
|
|
4
4
|
"author": "Gürgün Dayıoğlu",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "1.5.
|
|
6
|
+
"version": "1.5.1",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "./src/index.js",
|
|
9
9
|
"exports": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@fastify/pre-commit": "^2.1.0",
|
|
24
24
|
"c8": "^9.1.0",
|
|
25
|
-
"grules": "^0.
|
|
25
|
+
"grules": "^0.16.2",
|
|
26
26
|
"tinybench": "^2.6.0"
|
|
27
27
|
},
|
|
28
28
|
"repository": {
|
package/src/html.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const escapeDict = {
|
|
2
2
|
'"': """,
|
|
3
3
|
"'": "'",
|
|
4
4
|
"&": "&",
|
|
@@ -6,13 +6,10 @@ const escapeDictionary = {
|
|
|
6
6
|
">": ">",
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
const
|
|
10
|
-
`[${Object.keys(escapeDictionary).join("")}]`,
|
|
11
|
-
"gu",
|
|
12
|
-
);
|
|
9
|
+
const escapeRE = new RegExp(`[${Object.keys(escapeDict).join("")}]`, "gu");
|
|
13
10
|
|
|
14
|
-
const
|
|
15
|
-
return
|
|
11
|
+
const escapeFn = (key) => {
|
|
12
|
+
return escapeDict[key];
|
|
16
13
|
};
|
|
17
14
|
|
|
18
15
|
/**
|
|
@@ -26,7 +23,7 @@ const html = ({ raw: literals }, ...expressions) => {
|
|
|
26
23
|
|
|
27
24
|
for (; index !== expressions.length; ++index) {
|
|
28
25
|
let literal = literals[index];
|
|
29
|
-
let
|
|
26
|
+
let string =
|
|
30
27
|
expressions[index] === undefined || expressions[index] === null
|
|
31
28
|
? ""
|
|
32
29
|
: typeof expressions[index] === "string"
|
|
@@ -37,11 +34,11 @@ const html = ({ raw: literals }, ...expressions) => {
|
|
|
37
34
|
|
|
38
35
|
if (literal.length && literal.charCodeAt(literal.length - 1) === 33) {
|
|
39
36
|
literal = literal.slice(0, -1);
|
|
40
|
-
} else if (
|
|
41
|
-
|
|
37
|
+
} else if (string.length) {
|
|
38
|
+
string = string.replace(escapeRE, escapeFn);
|
|
42
39
|
}
|
|
43
40
|
|
|
44
|
-
accumulator += literal +
|
|
41
|
+
accumulator += literal + string;
|
|
45
42
|
}
|
|
46
43
|
|
|
47
44
|
return (accumulator += literals[index]);
|
|
@@ -57,14 +54,15 @@ const htmlGenerator = function* ({ raw: literals }, ...expressions) {
|
|
|
57
54
|
|
|
58
55
|
for (; index !== expressions.length; ++index) {
|
|
59
56
|
let literal = literals[index];
|
|
60
|
-
let expression;
|
|
57
|
+
let expression = expressions[index];
|
|
58
|
+
let string;
|
|
61
59
|
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
} else if (typeof
|
|
65
|
-
|
|
60
|
+
if (expression === undefined || expression === null) {
|
|
61
|
+
string = "";
|
|
62
|
+
} else if (typeof expression === "string") {
|
|
63
|
+
string = expression;
|
|
66
64
|
} else {
|
|
67
|
-
if (
|
|
65
|
+
if (expression[Symbol.iterator]) {
|
|
68
66
|
const isRaw =
|
|
69
67
|
literal.length !== 0 && literal.charCodeAt(literal.length - 1) === 33;
|
|
70
68
|
|
|
@@ -76,63 +74,60 @@ const htmlGenerator = function* ({ raw: literals }, ...expressions) {
|
|
|
76
74
|
yield literal;
|
|
77
75
|
}
|
|
78
76
|
|
|
79
|
-
for (
|
|
80
|
-
if (
|
|
77
|
+
for (expression of expression) {
|
|
78
|
+
if (expression === undefined || expression === null) {
|
|
81
79
|
continue;
|
|
82
|
-
}
|
|
83
|
-
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (typeof expression === "string") {
|
|
83
|
+
string = expression;
|
|
84
84
|
} else {
|
|
85
|
-
if (
|
|
86
|
-
for (
|
|
87
|
-
if (
|
|
85
|
+
if (expression[Symbol.iterator]) {
|
|
86
|
+
for (expression of expression) {
|
|
87
|
+
if (expression === undefined || expression === null) {
|
|
88
88
|
continue;
|
|
89
|
-
} else if (typeof innerValue === "string") {
|
|
90
|
-
expression = innerValue;
|
|
91
|
-
} else {
|
|
92
|
-
expression = `${innerValue}`;
|
|
93
89
|
}
|
|
94
90
|
|
|
95
|
-
|
|
91
|
+
string = `${expression}`;
|
|
92
|
+
|
|
93
|
+
if (string.length) {
|
|
96
94
|
if (!isRaw) {
|
|
97
|
-
|
|
98
|
-
escapeRegExp,
|
|
99
|
-
escapeFunction,
|
|
100
|
-
);
|
|
95
|
+
string = string.replace(escapeRE, escapeFn);
|
|
101
96
|
}
|
|
102
97
|
|
|
103
|
-
yield
|
|
98
|
+
yield string;
|
|
104
99
|
}
|
|
105
100
|
}
|
|
106
101
|
|
|
107
102
|
continue;
|
|
108
103
|
}
|
|
109
104
|
|
|
110
|
-
|
|
105
|
+
string = `${expression}`;
|
|
111
106
|
}
|
|
112
107
|
|
|
113
|
-
if (
|
|
108
|
+
if (string.length) {
|
|
114
109
|
if (!isRaw) {
|
|
115
|
-
|
|
110
|
+
string = string.replace(escapeRE, escapeFn);
|
|
116
111
|
}
|
|
117
112
|
|
|
118
|
-
yield
|
|
113
|
+
yield string;
|
|
119
114
|
}
|
|
120
115
|
}
|
|
121
116
|
|
|
122
117
|
continue;
|
|
123
118
|
}
|
|
124
119
|
|
|
125
|
-
|
|
120
|
+
string = `${expression}`;
|
|
126
121
|
}
|
|
127
122
|
|
|
128
123
|
if (literal.length && literal.charCodeAt(literal.length - 1) === 33) {
|
|
129
124
|
literal = literal.slice(0, -1);
|
|
130
|
-
} else if (
|
|
131
|
-
|
|
125
|
+
} else if (string.length) {
|
|
126
|
+
string = string.replace(escapeRE, escapeFn);
|
|
132
127
|
}
|
|
133
128
|
|
|
134
|
-
if (literal.length ||
|
|
135
|
-
yield literal +
|
|
129
|
+
if (literal.length || string.length) {
|
|
130
|
+
yield literal + string;
|
|
136
131
|
}
|
|
137
132
|
}
|
|
138
133
|
|
|
@@ -151,19 +146,15 @@ const htmlAsyncGenerator = async function* ({ raw: literals }, ...expressions) {
|
|
|
151
146
|
|
|
152
147
|
for (; index !== expressions.length; ++index) {
|
|
153
148
|
let literal = literals[index];
|
|
154
|
-
let expression;
|
|
155
|
-
|
|
156
|
-
expressions[index] = await expressions[index];
|
|
149
|
+
let expression = await expressions[index];
|
|
150
|
+
let string;
|
|
157
151
|
|
|
158
|
-
if (
|
|
159
|
-
|
|
160
|
-
} else if (typeof
|
|
161
|
-
|
|
152
|
+
if (expression === undefined || expression === null) {
|
|
153
|
+
string = "";
|
|
154
|
+
} else if (typeof expression === "string") {
|
|
155
|
+
string = expression;
|
|
162
156
|
} else {
|
|
163
|
-
if (
|
|
164
|
-
typeof expressions[index][Symbol.iterator] === "function" ||
|
|
165
|
-
typeof expressions[index][Symbol.asyncIterator] === "function"
|
|
166
|
-
) {
|
|
157
|
+
if (expression[Symbol.iterator] || expression[Symbol.asyncIterator]) {
|
|
167
158
|
const isRaw =
|
|
168
159
|
literal.length !== 0 && literal.charCodeAt(literal.length - 1) === 33;
|
|
169
160
|
|
|
@@ -175,66 +166,63 @@ const htmlAsyncGenerator = async function* ({ raw: literals }, ...expressions) {
|
|
|
175
166
|
yield literal;
|
|
176
167
|
}
|
|
177
168
|
|
|
178
|
-
for await (
|
|
179
|
-
if (
|
|
169
|
+
for await (expression of expression) {
|
|
170
|
+
if (expression === undefined || expression === null) {
|
|
180
171
|
continue;
|
|
181
|
-
}
|
|
182
|
-
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (typeof expression === "string") {
|
|
175
|
+
string = expression;
|
|
183
176
|
} else {
|
|
184
177
|
if (
|
|
185
|
-
|
|
186
|
-
|
|
178
|
+
expression[Symbol.iterator] ||
|
|
179
|
+
expression[Symbol.asyncIterator]
|
|
187
180
|
) {
|
|
188
|
-
for await (
|
|
189
|
-
if (
|
|
181
|
+
for await (expression of expression) {
|
|
182
|
+
if (expression === undefined || expression === null) {
|
|
190
183
|
continue;
|
|
191
|
-
} else if (typeof innerValue === "string") {
|
|
192
|
-
expression = innerValue;
|
|
193
|
-
} else {
|
|
194
|
-
expression = `${innerValue}`;
|
|
195
184
|
}
|
|
196
185
|
|
|
197
|
-
|
|
186
|
+
string = `${expression}`;
|
|
187
|
+
|
|
188
|
+
if (string.length) {
|
|
198
189
|
if (!isRaw) {
|
|
199
|
-
|
|
200
|
-
escapeRegExp,
|
|
201
|
-
escapeFunction,
|
|
202
|
-
);
|
|
190
|
+
string = string.replace(escapeRE, escapeFn);
|
|
203
191
|
}
|
|
204
192
|
|
|
205
|
-
yield
|
|
193
|
+
yield string;
|
|
206
194
|
}
|
|
207
195
|
}
|
|
208
196
|
|
|
209
197
|
continue;
|
|
210
198
|
}
|
|
211
199
|
|
|
212
|
-
|
|
200
|
+
string = `${expression}`;
|
|
213
201
|
}
|
|
214
202
|
|
|
215
|
-
if (
|
|
203
|
+
if (string.length) {
|
|
216
204
|
if (!isRaw) {
|
|
217
|
-
|
|
205
|
+
string = string.replace(escapeRE, escapeFn);
|
|
218
206
|
}
|
|
219
207
|
|
|
220
|
-
yield
|
|
208
|
+
yield string;
|
|
221
209
|
}
|
|
222
210
|
}
|
|
223
211
|
|
|
224
212
|
continue;
|
|
225
213
|
}
|
|
226
214
|
|
|
227
|
-
|
|
215
|
+
string = `${expression}`;
|
|
228
216
|
}
|
|
229
217
|
|
|
230
218
|
if (literal.length && literal.charCodeAt(literal.length - 1) === 33) {
|
|
231
219
|
literal = literal.slice(0, -1);
|
|
232
|
-
} else if (
|
|
233
|
-
|
|
220
|
+
} else if (string.length) {
|
|
221
|
+
string = string.replace(escapeRE, escapeFn);
|
|
234
222
|
}
|
|
235
223
|
|
|
236
|
-
if (literal.length ||
|
|
237
|
-
yield literal +
|
|
224
|
+
if (literal.length || string.length) {
|
|
225
|
+
yield literal + string;
|
|
238
226
|
}
|
|
239
227
|
}
|
|
240
228
|
|
package/src/includeFile.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
const fileCache = new Map();
|
|
3
|
+
const cache = new Map();
|
|
6
4
|
|
|
7
5
|
/**
|
|
8
6
|
* @param {string} path The path to the file to render.
|
|
9
7
|
* @returns {string} The cached content of the file.
|
|
10
8
|
*/
|
|
11
9
|
const includeFile = (path) => {
|
|
12
|
-
let file =
|
|
10
|
+
let file = cache.get(path);
|
|
13
11
|
|
|
14
12
|
if (file === undefined) {
|
|
15
|
-
file = readFileSync(path,
|
|
16
|
-
|
|
13
|
+
file = readFileSync(path, "utf8");
|
|
14
|
+
cache.set(path, file);
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
return file;
|
package/test.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { htmlAsyncGenerator as html } from "ghtml";
|
|
2
|
+
import { createReadStream } from "node:fs";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { Readable } from "node:stream";
|
|
5
|
+
import http from "node:http";
|
|
6
|
+
|
|
7
|
+
const asyncGenerator = async function* () {
|
|
8
|
+
const Hello = await new Promise((resolve) => {
|
|
9
|
+
setTimeout(() => {
|
|
10
|
+
resolve("Hello");
|
|
11
|
+
}, 1000);
|
|
12
|
+
});
|
|
13
|
+
yield `${Hello}!`;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
http
|
|
17
|
+
.createServer((req, res) => {
|
|
18
|
+
const htmlContent = html`<html>
|
|
19
|
+
<p>${asyncGenerator()}</p>
|
|
20
|
+
<code>${readFile("./README.md", "utf8")}</code>
|
|
21
|
+
<code>${createReadStream("./README.md", "utf8")}</code>
|
|
22
|
+
</html>`;
|
|
23
|
+
const readableStream = Readable.from(htmlContent);
|
|
24
|
+
res.writeHead(200, { "Content-Type": "text/html;charset=utf-8" });
|
|
25
|
+
readableStream.pipe(res);
|
|
26
|
+
})
|
|
27
|
+
.listen(3000);
|