First commit
This commit is contained in:
commit
de9567a36a
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
package-lock.json
|
|
@ -0,0 +1,44 @@
|
|||
let parser = require("./Parse");
|
||||
let crypto = require("node:crypto");
|
||||
let vm = require("node:vm");
|
||||
|
||||
module.exports = File;
|
||||
/**
|
||||
* @class File
|
||||
*/
|
||||
function File()
|
||||
{
|
||||
this.content = "";
|
||||
this.contentmd5 = "";
|
||||
this.parsedContent = "";
|
||||
this.cachedData = undefined;
|
||||
};
|
||||
|
||||
|
||||
function sha256(content)
|
||||
{
|
||||
return crypto.createHash("sha256").update(content,'utf-8').digest('hex');
|
||||
}
|
||||
|
||||
File.prototype.build = function(){
|
||||
this.contentmd5 = sha256(this.content);
|
||||
this.parsedContent = parser(this);
|
||||
};
|
||||
|
||||
File.prototype.isRequiredRebuild = function(content){
|
||||
return this.contentmd5 == sha256(content);
|
||||
};
|
||||
File.prototype.execute = function(memoriable){
|
||||
let output = [];
|
||||
let t = new vm.Script(this.parsedContent,{
|
||||
cachedData: this.cachedData,
|
||||
});
|
||||
let content = vm.createContext({
|
||||
...memoriable,
|
||||
output,
|
||||
echo:(...args) => output.push(...args)
|
||||
});
|
||||
t.runInContext(content);
|
||||
this.cachedData = t.createCachedData();
|
||||
return output.join('');
|
||||
};
|
|
@ -0,0 +1,347 @@
|
|||
let Hemex = require("@saqut/hemex");
|
||||
const File = require("./File");
|
||||
/**
|
||||
* @param {File} file
|
||||
*/
|
||||
function ParseEngine(file)
|
||||
{
|
||||
let content = [];
|
||||
let buffer = [];
|
||||
let hmx = new Hemex();
|
||||
hmx.setText(file.content);
|
||||
function flushBuffer()
|
||||
{
|
||||
if(buffer.length)
|
||||
{
|
||||
content.push({
|
||||
type:'text',
|
||||
value: buffer.join('')
|
||||
});
|
||||
}
|
||||
buffer=[];
|
||||
}
|
||||
hmx.addLexer({
|
||||
name: "scope"
|
||||
},()=>{
|
||||
hmx.while(()=>{
|
||||
if(hmx.include('{{'))
|
||||
{
|
||||
let doubleBrackContent = hmx.gather('double-brack');
|
||||
flushBuffer();
|
||||
content.push({
|
||||
type:'js-value',
|
||||
value: doubleBrackContent
|
||||
});
|
||||
return true;
|
||||
};
|
||||
if(hmx.include('@{'))
|
||||
{
|
||||
let jsBlockContent = hmx.gather('js-block');
|
||||
flushBuffer();
|
||||
content.push({
|
||||
type:'js-block',
|
||||
value: jsBlockContent
|
||||
});
|
||||
return true;
|
||||
};
|
||||
if(hmx.include('@if('))
|
||||
{
|
||||
let jsStatement = hmx.gather('js-if-block');
|
||||
flushBuffer();
|
||||
content.push({
|
||||
type:'js-if-block',
|
||||
value: jsStatement
|
||||
});
|
||||
return true;
|
||||
};
|
||||
if(hmx.include('@endif', true))
|
||||
{
|
||||
flushBuffer();
|
||||
content.push({
|
||||
type:'js-end-block'
|
||||
});
|
||||
return true;
|
||||
};
|
||||
if(hmx.include('@for('))
|
||||
{
|
||||
let jsStatement = hmx.gather('js-for-block');
|
||||
flushBuffer();
|
||||
content.push({
|
||||
type:'js-for-block',
|
||||
value: jsStatement
|
||||
});
|
||||
return true;
|
||||
};
|
||||
if(hmx.include('@import(', true))
|
||||
{
|
||||
let importedThing = hmx.gather('import');
|
||||
flushBuffer();
|
||||
content.push({
|
||||
type:'import',
|
||||
value: importedThing
|
||||
});
|
||||
return true;
|
||||
};
|
||||
if(hmx.include('@endfor', true))
|
||||
{
|
||||
flushBuffer();
|
||||
content.push({
|
||||
type:'js-end-block'
|
||||
});
|
||||
return true;
|
||||
};
|
||||
buffer.push(hmx.getChar());
|
||||
hmx.nextChar();
|
||||
return true;
|
||||
});
|
||||
flushBuffer();
|
||||
});
|
||||
hmx.addLexer({
|
||||
name: "js-block"
|
||||
},() => {
|
||||
hmx.beginPosition();
|
||||
if(hmx.include('@{'))
|
||||
{
|
||||
hmx.toChar(+2);
|
||||
};
|
||||
let script = hmx.gather('readjscontent','}');
|
||||
if(hmx.include('}'))
|
||||
{
|
||||
hmx.toChar(+1);
|
||||
};
|
||||
hmx.acceptPosition();
|
||||
return script;
|
||||
})
|
||||
|
||||
hmx.addLexer({
|
||||
name: "double-brack"
|
||||
},()=>{
|
||||
hmx.beginPosition();
|
||||
if(hmx.include('{{'))
|
||||
{
|
||||
hmx.toChar(+2);
|
||||
};
|
||||
let jsContent = hmx.gather('readjscontent', '}}');
|
||||
if(hmx.include('}}'))
|
||||
{
|
||||
hmx.toChar(+2);
|
||||
};
|
||||
hmx.acceptPosition();
|
||||
return jsContent;
|
||||
});
|
||||
|
||||
hmx.addLexer({
|
||||
name: "import"
|
||||
},()=>{
|
||||
hmx.beginPosition();
|
||||
if(hmx.include('@import('))
|
||||
{
|
||||
hmx.toChar(+8);
|
||||
};
|
||||
let jsContent = hmx.gather('readjscontent',')');
|
||||
if(hmx.include(')'))
|
||||
{
|
||||
hmx.toChar(+1);
|
||||
};
|
||||
hmx.acceptPosition();
|
||||
return jsContent;
|
||||
});
|
||||
|
||||
hmx.addLexer({
|
||||
name: "js-if-block"
|
||||
},()=>{
|
||||
hmx.beginPosition();
|
||||
if(hmx.include('@if('))
|
||||
{
|
||||
hmx.toChar(+4);
|
||||
};
|
||||
let jsContent = hmx.gather('readjscontent', ')');
|
||||
if(hmx.include(')'))
|
||||
{
|
||||
hmx.toChar(+2);
|
||||
};
|
||||
hmx.acceptPosition();
|
||||
return jsContent;
|
||||
});
|
||||
hmx.addLexer({
|
||||
name: "js-for-block"
|
||||
},()=>{
|
||||
hmx.beginPosition();
|
||||
if(hmx.include('@for('))
|
||||
{
|
||||
hmx.toChar(+5);
|
||||
};
|
||||
let jsContent = hmx.gather('readjscontent', ')');
|
||||
if(hmx.include(')'))
|
||||
{
|
||||
hmx.toChar(+1);
|
||||
};
|
||||
hmx.acceptPosition();
|
||||
return jsContent;
|
||||
});
|
||||
hmx.addLexer({
|
||||
name: "readjscontent"
|
||||
},(hmx, content)=>{
|
||||
hmx.beginPosition();
|
||||
let scopeLevel = 0;
|
||||
hmx.while(()=>{
|
||||
if(scopeLevel == 0)
|
||||
{
|
||||
if(content == null)
|
||||
{
|
||||
if(hmx.isWhiteSpace())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}else if(hmx.include(content))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
switch(hmx.getChar())
|
||||
{
|
||||
case '{':{
|
||||
scopeLevel++;
|
||||
hmx.nextChar();
|
||||
return true;
|
||||
}
|
||||
case '(':{
|
||||
scopeLevel++;
|
||||
hmx.nextChar();
|
||||
return true;
|
||||
}
|
||||
case '}':{
|
||||
scopeLevel = Math.max(scopeLevel - 1, 0);
|
||||
hmx.nextChar();
|
||||
return true;
|
||||
}
|
||||
case ')':{
|
||||
scopeLevel = Math.max(scopeLevel - 1, 0);
|
||||
hmx.nextChar();
|
||||
return true;
|
||||
}
|
||||
case '/':{
|
||||
if(hmx.include('//'))
|
||||
throw new Error("Çift parantezlerde yorum satırı kullanılamaz")
|
||||
else hmx.gather('skip-regex-content');
|
||||
return true;
|
||||
}
|
||||
case '\'':
|
||||
case '"':
|
||||
case '`':{
|
||||
hmx.gather('skip-string-content',hmx.getChar());
|
||||
return true;
|
||||
}
|
||||
default:{
|
||||
hmx.nextChar();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
});
|
||||
let jscontent = hmx.getPositionRange();
|
||||
hmx.acceptPosition();
|
||||
return jscontent;
|
||||
});
|
||||
hmx.addLexer({
|
||||
name: "skip-string-content"
|
||||
},(hmx, char)=>{
|
||||
hmx.beginPosition();
|
||||
if(hmx.isChar(char))
|
||||
{
|
||||
hmx.nextChar();
|
||||
}
|
||||
hmx.while(()=>{
|
||||
switch(hmx.getChar())
|
||||
{
|
||||
case '\\':{
|
||||
hmx.nextChar();
|
||||
hmx.nextChar();
|
||||
return true;
|
||||
}
|
||||
case char:{
|
||||
hmx.nextChar();
|
||||
return;
|
||||
}
|
||||
default:{
|
||||
hmx.nextChar();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
});
|
||||
hmx.acceptPosition();
|
||||
});
|
||||
hmx.addLexer({
|
||||
name: "skip-regex-content"
|
||||
},()=>{
|
||||
hmx.beginPosition();
|
||||
if(hmx.isChar('/'))
|
||||
{
|
||||
hmx.nextChar();
|
||||
};
|
||||
hmx.while(()=>{
|
||||
switch(hmx.getChar())
|
||||
{
|
||||
case '\\':{
|
||||
hmx.nextChar();
|
||||
hmx.nextChar();
|
||||
return true;
|
||||
}
|
||||
case '/':{
|
||||
hmx.nextChar();
|
||||
return false;
|
||||
}
|
||||
default:{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
});
|
||||
hmx.acceptPosition();
|
||||
});
|
||||
hmx.gather('scope');
|
||||
function useAST(content)
|
||||
{
|
||||
let jsContent = [];
|
||||
for (const {
|
||||
type,
|
||||
value
|
||||
} of content) switch(type)
|
||||
{
|
||||
case "js-value":{
|
||||
jsContent.push(`output.push(${value});\n`);
|
||||
break;
|
||||
}
|
||||
case "js-block":{
|
||||
jsContent.push(`\n${value}\n`);
|
||||
break;
|
||||
}
|
||||
case "text":{
|
||||
jsContent.push(`output.push(${JSON.stringify(value)});\n`);
|
||||
break;
|
||||
}
|
||||
case "import":{
|
||||
jsContent.push(`output.push(${JSON.stringify(`<!-- imported ${value}--->`)});\n`);
|
||||
break;
|
||||
}
|
||||
case "js-if-block":{
|
||||
jsContent.push(`if(${value}){\n`);
|
||||
break;
|
||||
}
|
||||
case "js-for-block":{
|
||||
jsContent.push(`for(${value}){\n`);
|
||||
break;
|
||||
}
|
||||
case "js-endif-block":{
|
||||
jsContent.push(`if(${value}){\n`);
|
||||
break;
|
||||
}
|
||||
case "js-end-block":{
|
||||
jsContent.push(`\n};\n`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return jsContent.join('');
|
||||
}
|
||||
return useAST(content);
|
||||
};
|
||||
|
||||
module.exports = ParseEngine;
|
|
@ -0,0 +1,14 @@
|
|||
const { readFile } = require("node:fs/promises");
|
||||
let {resolve} = require("node:path");
|
||||
|
||||
let File = require("./Processor/File");
|
||||
|
||||
exports.processFile = async path => {
|
||||
let absolute = resolve(path);
|
||||
let content = await readFile(absolute,"utf8");
|
||||
let file = new File();
|
||||
file.content = content;
|
||||
file.build();
|
||||
return file;
|
||||
};
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "razorblade",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "test.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@saqut/hemex": "^0.7.2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>
|
||||
{{ "Merhaba" }}
|
||||
</title>
|
||||
</head>
|
||||
<body>
|
||||
@import("merhaba")
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
|
@ -0,0 +1,5 @@
|
|||
output.push("<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <title>\r\n ");
|
||||
output.push( "Merhaba" );
|
||||
output.push("\r\n </title>\r\n</head>\r\n<body>\r\n ");
|
||||
output.push("<!-- imported \"merhaba\"--->");
|
||||
output.push("\r\n</body>\r\n</html>");
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>
|
||||
Merhaba
|
||||
</title>
|
||||
</head>
|
||||
<body>
|
||||
<!-- imported "merhaba"--->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,15 @@
|
|||
let parser = require("./init");
|
||||
let {writeFile} = require("node:fs/promises");
|
||||
|
||||
async function main()
|
||||
{
|
||||
let node = await parser.processFile("./source/abc.blade.php");
|
||||
await writeFile("./source/abc.blade.php.js", node.parsedContent, "utf8");
|
||||
let result = node.execute({
|
||||
ebilet: 25
|
||||
});
|
||||
await writeFile("./source/abc.blade.php.cache", node.cachedData, "utf8");
|
||||
await writeFile("./target/abc.html", result, "utf8");
|
||||
};
|
||||
|
||||
process.nextTick(main);
|
Reference in New Issue