Advertisement
Arinek

ArinekHTML Parser

Apr 24th, 2024
543
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. export class ArinekHTML {
  2.     #raw_html;
  3.     html;
  4.     #ns;
  5.  
  6.     keywords = [
  7.         "loop"
  8.     ];
  9.  
  10.     /**
  11.      * @param {NS} ns
  12.      * @param {string} html_file
  13.      */
  14.     constructor(ns, html_file) {
  15.         this.#raw_html = ns.read(html_file);
  16.         this.#ns = ns;
  17.     }
  18.  
  19.     /**
  20.      * @param {Collection} data
  21.      */
  22.     parse(data) {
  23.         this.html = this.#raw_html;
  24.  
  25.         while (this.commands.length !== 0) {
  26.             let commands = this.commands;
  27.  
  28.             //Validating Commands.
  29.             const invalid_commands = this.validateCommands(commands, this.keywords);
  30.             commands = commands.filter(command => invalid_commands.every(invalid_command => invalid_command.command !== command.command));
  31.  
  32.  
  33.             let command_pairs = []
  34.  
  35.             for (const command of commands) {
  36.                 if (command.depth === 0) {
  37.                     command_pairs.push(command);
  38.                 }
  39.             }
  40.  
  41.             let new_html = "";
  42.             let prev_end_index = 0;
  43.             for (let index = 0; index < command_pairs.length; index += 2) {
  44.                 const open_command = command_pairs[index];
  45.                 const close_command = command_pairs[index + 1];
  46.  
  47.                 const open_command_end_index = open_command.index + open_command.command.length + 3;
  48.                 const close_command_end_index = close_command.index + close_command.command.length + 3;
  49.  
  50.                 const content = this.html.slice(open_command_end_index, close_command.index);
  51.  
  52.                 //this.#ns.tprint(open_command.command, this.html[open_command.index]);
  53.  
  54.                 let args = open_command.command.split(":")[1].split(" ");
  55.  
  56.                 for (let arg in args) {
  57.                     args[arg] = new Arg(open_command, args[arg].split("=")[0], args[arg].split("=")[1]);
  58.                 }
  59.                 const result = open_command.run(args, content, data, this.#ns);
  60.  
  61.                 new_html += this.html.slice(prev_end_index, open_command.index) + result;
  62.                 prev_end_index = close_command_end_index;
  63.             }
  64.             new_html += this.html.slice(prev_end_index);
  65.             this.html = new_html;
  66.             //this.#ns.tprint(this.html);
  67.         }
  68.         for (const item in data.single) {
  69.             this.html = this.html.replaceAll(item, data[item]);
  70.         }
  71.     }
  72.  
  73.     /**
  74.      * @returns {Command[]}
  75.      */
  76.     get commands() {
  77.         let commands = [];
  78.         const html = this.html; //Shortened name.
  79.         let index = -1; //Index in html file.
  80.         let depth = -1; //Depth of command in command structure.
  81.         //this.#ns.tprint("\n");
  82.  
  83.         //While there is another command.
  84.         while (html.indexOf("${", index + 1) !== -1) {
  85.             index = html.indexOf("${", index + 1);
  86.             const end_of_command_index = html.indexOf("}", index);
  87.  
  88.             const command = html.slice(index + 2, end_of_command_index); //Command sliced from html from "${blablabla}" to "blablabla".
  89.             //this.#ns.tprint(index + " ", html[index]);
  90.  
  91.  
  92.             //Checking whether it is a command and not a variable.
  93.             if (new RegExp(".*:.*").test(command)) {
  94.  
  95.                 //Checking whether or not it is a closing statement, as such ending in two ":".
  96.                 if (new RegExp(".*::").test(command)) {
  97.                     const commandObject = new Command(command, depth, index);
  98.                     commands.push(commandObject);
  99.                     depth -= 1;
  100.                 }
  101.                 else {
  102.                     depth += 1;
  103.                     const commandObject = new Command(command, depth, index);
  104.                     commands.push(commandObject);
  105.                 }
  106.             }
  107.         }
  108.         //this.#ns.tprint(html);
  109.         return commands;
  110.     }
  111.  
  112.     /**
  113.      * @param {Command[]} commands
  114.      * @param {string[]} keywords
  115.      * @returns {Command[]?}
  116.      */
  117.     validateCommands(commands, keywords) {
  118.         let invalid_commands = [];
  119.         for (const command of commands) {
  120.             if (!keywords.some(keyword => keyword == command.name) && !new RegExp(".*:.*").test(command.command)) {
  121.                 invalid_commands.push(command);
  122.             }
  123.         }
  124.         return invalid_commands;
  125.     }
  126. }
  127.  
  128. class Command {
  129.     #command;
  130.     #name;
  131.     #depth;
  132.     #index;
  133.  
  134.     /**
  135.      * @param {string} command
  136.      * @param {number} depth
  137.      * @param {number} index
  138.      */
  139.     constructor(command, depth, index) {
  140.         this.#command = command;
  141.         this.#name = command.split(":")[0];
  142.         this.#depth = depth;
  143.         this.#index = index;
  144.     }
  145.  
  146.     get command() {
  147.         return this.#command;
  148.     }
  149.  
  150.     get name() {
  151.         return this.#name;
  152.     }
  153.  
  154.     get depth() {
  155.         return this.#depth;
  156.     }
  157.  
  158.     get index() {
  159.         return this.#index;
  160.     }
  161.  
  162.     /**
  163.      * @param {Arg[]} args
  164.      * @param {string} content
  165.      * @param {Collection} data
  166.      * @param {NS} ns
  167.      */
  168.     run(args, content, data, ns) {
  169.         switch (this.#name.toUpperCase()) {
  170.             case "LOOP":
  171.                 return new LOOP(args, content).run(data, ns);
  172.                 break;
  173.         }
  174.     }
  175. }
  176.  
  177. class Arg {
  178.     #command;
  179.     #name;
  180.     #value;
  181.  
  182.     /**
  183.      * @param {Command} command
  184.      * @param {string} name
  185.      * @param {string} value
  186.      */
  187.     constructor(command, name, value) {
  188.         this.#command = command;
  189.         this.#name = name;
  190.         this.#value = value;
  191.     }
  192.  
  193.  
  194.     get command() {
  195.         return this.#command;
  196.     }
  197.  
  198.     get name() {
  199.         return this.#name;
  200.     }
  201.  
  202.     get value() {
  203.         return this.#value;
  204.     }
  205. }
  206.  
  207. class LOOP {
  208.     #args;
  209.     #content;
  210.  
  211.     /**
  212.      *@param {Arg[]} args
  213.      *@param {string} content
  214.      */
  215.     constructor(args, content) {
  216.         this.#args = args;
  217.         this.#content = content;
  218.     }
  219.  
  220.     get args() {
  221.         return this.#args;
  222.     }
  223.  
  224.     get content() {
  225.         return this.#content;
  226.     }
  227.  
  228.     /**
  229.      * @param {Collection} data
  230.      * @param {NS} ns
  231.      */
  232.     run(data, ns) {
  233.         const items = this.#args.find(arg => arg.name.trim() === "items");
  234.         const item = this.#args.find(arg => arg.name.trim() === "item");
  235.         const itemStatus = this.#args.find(arg => arg.name.trim() === "itemStatus");
  236.         const begin = this.#args.find(arg => arg.name.trim() === "begin");
  237.         const end = this.#args.find(arg => arg.name.trim() === "end");
  238.  
  239.         let new_content = "";
  240.         if (items === undefined) {
  241.             if (begin !== undefined && end !== undefined) {
  242.                 if (item === undefined) {
  243.                     return this.#content.repeat(Number(end.value) - Number(begin.value) + 1);
  244.                 } else {
  245.                     for (let i = begin.value; i <= end.value; i++) {
  246.                         new_content += this.#content;
  247.                         new_content = new_content.replaceAll("${" + item.value + "}", i);
  248.                     }
  249.                 }
  250.             }
  251.         } else if (item === undefined && itemStatus !== undefined) {
  252.             for (let i = 0; i < data.data[items.value].length; i++) {
  253.                 new_content += this.#content;
  254.                 new_content = new_content.replaceAll("${" + itemStatus.value + "}", i);
  255.             }
  256.         } else if (item !== undefined && itemStatus === undefined) {
  257.             for (let i = 0; i < data.data[items.value].length; i++) {
  258.                 new_content += this.#content;
  259.                 new_content = new_content.replaceAll("${" + item.value + "}", data.data[items.value][i]);
  260.             }
  261.         } else {
  262.             for (let i = 0; i < data.data[items.value].length; i++) {
  263.                 new_content += this.#content;
  264.                 new_content = new_content.replaceAll("${" + item.value + "}", data.data[items.value][i]);
  265.                 new_content = new_content.replaceAll("${" + itemStatus.value + "}", i);
  266.             }
  267.         }
  268.  
  269.         return new_content;
  270.     }
  271. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement