feat: creat script for comple xshema #1
118
Complie-script/comple/comple-script.mjs
Normal file
118
Complie-script/comple/comple-script.mjs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { Lexer } from './lexer.mjs'; // 引入 Lexer 类
|
||||||
|
|
||||||
|
// 递归遍历项目目录
|
||||||
|
function findXSchemaDirectory(directoryPath) {
|
||||||
|
fs.readdir(directoryPath, (err, files) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('无法读取目录:', err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历目录中的所有文件和文件夹
|
||||||
|
files.forEach(file => {
|
||||||
|
const filePath = path.join(directoryPath, file);
|
||||||
|
|
||||||
|
fs.stat(filePath, (err, stats) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('无法获取文件状态:', err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.isDirectory()) {
|
||||||
|
// 如果是文件夹,检查是否为 xschema 文件夹
|
||||||
|
if (file === 'xschema') {
|
||||||
|
// 找到 xschema 文件夹,继续查找其中的 .xschema.tsx 文件
|
||||||
|
findXSchemaFiles(filePath);
|
||||||
|
} else {
|
||||||
|
// 如果是其他文件夹,递归调用
|
||||||
|
findXSchemaDirectory(filePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找 xschema 文件夹中的 .xschema.tsx 文件
|
||||||
|
function findXSchemaFiles(directoryPath) {
|
||||||
|
fs.readdir(directoryPath, (err, files) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('无法读取目录:', err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
files.forEach(file => {
|
||||||
|
const filePath = path.join(directoryPath, file);
|
||||||
|
|
||||||
|
// 如果是 .xschema.tsx 文件,进行处理
|
||||||
|
if (file.endsWith('.xschema.tsx')) {
|
||||||
|
processFile(filePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理找到的 .xschema.tsx 文件
|
||||||
|
function processFile(filePath) {
|
||||||
|
console.log('找到文件:', filePath);
|
||||||
|
|
||||||
|
// 读取文件内容
|
||||||
|
fs.readFile(filePath, 'utf8', (err, data) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('无法读取文件:', err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在这里创建一个 Lexer 实例并进行词法分析
|
||||||
|
const lexer = new Lexer(data); // 创建 Lexer 实例
|
||||||
|
const tokens = lexer.lex(); // 获取 tokens
|
||||||
|
|
||||||
|
// 打印出解析得到的 tokens,或者根据需要进行进一步处理
|
||||||
|
console.log('生成的 Tokens:', tokens);
|
||||||
|
// 进行编译
|
||||||
|
const compiledData = compileFile(data, tokens);
|
||||||
|
|
||||||
|
// 输出编译后的数据并保存为 .tsx 文件(去除 xschema 部分)
|
||||||
|
const outputFilePath = filePath.replace('.xschema.tsx', '.schema.ts'); // 输出文件名去除 xschema 部分,保留 .tsx 后缀
|
||||||
|
fs.writeFile(outputFilePath, compiledData, 'utf8', (err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('无法写入 TSX 文件:', err);
|
||||||
|
} else {
|
||||||
|
console.log('编译后的文件已保存:', outputFilePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function compileFile(fileContent, tokens) {
|
||||||
|
let compiledCode = '';
|
||||||
|
|
||||||
|
tokens.forEach(token => {
|
||||||
|
if (token === 'startTag') {
|
||||||
|
// 输出 'startTag' 标记
|
||||||
|
compiledCode += `Start Tag: ${tokens[1]} \n`;
|
||||||
|
|
||||||
|
// 输出属性
|
||||||
|
tokens[2].forEach(attr => {
|
||||||
|
const key = Object.keys(attr)[0]; // 获取属性名
|
||||||
|
const value = attr[key]; // 获取属性值
|
||||||
|
compiledCode += ` Attribute: ${key}="${value}" \n`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (token === 'endTag') {
|
||||||
|
// 输出 'endTag' 标记(如果有的话)
|
||||||
|
compiledCode += `End Tag: ${tokens[1]} \n`;
|
||||||
|
}
|
||||||
|
else if (token === 'text') {
|
||||||
|
// 输出文本内容
|
||||||
|
compiledCode += `Text: ${tokens[1]} \n`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return compiledCode; // 返回生成的简单 token 输出
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动程序并从根目录开始查找 xschema 文件夹
|
||||||
|
const projectRootDirectory = './'; // 设置项目根目录,通常为当前目录
|
||||||
|
findXSchemaDirectory(projectRootDirectory);
|
130
Complie-script/comple/lexer.mjs
Normal file
130
Complie-script/comple/lexer.mjs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
// lexer.mjs
|
||||||
|
import { token } from './token.mjs';
|
||||||
|
|
||||||
|
export class Lexer {
|
||||||
|
constructor(string) {
|
||||||
|
this.string = string;
|
||||||
|
this.pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
advance() {
|
||||||
|
return this.string[this.pos++];
|
||||||
|
}
|
||||||
|
|
||||||
|
lookAhead() {
|
||||||
|
return this.string[this.pos];
|
||||||
|
}
|
||||||
|
|
||||||
|
trimQuotes(str) {
|
||||||
|
return str.replace(/^['"]|['"]$/g, ''); // Remove surrounding quotes
|
||||||
|
}
|
||||||
|
|
||||||
|
lex() {
|
||||||
|
let text = '';
|
||||||
|
while (true) {
|
||||||
|
let t = this.advance();
|
||||||
|
let tokenResult = ''; // Renamed to avoid conflict with outer token variable
|
||||||
|
switch (t) {
|
||||||
|
case '<':
|
||||||
|
if (this.lookAhead() === '/') {
|
||||||
|
tokenResult = this.handleEndTag();
|
||||||
|
} else {
|
||||||
|
tokenResult = this.handleStartTag();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
if (text !== '') {
|
||||||
|
text += t;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case undefined:
|
||||||
|
if (this.pos >= this.string.length) {
|
||||||
|
tokenResult = [token.eof, 'eof', []];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
text += t;
|
||||||
|
tokenResult = this.handleTextTag(text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.string = this.string.slice(this.pos);
|
||||||
|
this.pos = 0;
|
||||||
|
if (tokenResult !== '') {
|
||||||
|
return tokenResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleStartTag() {
|
||||||
|
let idx = this.string.indexOf('>');
|
||||||
|
if (idx === -1) {
|
||||||
|
throw new Error('parse err! miss match ' + '>');
|
||||||
|
}
|
||||||
|
let str = this.string.slice(this.pos, idx);
|
||||||
|
let s = '';
|
||||||
|
if (str.includes(' ')) {
|
||||||
|
s = str.split(' ')[0]; // Fixed splitting logic
|
||||||
|
} else {
|
||||||
|
s = str;
|
||||||
|
}
|
||||||
|
let type = s.slice(1);
|
||||||
|
this.pos += type.length;
|
||||||
|
let props = this.handlePropTag();
|
||||||
|
this.advance();
|
||||||
|
return [token.startTag, type, props];
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePropTag() {
|
||||||
|
let idx = this.string.indexOf('>');
|
||||||
|
if (idx == -1) {
|
||||||
|
throw new Error('parse err! miss match ' + '>');
|
||||||
|
}
|
||||||
|
let string = this.string.slice(this.pos, idx);
|
||||||
|
let pm = [];
|
||||||
|
if (string.trim() != '') { // Checking if string is not empty
|
||||||
|
let props = string.split(' ');
|
||||||
|
pm = props.filter((prop) => {
|
||||||
|
return prop != '';
|
||||||
|
}).map((prop) => {
|
||||||
|
let kv = prop.split('=');
|
||||||
|
let o = {};
|
||||||
|
// Ensure kv[1] exists before calling trimQuotes
|
||||||
|
if (kv[1]) {
|
||||||
|
o[kv[0]] = this.trimQuotes(kv[1]);
|
||||||
|
} else {
|
||||||
|
o[kv[0]] = ''; // Or assign a default value
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
});
|
||||||
|
this.pos += string.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
handleEndTag() {
|
||||||
|
this.advance();
|
||||||
|
let idx = this.string.indexOf('>');
|
||||||
|
let type = this.string.slice(this.pos, idx);
|
||||||
|
this.pos += type.length;
|
||||||
|
if (this.advance() !== '>') {
|
||||||
|
throw new Error('parse err! miss match ' + '>');
|
||||||
|
}
|
||||||
|
return [token.endTag, type, []];
|
||||||
|
}
|
||||||
|
|
||||||
|
handleTextTag(text) {
|
||||||
|
let t = text.trim();
|
||||||
|
if (this.lookAhead() === '<') {
|
||||||
|
return [token.text, t, []];
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
Complie-script/comple/token.mjs
Normal file
7
Complie-script/comple/token.mjs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// token.mjs
|
||||||
|
export const token = {
|
||||||
|
startTag: 'startTag',
|
||||||
|
endTag: 'endTag',
|
||||||
|
text: 'text',
|
||||||
|
eof: 'eof'
|
||||||
|
};
|
5
Complie-script/xschema/A.schema.ts
Normal file
5
Complie-script/xschema/A.schema.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Start Tag: iv
|
||||||
|
Attribute: v=""
|
||||||
|
Attribute: name="{{jsx-parse}}"
|
||||||
|
Attribute: class="{{fuck}}"
|
||||||
|
Attribute: id="1"
|
15
Complie-script/xschema/A.xschema.tsx
Normal file
15
Complie-script/xschema/A.xschema.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<div name="{{jsx-parse}}" class="{{fuck}}" id="1">
|
||||||
|
Life is too difficult
|
||||||
|
<span name="life" like="rape">
|
||||||
|
<p>Life is like rape</p>
|
||||||
|
</span>
|
||||||
|
<div>
|
||||||
|
<span name="live" do="{{gofuck}}">
|
||||||
|
<p>Looking away, everything is sad</p>
|
||||||
|
</span>
|
||||||
|
<Counter me="excellent">
|
||||||
|
I am awesome
|
||||||
|
</Counter>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user