UNPKG

ocat-lang

Version:

A programming language for the web design and development

387 lines (386 loc) 18.1 kB
"use strict"; 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; } };