ocat-lang
Version:
A programming language for the web design and development
387 lines (386 loc) • 18.1 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.run = exports.save = exports.getThemes = void 0;
const error_1 = require("../error");
const memory_1 = require("../memory/");
const print_1 = require("../print/");
const lang_1 = require("../lang");
const parser_1 = require("./parser");
const utils_1 = require("./utils");
const adapters_1 = require("./adapters");
const express_1 = __importDefault(require("express"));
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const child_process_1 = require("child_process");
const constants_1 = require("./constants");
const view_1 = require("./adapters/view");
const path_2 = require("./adapters/path");
const memory = new memory_1.Memory();
const app = (0, express_1.default)();
const getThemes = () => {
if (fs_1.default.existsSync("./themes") && constants_1.config.themes) {
fs_1.default.readdirSync("./themes").forEach((file) => {
const name = file.replace(".json", "");
const content = fs_1.default.readFileSync(`./themes/${file}`, "utf-8");
const properties = JSON.parse(content);
memory.declareTheme(name, properties);
});
}
};
exports.getThemes = getThemes;
const save = () => {
(0, exports.getThemes)();
const properties = constants_1.config.properties;
if (properties) {
properties.provided.forEach((key) => {
memory.addProperty(key);
});
if (properties.defined) {
Object.entries(properties.defined).forEach(([name, value]) => {
memory.addProperty(name);
memory.setOrder(name, value);
});
}
}
if (constants_1.config.collections) {
Object.entries(constants_1.config.collections).forEach(([name, value]) => {
const folder = path_1.default.join("./collections", value);
if (fs_1.default.existsSync(folder)) {
const collectionItems = [];
const items = fs_1.default.readdirSync(folder, { withFileTypes: true });
const files = items.filter((item) => item.isFile());
files.forEach((file) => {
const name = file.name;
const params = {};
const content = fs_1.default
.readFileSync(path_1.default.join(folder, name), "utf8")
.replace(/---\s+(.*?)\s+---/gs, (_match, paramContent) => {
const paramMatch = /(.*?)="(.*?)"/gs;
const matchs = paramContent.match(paramMatch);
matchs === null || matchs === void 0 ? void 0 : matchs.forEach(([match, key, valuex]) => {
params[key] = valuex;
});
return "";
});
collectionItems.push({
content,
params,
title: name,
});
});
memory.declareCollection(name, collectionItems);
}
});
}
};
exports.save = save;
const run = (nodes) => {
(0, exports.save)();
const routes = [];
const views = [];
let index = 0;
let styles = constants_1.preStyles + constants_1.globalStyles;
let head = constants_1.defhead;
let lastConditionValue = false;
let title = "", description = "", layout = "";
nodes.forEach((node) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
const display = (err) => {
if (err instanceof error_1.CustomError) {
err.display(node.line);
}
else if (err instanceof error_1.Warning) {
err.display(node.line);
}
};
try {
switch (node.type) {
case parser_1.NodeType.OUTPUT:
if ((_a = node.params.content) === null || _a === void 0 ? void 0 : _a.startsWith("\\")) {
const name = node.params.content.replace("\\", "");
const value = memory.getVar(name);
(0, print_1.print)((_b = value === null || value === void 0 ? void 0 : value.value) !== null && _b !== void 0 ? _b : "");
}
else {
(0, print_1.print)(node.params.content);
}
break;
case parser_1.NodeType.ERR:
throw new error_1.CustomError((_c = node.params.cause) !== null && _c !== void 0 ? _c : constants_1.config.DERR, error_1.ErrorType.RuntimeError);
break;
case parser_1.NodeType.DECLARE:
try {
memory.declareVar(node.params.name, node.params.value, node.params.type);
}
catch (e) {
display(e);
}
break;
case parser_1.NodeType.IF:
const condition = node.params.condition;
const cond = condition === null || condition === void 0 ? void 0 : condition.cond;
const body = condition === null || condition === void 0 ? void 0 : condition.body;
if (cond && body) {
try {
lastConditionValue = commanditeCond(cond);
if (lastConditionValue) {
(0, lang_1.rund)(false, false, body);
}
}
catch (e) {
display(e);
}
}
break;
case parser_1.NodeType.SHOW:
const route = "/" + ((_d = node.params.route) !== null && _d !== void 0 ? _d : `404/${++index}`);
const processedHTMLContent = (0, adapters_1.processHTML)(memory, (0, adapters_1.processLayout)(layout, title, description, (_e = node.params.content) !== null && _e !== void 0 ? _e : ""));
const processedContent = `
<head>${head}</head>
<body>${processedHTMLContent}</body>
`;
routes.push({ name: route, content: processedContent });
break;
case parser_1.NodeType.EXPORTW:
memory.setOrder("export", "true");
break;
case parser_1.NodeType.STYLE:
styles +=
node.params.content || "* { box-sizing: border-box; }";
break;
case parser_1.NodeType.IMPORT:
const mem = (0, lang_1.init)(false, false, "./" + node.params.name || "./lib/main.ocat");
memory.copyFrom(mem);
break;
case parser_1.NodeType.UseStrict:
memory.setStrict();
break;
case parser_1.NodeType.ORDER:
memory.setOrder(node.params.name, node.params.content);
break;
case parser_1.NodeType.CDECLARE:
memory.declareComponent(node.params.name, (0, adapters_1.processHTML)(memory, (_f = node.params.content) !== null && _f !== void 0 ? _f : ""));
break;
case parser_1.NodeType.META:
const { type, content } = node.params;
if (!(type && content)) {
break;
}
if (type.startsWith("\\")) {
switch (type.replace(/\\/g, "")) {
case "title":
head += `<title>${content}</title>`;
title = content;
break;
}
}
else {
if (type === "description") {
description = content;
}
head += `<meta name="${type}" content="${content}" />`;
}
break;
case parser_1.NodeType.EXEC:
(0, child_process_1.exec)(node.params.content || `echo ${constants_1.config.ENCFE}`);
break;
case parser_1.NodeType.Function:
memory.declareFunction(node.params.name, node.params.content);
break;
case parser_1.NodeType.FCall:
const func = (_g = memory.getFunction(node.params.name)) !== null && _g !== void 0 ? _g : { name: (_h = node.params.name) !== null && _h !== void 0 ? _h : "", content: "" };
(0, lang_1.rund)(false, false, func.content);
break;
case parser_1.NodeType.Create:
const dtype = node.params.type;
const dname = node.params.name;
const contentx = node.params.content;
if (dtype === "file") {
fs_1.default.writeFileSync(dname !== null && dname !== void 0 ? dname : ".ocat", contentx !== null && contentx !== void 0 ? contentx : "p");
}
else if (dtype === "folder" || dtype === "dir") {
fs_1.default.mkdirSync(dname !== null && dname !== void 0 ? dname : "./.ocat");
}
break;
case parser_1.NodeType.Layout:
const tag = node.params.content;
layout = (0, adapters_1.processHTML)(memory, tag !== null && tag !== void 0 ? tag : "");
break;
case parser_1.NodeType.LOAD:
const _type = (_j = node.params.type) !== null && _j !== void 0 ? _j : "";
const _route = (0, path_2.processPath)((_k = node.params.route) !== null && _k !== void 0 ? _k : "", constants_1.config);
const pathName = (_l = _route.split("/").pop()) !== null && _l !== void 0 ? _l : "";
const readed = (_m = (0, utils_1.readFile)(_route + `/${pathName}.component.html`)) !== null && _m !== void 0 ? _m : "";
const cssReaded = (_o = (0, utils_1.readFile)(_route + `/${pathName}.component.css`)) !== null && _o !== void 0 ? _o : "";
const name = ((_q = (_p = readed.match(/<title>\w+<\/title>/g)) === null || _p === void 0 ? void 0 : _p[0]) !== null && _q !== void 0 ? _q : "udef")
.replace("<title>", "")
.replace("</title>", "");
if (_type === "component" || _type === "template") {
const prcontent = readed
.split(/\n/g)
.splice(1)
.join("\n");
const joinedContent = prcontent +
`<style>${(0, adapters_1.processCSS)(cssReaded, name, memory)}</style>`;
if (_type === "component") {
memory.declareComponent(name, joinedContent);
}
else {
memory.declareTemplate(name, joinedContent);
}
}
else if (_type === "layout") {
layout = (0, adapters_1.processHTML)(memory, readed);
}
break;
}
}
catch (e) {
if (e instanceof error_1.Warning || e instanceof error_1.CustomError) {
e.display(node.line);
}
else {
console.log("INTERNAL ERROR");
}
}
});
if (routes.length !== 0 ||
constants_1.config.views ||
memory.getOrder("export") === "true" ||
memory.getOrder("web")) {
if (constants_1.config.views) {
const viewsFolder = "./views/";
if (!fs_1.default.existsSync(viewsFolder)) {
fs_1.default.mkdirSync(viewsFolder);
}
const items = fs_1.default.readdirSync(viewsFolder, { withFileTypes: true });
const files = items.filter((item) => item.isFile());
const dirs = items.filter((item) => item.isDirectory());
files.forEach((file) => {
if (file.name.endsWith(".html")) {
const content = fs_1.default.readFileSync(path_1.default.join(viewsFolder, file.name), "utf-8");
views.push((0, view_1.viewAdapter)(file.name, content));
}
});
dirs.forEach((dir) => {
const dirPath = path_1.default.join(viewsFolder, dir.name);
const dirItems = fs_1.default.readdirSync(dirPath, {
withFileTypes: true,
});
const files = dirItems.filter((item) => item.isFile());
files.forEach((file) => {
if (file.name.endsWith(".html")) {
const name = path_1.default.join(dirPath, file.name);
const _name = `${dir.name}/${file.name}`;
const content = fs_1.default.readFileSync(name, "utf-8");
const view = (0, view_1.viewAdapter)(_name, content);
views.push(view);
}
});
});
views.forEach((view) => {
app.get(view.name, (req, res) => {
var _a;
if (view.useKey) {
res.send((0, view_1.viewAdapt)(view, memory, (_a = req.params.key) !== null && _a !== void 0 ? _a : null));
}
else {
res.send((0, view_1.viewAdapt)(view, memory));
}
});
});
}
const routeTemplate = (0, adapters_1.processRouteTemplate)(constants_1.codeRouteTemplate, routes, views);
routes.forEach((route) => {
app.get(route.name, (req, res) => {
res.send((0, adapters_1.processRoute)(memory, constants_1.preJs, route.content, route.name, routeTemplate, styles));
});
});
app.all("*", (req, res) => {
res.status(404).send((0, adapters_1.process404)(constants_1.code404, { routeTemplate }));
});
if (memory.getOrder("export") === "true") {
if (fs_1.default.existsSync("./out"))
fs_1.default.rmSync("./out", { recursive: true });
fs_1.default.mkdirSync("./out");
fs_1.default.mkdirSync("./out/css");
fs_1.default.writeFileSync("./out/css/style.css", styles);
routes.forEach((route) => {
const routePath = route.name === "/"
? "./out/index.html"
: `./out/${route.name.replace(/^\//, "")}/index.html`;
const dir = path_1.default.dirname(routePath);
fs_1.default.mkdirSync(dir, { recursive: true });
const cssPath = route.name === "/"
? "./css/style.css"
: "../".repeat(route.name.split("/").length - 1) +
"css/style.css";
const contentWithCSS = `<link href="${cssPath}" rel="stylesheet" />${route.content}`;
fs_1.default.writeFileSync(routePath, contentWithCSS);
});
}
try {
app.listen(constants_1.config.port, () => {
console.log(`Server running at http://localhost:${constants_1.config.port}/`);
console.log(`Quit the server with (CTRL or CMD) + C`);
});
}
catch (e) {
console.log("The port is already in use");
}
}
return memory;
};
exports.run = run;
const commanditeCond = (condition) => {
const args_ = condition.split("\\s+");
const args = args_.map((arg) => arg.trim());
const firstValue = (0, utils_1.getValue)(args[0], memory);
const operator = args[1];
const secondValue = (0, utils_1.getValue)(args[2], memory);
if (operator.match(/\b(<>|<=|>=|<|>)\b/) &&
(firstValue.type !== "int" || secondValue.type !== "int")) {
const message = `Cannot compare ${firstValue.type} and ${secondValue.type} with a number operator`;
if (memory.isStrict) {
throw new error_1.CustomError(message, error_1.ErrorType.ExecutionError);
}
else {
throw new error_1.Warning(message);
}
}
switch (operator) {
case "=":
return firstValue.value === secondValue.value;
break;
case "!=":
return firstValue.value !== secondValue.value;
break;
case "<>":
return Number(firstValue.value) !== Number(secondValue.value);
break;
case "<=":
return Number(firstValue.value) <= Number(secondValue.value);
break;
case ">=":
return Number(firstValue.value) >= Number(secondValue.value);
break;
case "<":
return Number(firstValue.value) < Number(secondValue.value);
break;
case ">":
return Number(firstValue.value) > Number(secondValue.value);
break;
default:
const message = `Unknown condition: ${operator}`;
if (memory.isStrict) {
throw new error_1.CustomError(message, error_1.ErrorType.ExecutionError);
}
else {
throw new error_1.Warning(message);
}
break;
}
};