-
Notifications
You must be signed in to change notification settings - Fork 0
/
mod.ts
141 lines (109 loc) · 3.75 KB
/
mod.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import { cryptoRandomString } from "./deps.ts";
/**
* This function takes care of rendering the <deno> tag.
* @param {string} filePath - This is the path of the file to render.
* @returns {Promise<string>}
*/
async function render(filePath: string, data?: Record<string, unknown>): Promise<string> {
if (!Deno.statSync(filePath))
throw new Error(`The file with the path "${filePath}" does not exist!`);
/**
* create a utf-8 decoder
* @type {TextDecoder}
*/
const decoder: TextDecoder = new TextDecoder("utf-8");
/**
* Finds the position of the deno tag, either when it opens or closes.
* @param {string} file - The file to analyze.
* @param {string} tag - The tag to search for, either <deno> or </deno>.
* @param {number} pos - The last position that was reviewed.
* @returns {Promise<number>}
*/
async function searchTag(file: string, tag: string, pos: number): Promise<number> {
/**
* Gets the position of the tag.
* @type {number}
*/
const target: number = file.indexOf(tag, pos);
/**
* Gets the position when a comment was opened.
* @type {number}
*/
const openComment: number = file.indexOf("<!--", pos),
/**
* Gets the position when a comment was closed
* @type {number}
*/
closeComment: number = file.indexOf("-->", pos);
if (target < 0)
return -1;
else if ((openComment < target) && (target < closeComment))
return await searchTag(file, tag, (closeComment + 3));
return target;
}
const asyncFunction: FunctionConstructor = Object.getPrototypeOf(async function(){}).constructor;
return await (
/**
* This function is in charge of searching and rendering all deno tags.
* @param {string} file - This will be the file to return when rendering is finished.
* @returns {Promise<string>}
*/
async function lookingDeno(file: string): Promise<string> {
/**
* This is where the deno tag starts.
* @type {number}
*/
const open: number = await searchTag(file, "<deno>", 0);
if (open < 0) return file;
/**
* This is where the deno tag ends.
* @type {number}
*/
const close: number = await searchTag(file, "</deno>", 0);
if (close < 0) throw new Error("Unterminated deno tag!");
/**
* This creates a crypto.
* @type {string}
*/
const crypto: string = cryptoRandomString({
type: "alphanumeric",
length: 32
});
/**
* This is a variable with a random name, this to prevent someone external from modifying the values.
* @type {string}
*/
const privateVar = `a${crypto}z`;
/**
* This creates a function with the code to execute and receives the return.
* @type {string[]}
*/
const result: string[] = await new asyncFunction("data", `
/**
* This is the variable in charge of receiving and returning the changes in the html.
* @type {string[]}
*/
let ${privateVar} = [];
/**
* This function assigns a new value to the secret variable.
* @returns {void}
*/
function write(toWrite) {
${privateVar}.push(toWrite)
};
/**
* This function is responsible for executing the code declared in the deno tag.
* @returns {Promise<void> | void}
*/
await (async function main() {
${file.slice(open+6, close)}
})();
return ${privateVar};
`)(data);
return await lookingDeno(
file.replace(file.slice(open, close + 7), result.join("\n"))
);
}
)(decoder.decode(Deno.readFileSync(filePath)));
}
export default render;