From 3f50811a3eb4813b8f081395f1fad9f82f334f8c Mon Sep 17 00:00:00 2001 From: Dagan Martinez Date: Sun, 27 Mar 2022 15:57:32 -0400 Subject: [PATCH] Lint/format JS files --- .eslintrc.cjs | 14 + .gitignore | 6 +- Debugger.js | 754 +++++++++---------- Settings.js | 235 +++--- controller.js | 852 ++++++++++----------- examples.js | 14 +- modals.js | 106 ++- package-lock.json | 1794 ++++++++++++++++++++++++++++++++++++++++++++- package.json | 14 +- test.js | 457 ++++++------ 10 files changed, 2947 insertions(+), 1299 deletions(-) create mode 100644 .eslintrc.cjs diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..d63b4a6 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,14 @@ +module.exports = { + "env": { + "browser": true, + "node": true, + "es2021": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "rules": { + } +} diff --git a/.gitignore b/.gitignore index c2c1fff..b164050 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,10 @@ !**/**/ !.gitignore !*.js +!*.cjs !*.html !*.css -!package.json -!package-lock.json +!*.json +!*.yaml +!*.yml node_modules diff --git a/Debugger.js b/Debugger.js index 047a3ee..485e487 100644 --- a/Debugger.js +++ b/Debugger.js @@ -2,21 +2,21 @@ const DEFAULT_CELL_WIDTH = 256; export const TokenType = Object.freeze({ - // Standard Brainfuck commands - "BF_LOOP_OPEN": 1, - "BF_LOOP_CLOSE":2, - "BF_ADD": 3, - "BF_SHIFT": 4, - "BF_OUTPUT": 5, - "BF_INPUT": 6, - - // Represents a [-] like construct - // Automatically brings the value the pointer is pointing to to zero - "BF_ZERO": 7, - - // Cushioning for the beginning and end of the token array - "BF_START": 8, - "BF_END": 9, + // Standard Brainfuck commands + "BF_LOOP_OPEN": 1, + "BF_LOOP_CLOSE": 2, + "BF_ADD": 3, + "BF_SHIFT": 4, + "BF_OUTPUT": 5, + "BF_INPUT": 6, + + // Represents a [-] like construct + // Automatically brings the value the pointer is pointing to to zero + "BF_ZERO": 7, + + // Cushioning for the beginning and end of the token array + "BF_START": 8, + "BF_END": 9, }); /* @@ -25,396 +25,348 @@ export const TokenType = Object.freeze({ * ignore the value the user wants to push, and push * the historical value instead */ -class EfficientStack -{ - constructor() - { - this._internal_stack=[] - this.clear(); - } - - clear() - { - this._internal_stack.length = 0; - this._stack_pointer = 0; - } - - push(val) - { - if(this._stack_pointer > this._internal_stack.length) - { - throw("EfficientStack: can't push: sp>stack length"); - } - if(this._stack_pointer === this._internal_stack.length) - { - this._internal_stack.push(val) - } - - this._stack_pointer++; - } - - pop() - { - if(this._stack_pointer===0) - { - throw("EfficientStack: can't pop: nothing to pop"); - } - - this._stack_pointer--; - return this._internal_stack[this._stack_pointer]; - } - - get length(){ - return this._stack_pointer; - } +class EfficientStack { + constructor() { + this._internal_stack = [] + this.clear(); + } + + clear() { + this._internal_stack.length = 0; + this._stack_pointer = 0; + } + + push(val) { + if (this._stack_pointer > this._internal_stack.length) { + throw ("EfficientStack: can't push: sp>stack length"); + } + if (this._stack_pointer === this._internal_stack.length) { + this._internal_stack.push(val) + } + + this._stack_pointer++; + } + + pop() { + if (this._stack_pointer === 0) { + throw ("EfficientStack: can't pop: nothing to pop"); + } + + this._stack_pointer--; + return this._internal_stack[this._stack_pointer]; + } + + get length() { + return this._stack_pointer; + } } // Adapted from Property404/dbfi/src/interpret.c // See original source for helpful comments or lack thereof -function tokenize(source, optimize=true) -{ - let line_number = 0; - let column = 0; - let token_index = 0; - - const tokens = []; - const skip_stack = []; - - for(let i=0;i[].,".includes(character)) - { - const new_token = {type:null, value:1, start:i, line:line_number, column: column}; - - new_token.character=character; - switch(character) - { - case "[": - // Optimize out [-] and [+] into one token - if(optimize && (source[i+1] === "-" || source[i+1] === "+") && source[i+2] === "]") - { - new_token.type=TokenType.BF_ZERO; - new_token.value_stack = []; - new_token.is_positive = (source[i+1]==='+'); - i+=2; - column+=2; - } - else - { - new_token.type = TokenType.BF_LOOP_OPEN; - skip_stack.push(token_index); - new_token.pc_stack = new EfficientStack(); - } - break; - case "]": - new_token.type = TokenType.BF_LOOP_CLOSE; - new_token.pc_stack = new EfficientStack(); - // [ and ] need to be mated - new_token.partner = skip_stack.pop(); - if( - new_token.partner === undefined - ) - { - throw(`Unmatched ']' at line ${line_number+1} column ${column+1}`); - } - tokens[new_token.partner].partner = token_index; - break; - - case '-': - case '+': - new_token.type=TokenType.BF_ADD; - new_token.value=(character=='+'?1:-1); - break; - - case '<': - case '>': - new_token.type=TokenType.BF_SHIFT; - new_token.value=(character=='>'?1:-1); - break; - - case '.': - new_token.type = TokenType.BF_OUTPUT; - break; - - case ',': - new_token.type = TokenType.BF_INPUT; - new_token.value_stack = []; - break; - - default: - break; - } - - // Potentially condense series of <<<< >>>> ++++ or ---- - if(optimize && token_index > 0 && new_token.type == tokens[tokens.length - 1].type && - [TokenType.BF_SHIFT,TokenType.BF_ADD].indexOf(new_token.type) != -1) - { - tokens[tokens.length -1].value += new_token.value; - } - else - { - tokens.push(new_token); - token_index++; - } - } - if(character === "\n") - { - line_number++; - column=-1; - } - column++; - } - tokens.unshift({type:TokenType.BF_START,value:0}); - tokens.push({type:TokenType.BF_END}); - - // Since we added a token at beginning, we have to shift now - for(const index in tokens) - { - if(tokens[index].partner) - { - tokens[index].partner += 1; - } - } - return tokens; +function tokenize(source, optimize = true) { + let line_number = 0; + let column = 0; + let token_index = 0; + + const tokens = []; + const skip_stack = []; + + for (let i = 0; i < source.length; i++) { + const character = source[i]; + + if ("+-<>[].,".includes(character)) { + const new_token = { + type: null, + value: 1, + start: i, + line: line_number, + column: column + }; + + new_token.character = character; + switch (character) { + case "[": + // Optimize out [-] and [+] into one token + if (optimize && (source[i + 1] === "-" || source[i + 1] === "+") && source[i + 2] === "]") { + new_token.type = TokenType.BF_ZERO; + new_token.value_stack = []; + new_token.is_positive = (source[i + 1] === '+'); + i += 2; + column += 2; + } else { + new_token.type = TokenType.BF_LOOP_OPEN; + skip_stack.push(token_index); + new_token.pc_stack = new EfficientStack(); + } + break; + case "]": + new_token.type = TokenType.BF_LOOP_CLOSE; + new_token.pc_stack = new EfficientStack(); + // [ and ] need to be mated + new_token.partner = skip_stack.pop(); + if ( + new_token.partner === undefined + ) { + throw (`Unmatched ']' at line ${line_number+1} column ${column+1}`); + } + tokens[new_token.partner].partner = token_index; + break; + + case '-': + case '+': + new_token.type = TokenType.BF_ADD; + new_token.value = (character == '+' ? 1 : -1); + break; + + case '<': + case '>': + new_token.type = TokenType.BF_SHIFT; + new_token.value = (character == '>' ? 1 : -1); + break; + + case '.': + new_token.type = TokenType.BF_OUTPUT; + break; + + case ',': + new_token.type = TokenType.BF_INPUT; + new_token.value_stack = []; + break; + + default: + break; + } + + // Potentially condense series of <<<< >>>> ++++ or ---- + if (optimize && token_index > 0 && new_token.type == tokens[tokens.length - 1].type && [TokenType.BF_SHIFT, TokenType.BF_ADD].indexOf(new_token.type) != -1) { + tokens[tokens.length - 1].value += new_token.value; + } else { + tokens.push(new_token); + token_index++; + } + } + if (character === "\n") { + line_number++; + column = -1; + } + column++; + } + tokens.unshift({ + type: TokenType.BF_START, + value: 0 + }); + tokens.push({ + type: TokenType.BF_END + }); + + // Since we added a token at beginning, we have to shift now + for (const index in tokens) { + if (tokens[index].partner) { + tokens[index].partner += 1; + } + } + return tokens; } -export class Debugger -{ - constructor(source) - { - if(source) - this.load(source); - - this.output_callback = (val)=>{}; - this.input_callback = ()=>{return 0;}; - - this.cell_width = DEFAULT_CELL_WIDTH; - this.optimize=true; - this.allow_wrapping = true; - this.allow_negative_pointer = false; - } - - load(source){ - this.source = source; - this.tokens = tokenize(source, this.optimize); - this.tape = {"0":0}; - this.reset(); - } - - getPositionInSource() - { - const res = this.tokens[this.pc].start; - if (res === undefined) - return -1; - return res; - } - - // Get a unique-ish integer valued tied to our current state - getStateHash() - { - let total = 0; - for (let i=0;i<1000;i++) - { - if(this.tape[i]) - total+=this.tape[i]; - } - total += this.pointer * 100000; - let pcval = this.tokens[this.pc].type; - total += 1000*pcval; - return total; - } - - atEnd() - { - if(!this.tokens)return false; - return this.pc >= this.tokens.length || this.tokens[this.pc].type==TokenType.BF_END; - } - - atBeginning() - { - if(!this.tokens)return true; - return this.pc == 0; - } - - reset() - { - this.last_pc=0; - this.pc = 0; - this.pointer=0; - for(const i in this.tape) - { - this.tape[i] = 0; - } - for (const token of this.tokens) - { - if(token.value_stack) - token.value_stack.length = 0; - if(token.pc_stack !== undefined) - { - token.pc_stack.clear(); - token.pc_stack.push(0); - } - } - } - - step(reverse=false) - { - let stepagain = false; - if(reverse) - this.pc --; - - let pc_going_forth = this.pc; - - if(this.pc<0 || this.pc>this.tokens.length) - { - throw("Program counter out of bounds (pc = "+this.pc+")"); - } - - const token = this.tokens[this.pc]; - - if (this.tape[this.pointer] == undefined) - this.tape[this.pointer] = 0; - - if(token == undefined) - { - throw "Found undefined token"; - } - switch(token.type) - { - case TokenType.BF_ZERO: - if(reverse) - { - this.tape[this.pointer] = token.value_stack.pop(); - } - else - { - token.value_stack.push(this.tape[this.pointer]); - if(this.tape[this.pointer] && !this.allow_wrapping && token.is_positive) - { - throw("[+]-type construct throws cell value out of bounds"); - } - this.tape[this.pointer] = 0; - } - break; - - case TokenType.BF_ADD: - if(reverse) - this.tape[this.pointer]-=token.value; - else - this.tape[this.pointer]+=token.value; - - if - ( - this.tape[this.pointer] < 0 || - this.tape[this.pointer] >= this.cell_width - ) - { - if(!this.allow_wrapping)throw("Cell value out of bounds"); - - this.tape[this.pointer]%=this.cell_width; - if(this.tape[this.pointer] < 0) - this.tape[this.pointer] = this.cell_width+this.tape[this.pointer]; - } - break; - case TokenType.BF_SHIFT: - if(reverse) - this.pointer-=token.value; - else - this.pointer+=token.value; - if(this.pointer<0 && !this.allow_negative_pointer) - throw(`Pointer out of bounds(pointer=${this.pointer}, direction=${reverse?"reverse":"forward"}) at line ${token.line+1} column ${token.column+1}`); - break; - case TokenType.BF_INPUT: - if(!reverse) - { - const old_val = this.tape[this.pointer]; - const new_val = this.input_callback(); - if(new_val === null) - { - // Effectively do nothing, not even move PC - // This is to allow controller.js to get input from user - return; - } - else if(Number.isInteger(new_val)) - { - this.tape[this.pointer] = new_val; - token.value_stack.push(old_val); - } - else - { - throw "Debugger expected integer input(eg an ASCII value) but got: "+new_val; - } - } - else - { - this.tape[this.pointer] = token.value_stack.pop(); - } - break; - case TokenType.BF_OUTPUT: - if (!reverse) - { - const val = this.tape[this.pointer]; - const ch = String.fromCharCode(val); - - this.output_callback(ch); - } - break; - - case TokenType.BF_LOOP_OPEN: - case TokenType.BF_LOOP_CLOSE: - if(!reverse) - { - token.pc_stack.push(this.last_pc+1); - - if - ( - (token.type === TokenType.BF_LOOP_CLOSE && this.tape[this.pointer])|| - (token.type === TokenType.BF_LOOP_OPEN && !this.tape[this.pointer]) - ) - { - this.tokens[token.partner].pc_stack.push(this.pc); - this.pc = token.partner; - } - } - else - { - this.pc = token.pc_stack.pop(); - if(this.pc == token.partner) - { - this.tokens[token.partner].pc_stack.pop(); - } - } - break; - case TokenType.BF_START: - case TokenType.BF_END: - break; - default: - throw "Found unknown token"; - } - - if(!reverse) - { - this.pc ++; - if(this.pc>=this.tokens.length) - { - throw("Program counter out of bounds (pc = "+this.pc+")"); - } - } - - this.last_pc = pc_going_forth; - - if(stepagain) - this.step(reverse); - } - - get current_value() - { - return this.tape[this.pointer]; - } - set current_value(val) - { - this.tape[this.pointer] = val; - } +export class Debugger { + constructor(source) { + if (source) + this.load(source); + + this.output_callback = () => {}; + this.input_callback = () => { + return 0; + }; + + this.cell_width = DEFAULT_CELL_WIDTH; + this.optimize = true; + this.allow_wrapping = true; + this.allow_negative_pointer = false; + } + + load(source) { + this.source = source; + this.tokens = tokenize(source, this.optimize); + this.tape = { + "0": 0 + }; + this.reset(); + } + + getPositionInSource() { + const res = this.tokens[this.pc].start; + if (res === undefined) + return -1; + return res; + } + + // Get a unique-ish integer valued tied to our current state + getStateHash() { + let total = 0; + for (let i = 0; i < 1000; i++) { + if (this.tape[i]) + total += this.tape[i]; + } + total += this.pointer * 100000; + let pcval = this.tokens[this.pc].type; + total += 1000 * pcval; + return total; + } + + atEnd() { + if (!this.tokens) return false; + return this.pc >= this.tokens.length || this.tokens[this.pc].type == TokenType.BF_END; + } + + atBeginning() { + if (!this.tokens) return true; + return this.pc == 0; + } + + reset() { + this.last_pc = 0; + this.pc = 0; + this.pointer = 0; + for (const i in this.tape) { + this.tape[i] = 0; + } + for (const token of this.tokens) { + if (token.value_stack) + token.value_stack.length = 0; + if (token.pc_stack !== undefined) { + token.pc_stack.clear(); + token.pc_stack.push(0); + } + } + } + + step(reverse = false) { + let stepagain = false; + if (reverse) + this.pc--; + + let pc_going_forth = this.pc; + + if (this.pc < 0 || this.pc > this.tokens.length) { + throw ("Program counter out of bounds (pc = " + this.pc + ")"); + } + + const token = this.tokens[this.pc]; + + if (this.tape[this.pointer] == undefined) + this.tape[this.pointer] = 0; + + if (token == undefined) { + throw "Found undefined token"; + } + switch (token.type) { + case TokenType.BF_ZERO: + if (reverse) { + this.tape[this.pointer] = token.value_stack.pop(); + } else { + token.value_stack.push(this.tape[this.pointer]); + if (this.tape[this.pointer] && !this.allow_wrapping && token.is_positive) { + throw ("[+]-type construct throws cell value out of bounds"); + } + this.tape[this.pointer] = 0; + } + break; + + case TokenType.BF_ADD: + if (reverse) + this.tape[this.pointer] -= token.value; + else + this.tape[this.pointer] += token.value; + + if ( + this.tape[this.pointer] < 0 || + this.tape[this.pointer] >= this.cell_width + ) { + if (!this.allow_wrapping) throw ("Cell value out of bounds"); + + this.tape[this.pointer] %= this.cell_width; + if (this.tape[this.pointer] < 0) + this.tape[this.pointer] = this.cell_width + this.tape[this.pointer]; + } + break; + case TokenType.BF_SHIFT: + if (reverse) + this.pointer -= token.value; + else + this.pointer += token.value; + if (this.pointer < 0 && !this.allow_negative_pointer) + throw (`Pointer out of bounds(pointer=${this.pointer}, direction=${reverse?"reverse":"forward"}) at line ${token.line+1} column ${token.column+1}`); + break; + case TokenType.BF_INPUT: + if (!reverse) { + const old_val = this.tape[this.pointer]; + const new_val = this.input_callback(); + if (new_val === null) { + // Effectively do nothing, not even move PC + // This is to allow controller.js to get input from user + return; + } else if (Number.isInteger(new_val)) { + this.tape[this.pointer] = new_val; + token.value_stack.push(old_val); + } else { + throw "Debugger expected integer input(eg an ASCII value) but got: " + new_val; + } + } else { + this.tape[this.pointer] = token.value_stack.pop(); + } + break; + case TokenType.BF_OUTPUT: + if (!reverse) { + const val = this.tape[this.pointer]; + const ch = String.fromCharCode(val); + + this.output_callback(ch); + } + break; + + case TokenType.BF_LOOP_OPEN: + case TokenType.BF_LOOP_CLOSE: + if (!reverse) { + token.pc_stack.push(this.last_pc + 1); + + if ( + (token.type === TokenType.BF_LOOP_CLOSE && this.tape[this.pointer]) || + (token.type === TokenType.BF_LOOP_OPEN && !this.tape[this.pointer]) + ) { + this.tokens[token.partner].pc_stack.push(this.pc); + this.pc = token.partner; + } + } else { + this.pc = token.pc_stack.pop(); + if (this.pc == token.partner) { + this.tokens[token.partner].pc_stack.pop(); + } + } + break; + case TokenType.BF_START: + case TokenType.BF_END: + break; + default: + throw "Found unknown token"; + } + + if (!reverse) { + this.pc++; + if (this.pc >= this.tokens.length) { + throw ("Program counter out of bounds (pc = " + this.pc + ")"); + } + } + + this.last_pc = pc_going_forth; + + if (stepagain) + this.step(reverse); + } + + get current_value() { + return this.tape[this.pointer]; + } + set current_value(val) { + this.tape[this.pointer] = val; + } } diff --git a/Settings.js b/Settings.js index d44ecf9..f7ade0c 100644 --- a/Settings.js +++ b/Settings.js @@ -1,138 +1,117 @@ -import {getExample} from "./examples.js"; +import { + getExample +} from "./examples.js"; const LOCAL_STORAGE_PREFIX = "brainfuck_debugger_app__"; // let's still be functional even if storage is disabled -let fauxStorage={}; -export function putLocalStorage(key, value) -{ - try{ - localStorage[LOCAL_STORAGE_PREFIX+key] = value; - }catch(e){ - fauxStorage[key] = value; - } +let fauxStorage = {}; +export function putLocalStorage(key, value) { + try { + localStorage[LOCAL_STORAGE_PREFIX + key] = value; + } catch (e) { + fauxStorage[key] = value; + } } -export function accessLocalStorage(key) -{ - let val; - try{ - val = localStorage[LOCAL_STORAGE_PREFIX+key]; - }catch(e){ - val = fauxStorage[key]; - } - if(val === undefined) - { - if(key === "source") - return getExample("hello-world"); - } - return val; +export function accessLocalStorage(key) { + let val; + try { + val = localStorage[LOCAL_STORAGE_PREFIX + key]; + } catch (e) { + val = fauxStorage[key]; + } + if (val === undefined) { + if (key === "source") + return getExample("hello-world"); + } + return val; } -function Option(name,default_value){ - this.name = name; - this.default_value=default_value; - if(accessLocalStorage(name) === undefined) - { - this.value = default_value; - putLocalStorage(name, default_value); - } - else - { - let val = accessLocalStorage(name); - if(val === "true") - val = true; - if(val === "false") - val = false; - val = Number(val) || val; - this.value = val; - } + +function Option(name, default_value) { + this.name = name; + this.default_value = default_value; + if (accessLocalStorage(name) === undefined) { + this.value = default_value; + putLocalStorage(name, default_value); + } else { + let val = accessLocalStorage(name); + if (val === "true") + val = true; + if (val === "false") + val = false; + val = Number(val) || val; + this.value = val; + } } -export class Settings -{ - constructor(update_callback) - { - this.options= - [ - new Option("editor-keymap", "default"), - new Option("editor-highlighting", true), - new Option("editor-theme", "monokai"), - new Option("global-theme", "dagan"), - new Option("cell-width", 8), - new Option("step-delay", 1), - new Option("optimize", true), - new Option("line-numbers", true), - new Option("close-brackets", true), - new Option("match-brackets", true), - new Option("wrapping-allowed", true), - new Option("double-tape", false), - ]; - this.update_callback = update_callback; - this.options_map = {}; - for(const option of this.options) - { - this.options_map[option.name] = option; - } - this.loadToUI(); - this.setUpEvents(); - } - - setUpEvents() - { - const eventHandler = (option_name)=>{ - let value; - if(event.target.type === "checkbox") - { - value = event.target.checked; - } - else - { - value = event.target.value; - } - if(value !== undefined) - { - this.options_map[option_name].value = value; - putLocalStorage(option_name, value); - } - this.update_callback(); - }; - for(const option of this.options) - { - const element = document.getElementById("opt-"+option.name); - const eh = eventHandler.bind(this, option.name); - element.addEventListener("input",eh); - } +export class Settings { + constructor(update_callback) { + this.options = [ + new Option("editor-keymap", "default"), + new Option("editor-highlighting", true), + new Option("editor-theme", "monokai"), + new Option("global-theme", "dagan"), + new Option("cell-width", 8), + new Option("step-delay", 1), + new Option("optimize", true), + new Option("line-numbers", true), + new Option("close-brackets", true), + new Option("match-brackets", true), + new Option("wrapping-allowed", true), + new Option("double-tape", false), + ]; + this.update_callback = update_callback; + this.options_map = {}; + for (const option of this.options) { + this.options_map[option.name] = option; + } + this.loadToUI(); + this.setUpEvents(); + } + + setUpEvents() { + const eventHandler = (option_name) => { + let value; + if (event.target.type === "checkbox") { + value = event.target.checked; + } else { + value = event.target.value; + } + if (value !== undefined) { + this.options_map[option_name].value = value; + putLocalStorage(option_name, value); + } + this.update_callback(); + }; + for (const option of this.options) { + const element = document.getElementById("opt-" + option.name); + const eh = eventHandler.bind(this, option.name); + element.addEventListener("input", eh); + } - } + } - loadToUI() - { - for(const option of this.options) - { - const element = document.getElementById("opt-"+option.name); - if (element.tagName === "INPUT") - { - if(element.type === "number") - element.value = option.value; - else if(element.type === "checkbox") - { - const val = !!(option.value); - if(typeof val !== "boolean") - throw("Expected boolean value"); - element.checked = val; - } - else - throw("Unknown type of input"); - } - else if(element.tagName === "SELECT") - { - element.value = option.value; - } - } - } + loadToUI() { + for (const option of this.options) { + const element = document.getElementById("opt-" + option.name); + if (element.tagName === "INPUT") { + if (element.type === "number") + element.value = option.value; + else if (element.type === "checkbox") { + const val = !!(option.value); + if (typeof val !== "boolean") + throw ("Expected boolean value"); + element.checked = val; + } else + throw ("Unknown type of input"); + } else if (element.tagName === "SELECT") { + element.value = option.value; + } + } + } - get(option_name) - { - if(this.options_map[option_name]) - return this.options_map[option_name].value; - else - console.log("No such option: "+option_name); - } + get(option_name) { + if (this.options_map[option_name]) + return this.options_map[option_name].value; + else + console.log("No such option: " + option_name); + } } diff --git a/controller.js b/controller.js index 99f569b..5f25ff7 100644 --- a/controller.js +++ b/controller.js @@ -1,29 +1,39 @@ -import {TokenType,Debugger} from "./Debugger.js"; -import {getExample} from "./examples.js"; -import {accessLocalStorage, putLocalStorage, Settings} from "./Settings.js"; +import { + TokenType, + Debugger +} from "./Debugger.js"; +import { + getExample +} from "./examples.js"; +import { + accessLocalStorage, + putLocalStorage, + Settings +} from "./Settings.js"; const PAUSE_BUTTON_TEXT = "Pause"; const PLAY_BUTTON_TEXT = "Run"; const MIN_CELLS = 50; const Mode = Object.freeze({ - // User is editing code - "EDIT_MODE":1, - // Transitioning between modes - "TRANSITION_MODE":2, - // User is stepping - "DEBUG_MODE":3, - // User is running the program (not stepping) - "PLAY_MODE":4, - // Program is waiting for user input - "INPUT_MODE":5, + // User is editing code + "EDIT_MODE": 1, + // Transitioning between modes + "TRANSITION_MODE": 2, + // User is stepping + "DEBUG_MODE": 3, + // User is running the program (not stepping) + "PLAY_MODE": 4, + // Program is waiting for user input + "INPUT_MODE": 5, }); +const iobox = document.querySelector("#iobox"); + // Common DOM elements -const dom_elements= -{ - hamburger_menu : document.querySelector("#hamburger-menu"), - hamburger_button : document.querySelector(".hamburger-button"), - settings_modal : document.querySelector("#settings-modal"), +const dom_elements = { + hamburger_menu: document.querySelector("#hamburger-menu"), + hamburger_button: document.querySelector(".hamburger-button"), + settings_modal: document.querySelector("#settings-modal"), }; let mode = Mode.EDIT_MODE; @@ -36,7 +46,7 @@ let highest_cell = -1; // Input buffer // User produces via iobox // BF program consumes -const input_queue = []; +const input_queue = []; // Used to determine which state we switched // from when switching to Input Mode let last_state; @@ -44,512 +54,464 @@ let last_state; // (for highlighting during debugging) let mark; // The time we wait between steps when debugging -let step_delay=0; +let step_delay = 0; // Rows that we stop at // Only in "Play" mode const breakpoints = new Set(); -const code_editor = CodeMirror(document.querySelector("#edit-panel-container"), - { - lineWrapping: true, - spellCheck:false, - value:accessLocalStorage("source")||"", - gutters: ["breakpoints","CodeMirror-linenumbers"], - matchBrackets: true, - autoCloseBrackets: true - } -); -code_editor.save = ()=>putLocalStorage("source",code_editor.getValue()); - -function addBreakpoint(line) -{ - const marker = document.createElement("div"); - marker.classList.add("breakpoint"); - marker.innerHTML = "●"; - breakpoints.add(line); - code_editor.setGutterMarker(line, "breakpoints", marker); +/* eslint no-undef: "off" */ +const code_editor = CodeMirror(document.querySelector("#edit-panel-container"), { + lineWrapping: true, + spellCheck: false, + value: accessLocalStorage("source") || "", + gutters: ["breakpoints", "CodeMirror-linenumbers"], + matchBrackets: true, + autoCloseBrackets: true +}); +code_editor.save = () => putLocalStorage("source", code_editor.getValue()); + +function addBreakpoint(line) { + const marker = document.createElement("div"); + marker.classList.add("breakpoint"); + marker.innerHTML = "●"; + breakpoints.add(line); + code_editor.setGutterMarker(line, "breakpoints", marker); } -function removeBreakpoint(line) -{ - breakpoints.delete(line); - code_editor.setGutterMarker(line, "breakpoints",null); + +function removeBreakpoint(line) { + breakpoints.delete(line); + code_editor.setGutterMarker(line, "breakpoints", null); } -function clearBreakpoints() -{ - breakpoints.length=0; - code_editor.clearGutter("breakpoints"); + +function clearBreakpoints() { + breakpoints.length = 0; + code_editor.clearGutter("breakpoints"); } code_editor.on("gutterClick", function(cm, n) { - const info = cm.lineInfo(n); - if(!info.gutterMarkers) - addBreakpoint(n); - else - removeBreakpoint(n); + const info = cm.lineInfo(n); + if (!info.gutterMarkers) + addBreakpoint(n); + else + removeBreakpoint(n); }); -function updateSettings() -{ - code_editor.setOption("mode", settings.get("editor-highlighting")?"brainfuck":null); - code_editor.setOption("keyMap",settings.get("editor-keymap").toLowerCase()); - code_editor.setOption("lineNumbers",settings.get("line-numbers")); - code_editor.setOption("autoCloseBrackets",settings.get("close-brackets")); - code_editor.setOption("matchBrackets",settings.get("match-brackets")); - - debug.cell_width = 2**settings.get("cell-width"); - debug.optimize=settings.get("optimize"); - debug.allow_negative_pointer = settings.get("double-tape"); - debug.allow_wrapping = settings.get("wrapping-allowed"); - step_delay=settings.get("step-delay"); - - /* New Theme */ - const editor_theme = settings.get("editor-theme"); - const global_theme = settings.get("global-theme"); - - document.querySelector("#global-theme").href="themes/"+global_theme+".css"; - (a=>a.href=a.href.replace(/theme\/.*.css/, "theme/"+editor_theme+".css"))( - document.querySelector("#editor-theme") - ); - code_editor.setOption("theme",editor_theme); +function updateSettings() { + code_editor.setOption("mode", settings.get("editor-highlighting") ? "brainfuck" : null); + code_editor.setOption("keyMap", settings.get("editor-keymap").toLowerCase()); + code_editor.setOption("lineNumbers", settings.get("line-numbers")); + code_editor.setOption("autoCloseBrackets", settings.get("close-brackets")); + code_editor.setOption("matchBrackets", settings.get("match-brackets")); + + debug.cell_width = 2 ** settings.get("cell-width"); + debug.optimize = settings.get("optimize"); + debug.allow_negative_pointer = settings.get("double-tape"); + debug.allow_wrapping = settings.get("wrapping-allowed"); + step_delay = settings.get("step-delay"); + + /* New Theme */ + const editor_theme = settings.get("editor-theme"); + const global_theme = settings.get("global-theme"); + + document.querySelector("#global-theme").href = "themes/" + global_theme + ".css"; + (a => a.href = a.href.replace(/theme\/.*.css/, "theme/" + editor_theme + ".css"))( + document.querySelector("#editor-theme") + ); + code_editor.setOption("theme", editor_theme); } /* For whatever reason, I decided to call states "Modes" * Kinda a FSM */ -function switchToInputMode() -{ - last_state = mode; - switchToDebugMode(); +function switchToInputMode() { + last_state = mode; + switchToDebugMode(); - const iobox = document.querySelector("#iobox"); - iobox.focus(); + iobox.focus(); - mode = Mode.INPUT_MODE; + mode = Mode.INPUT_MODE; } -function switchFromInputMode() -{ - if(last_state === Mode.PLAY_MODE) - play(); - else if(last_state === Mode.DEBUG_MODE) - switchToDebugMode(); - else - throw "Unknown mode we switched from"; + +function switchFromInputMode() { + if (last_state === Mode.PLAY_MODE) + play(); + else if (last_state === Mode.DEBUG_MODE) + switchToDebugMode(); + else + throw "Unknown mode we switched from"; } -function switchToPlayMode() -{ - switchToDebugMode(); - mode = Mode.PLAY_MODE; - updateButtons(); + +function switchToPlayMode() { + switchToDebugMode(); + mode = Mode.PLAY_MODE; + updateButtons(); } -function switchToEditMode() -{ - if(mode === Mode.EDIT_MODE) - return; - mode = Mode.TRANSITION_MODE; +function switchToEditMode() { + if (mode === Mode.EDIT_MODE) + return; + mode = Mode.TRANSITION_MODE; - // Disable tape to show user that we're not debugging - document.getElementById("tape").classList.add("disabled"); + // Disable tape to show user that we're not debugging + document.getElementById("tape").classList.add("disabled"); - // Reset debugger - this is mainly to stop cell highlighting - debug.load(""); + // Reset debugger - this is mainly to stop cell highlighting + debug.load(""); - // Disable CodeMirror input - code_editor.setOption("readOnly", false); + // Disable CodeMirror input + code_editor.setOption("readOnly", false); - // Remove highlighting - if(mark)mark.clear(); + // Remove highlighting + if (mark) mark.clear(); - mode = Mode.EDIT_MODE; + mode = Mode.EDIT_MODE; - updateButtons(); - updateTape(); + updateButtons(); + updateTape(); } -function switchToDebugMode() -{ - - if([Mode.PLAY_MODE,Mode.DEBUG_MODE,Mode.INPUT_MODE]. - includes(mode)) - { - mode = Mode.DEBUG_MODE; - updateButtons(); - return; - } - mode = Mode.TRANSITION_MODE; - - loadAndReset(); - document.getElementById("tape").classList.remove("disabled"); - code_editor.setOption("readOnly", true); - - // Restore breakpoints - breakpoints.length=0; - for(let i=0;iMIN_CELLS?pointer:MIN_CELLS; - - if(desired_amount_of_cells > highest_cell) - { - const template = tape.querySelector("#cell-template"); - for(let i=highest_cell+1;i<=desired_amount_of_cells;i++) - { - const new_cell = template.cloneNode(true); - new_cell.removeAttribute("hidden"); - new_cell.id="cell-"+i; - new_cell.querySelector(".cell-index").textContent=i; - new_cell.querySelector(".cell-value").textContent="0"; - tape.appendChild(new_cell); - } - highest_cell = desired_amount_of_cells; - } - - const old_cell = tape.querySelector(".active"); - if(old_cell) - { - old_cell.classList.remove("active"); - } - if(!debug.atBeginning() && pointer >= 0) - { - const val = debug.tape[pointer]||0; - const current_cell = tape.querySelector("#cell-"+pointer||0); - const rect = current_cell.getBoundingClientRect(); - - current_cell.querySelector(".cell-value").textContent=val; - current_cell.classList.add("active"); - - if ((rect.right < 0) || (rect.left > window.innerWidth)) - tape_container.scrollLeft = current_cell.offsetLeft; - } +function updateTape() { + const tape_container = document.getElementById("tape-container"); + const tape = tape_container.querySelector("#tape"); + const pointer = debug.pointer; + const desired_amount_of_cells = pointer > MIN_CELLS ? pointer : MIN_CELLS; + + if (desired_amount_of_cells > highest_cell) { + const template = tape.querySelector("#cell-template"); + for (let i = highest_cell + 1; i <= desired_amount_of_cells; i++) { + const new_cell = template.cloneNode(true); + new_cell.removeAttribute("hidden"); + new_cell.id = "cell-" + i; + new_cell.querySelector(".cell-index").textContent = i; + new_cell.querySelector(".cell-value").textContent = "0"; + tape.appendChild(new_cell); + } + highest_cell = desired_amount_of_cells; + } + + const old_cell = tape.querySelector(".active"); + if (old_cell) { + old_cell.classList.remove("active"); + } + if (!debug.atBeginning() && pointer >= 0) { + const val = debug.tape[pointer] || 0; + const current_cell = tape.querySelector("#cell-" + pointer || 0); + const rect = current_cell.getBoundingClientRect(); + + current_cell.querySelector(".cell-value").textContent = val; + current_cell.classList.add("active"); + + if ((rect.right < 0) || (rect.left > window.innerWidth)) + tape_container.scrollLeft = current_cell.offsetLeft; + } } -function step(reverse=false, update=true) -{ - try{ - debug.step(reverse); - }catch(e) - { - raiseError(e); - return false; - } - if(update) - { - updateHighlight(); - updateTape(); - } - return true; + +function step(reverse = false, update = true) { + try { + debug.step(reverse); + } catch (e) { + raiseError(e); + return false; + } + if (update) { + updateHighlight(); + updateTape(); + } + return true; } function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); + return new Promise(resolve => setTimeout(resolve, ms)); } -document.querySelector("#step-forward-button").addEventListener("click",()=> { - switchToDebugMode(); - if(!debug.atEnd()) - { - step(false); - } - updateButtons(); +document.querySelector("#step-forward-button").addEventListener("click", () => { + switchToDebugMode(); + if (!debug.atEnd()) { + step(false); + } + updateButtons(); }); -function pause() -{ - document.querySelector("#playpause-button").removeEventListener("click",pause); - document.querySelector("#playpause-button").addEventListener("click",play); - switchToDebugMode(); +function pause() { + document.querySelector("#playpause-button").removeEventListener("click", pause); + document.querySelector("#playpause-button").addEventListener("click", play); + switchToDebugMode(); } -async function play(){ - switchToPlayMode(); - document.querySelector("#playpause-button").removeEventListener("click",play); - document.querySelector("#playpause-button").addEventListener("click",pause); - let counter=0; - while(!debug.atEnd() && mode === Mode.PLAY_MODE) - { - /* - * step_delay === 0 is super speed mode - * Only stopping occasionally - * or for input or output - */ - let token = debug.tokens[debug.pc]; - const prev_line = token.line; - if( - step_delay>0|| - ((counter%1000)===0) || - [ - TokenType.BF_OUTPUT, - TokenType.BF_INPUT, - TokenType.BF_START, - TokenType.BF_END - ].includes(token.type) - ) - { - if(!step())break; - await sleep(step_delay?step_delay-1:0); - } - else - { - if(!step(false, false))break; - } - counter++; - - token = debug.tokens[debug.pc]; - if(breakpoints.has(token.line) && token.line !== prev_line) - { - break; - } - } - updateTape(); - updateButtons(); - updateHighlight(); - if(mode === Mode.PLAY_MODE) - { - pause(); - } +async function play() { + switchToPlayMode(); + document.querySelector("#playpause-button").removeEventListener("click", play); + document.querySelector("#playpause-button").addEventListener("click", pause); + let counter = 0; + while (!debug.atEnd() && mode === Mode.PLAY_MODE) { + /* + * step_delay === 0 is super speed mode + * Only stopping occasionally + * or for input or output + */ + let token = debug.tokens[debug.pc]; + const prev_line = token.line; + if ( + step_delay > 0 || + ((counter % 1000) === 0) || [ + TokenType.BF_OUTPUT, + TokenType.BF_INPUT, + TokenType.BF_START, + TokenType.BF_END + ].includes(token.type) + ) { + if (!step()) break; + await sleep(step_delay ? step_delay - 1 : 0); + } else { + if (!step(false, false)) break; + } + counter++; + + token = debug.tokens[debug.pc]; + if (breakpoints.has(token.line) && token.line !== prev_line) { + break; + } + } + updateTape(); + updateButtons(); + updateHighlight(); + if (mode === Mode.PLAY_MODE) { + pause(); + } } -document.querySelector("#step-back-button").addEventListener("click",()=> { - switchToDebugMode(); - if(!debug.atBeginning()) - { - step(true); - } - updateButtons(); +document.querySelector("#step-back-button").addEventListener("click", () => { + switchToDebugMode(); + if (!debug.atBeginning()) { + step(true); + } + updateButtons(); }); -document.querySelector("#playpause-button").addEventListener("click",play); +document.querySelector("#playpause-button").addEventListener("click", play); -document.querySelector("#reset-button").addEventListener("click",()=> { - switchToDebugMode(); - loadAndReset(); - updateHighlight(); +document.querySelector("#reset-button").addEventListener("click", () => { + switchToDebugMode(); + loadAndReset(); + updateHighlight(); }); -document.querySelector("#edit-panel-container .CodeMirror-lines").addEventListener("click",()=>{ - if(mode === Mode.DEBUG_MODE) - switchToEditMode(); +document.querySelector("#edit-panel-container .CodeMirror-lines").addEventListener("click", () => { + if (mode === Mode.DEBUG_MODE) + switchToEditMode(); }); -function addCharacterToIOBox(ch) -{ - const term = document.querySelector("#iobox"); - if(ch==='\r') - { - ch='\n\r'; - } - term.querySelector("#iobox-content").textContent+=ch; - term.scrollTop = term.scrollHeight; +function addCharacterToIOBox(ch) { + const term = document.querySelector("#iobox"); + if (ch === '\r') { + ch = '\n\r'; + } + term.querySelector("#iobox-content").textContent += ch; + term.scrollTop = term.scrollHeight; } -document.querySelector("#iobox").addEventListener("focus", event=>{ - iobox.querySelector("#iobox-cursor").removeAttribute("hidden"); +document.querySelector("#iobox").addEventListener("focus", () => { + iobox.querySelector("#iobox-cursor").removeAttribute("hidden"); }); -document.querySelector("#iobox").addEventListener("blur", event=>{ - iobox.querySelector("#iobox-cursor").hidden = true; +document.querySelector("#iobox").addEventListener("blur", () => { + iobox.querySelector("#iobox-cursor").hidden = true; }); -document.querySelector("#iobox").addEventListener("keydown", event=>{ - const key = event.key; - if(event.isComposing || - event.keyCode === 229|| - mode !== Mode.INPUT_MODE - ) - { - return; - } - - let character=key; - - if (key === "Tab") - character="\t"; - else if (key === "Space") - character=" "; - else if (key === "Enter") - character="\r"; - - // ' and / open up search - if("'/ ".includes(key)) - event.preventDefault(); - - if(character.length === 1) - { - addCharacterToIOBox(character); - input_queue.push(character.charCodeAt(0)); - } - if(key==="Enter" && mode === Mode.INPUT_MODE) - switchFromInputMode(); +document.querySelector("#iobox").addEventListener("keydown", event => { + const key = event.key; + if (event.isComposing || + event.keyCode === 229 || + mode !== Mode.INPUT_MODE + ) { + return; + } + + let character = key; + + if (key === "Tab") + character = "\t"; + else if (key === "Space") + character = " "; + else if (key === "Enter") + character = "\r"; + + // ' and / open up search + if ("'/ ".includes(key)) + event.preventDefault(); + + if (character.length === 1) { + addCharacterToIOBox(character); + input_queue.push(character.charCodeAt(0)); + } + if (key === "Enter" && mode === Mode.INPUT_MODE) + switchFromInputMode(); }); -debug.output_callback=addCharacterToIOBox; +debug.output_callback = addCharacterToIOBox; -function raiseError(message) -{ - const modal = document.querySelector("#error-modal"); - modal.querySelector("#error-message").textContent = message; - modal.removeAttribute("hidden"); +function raiseError(message) { + const modal = document.querySelector("#error-modal"); + modal.querySelector("#error-message").textContent = message; + modal.removeAttribute("hidden"); } -function input_callback() -{ - // If val is null, Debugger does not step - let val = null; - if(input_queue.length > 0) - { - val = input_queue.shift(); - } - else - { - switchToInputMode(); - } - return val; +function input_callback() { + // If val is null, Debugger does not step + let val = null; + if (input_queue.length > 0) { + val = input_queue.shift(); + } else { + switchToInputMode(); + } + return val; } debug.input_callback = input_callback; -dom_elements.hamburger_button.addEventListener("click", ()=>{ - let initial = true; - const menu = dom_elements.hamburger_menu; - const handler = e=>{ - // Skip first click - if(initial) - initial= false; - else - { - menu.hidden = true; - document.removeEventListener("click", handler); - } - }; - if(menu.hidden) - { - menu.removeAttribute("hidden"); - document.addEventListener("click", handler); - } +dom_elements.hamburger_button.addEventListener("click", () => { + let initial = true; + const menu = dom_elements.hamburger_menu; + const handler = () => { + // Skip first click + if (initial) + initial = false; + else { + menu.hidden = true; + document.removeEventListener("click", handler); + } + }; + if (menu.hidden) { + menu.removeAttribute("hidden"); + document.addEventListener("click", handler); + } }); -document.getElementById("clear-iobox").addEventListener("click",()=>{ - document.getElementById("iobox-content").textContent=""; - input_queue.length=0; +document.getElementById("clear-iobox").addEventListener("click", () => { + document.getElementById("iobox-content").textContent = ""; + input_queue.length = 0; }); document.getElementById("clear-breakpoints"). - addEventListener("click", clearBreakpoints); +addEventListener("click", clearBreakpoints); document.querySelectorAll("#examples-modal button[data-example]").forEach( - button=>button.addEventListener("click", - e=>{ - code_editor.setOption("value", - getExample(e.target.getAttribute("data-example"))); - loadAndReset(); - } - ) + button => button.addEventListener("click", + e => { + code_editor.setOption("value", + getExample(e.target.getAttribute("data-example"))); + loadAndReset(); + } + ) ); clearTape(); diff --git a/examples.js b/examples.js index 6cdad59..6f2b30d 100644 --- a/examples.js +++ b/examples.js @@ -1,6 +1,5 @@ -const EXAMPLES = -{ - "hello-world":`[ This program prints "Hello World!" and a newline to the screen, its +const EXAMPLES = { + "hello-world": `[ This program prints "Hello World!" and a newline to the screen, its length is 106 active command characters. [It is not the shortest.] This loop is an "initial comment loop", a simple way of adding a comment @@ -43,7 +42,7 @@ Pointer : ^ +++.------.--------. Cell #3 for 'rl' and 'd' >>+. Add 1 to Cell #5 gives us an exclamation point >++. And finally a newline from Cell #6`, - "rot13":`-,+[ Read first character and start outer character reading loop + "rot13": `-,+[ Read first character and start outer character reading loop -[ Skip forward if character is 0 >>++++[>++++++++<-] Set up divisor (32) for division loop (MEMORY LAYOUT: dividend copy remainder divisor quotient zero zero) @@ -71,7 +70,7 @@ Pointer : ^ <.[-] Output ROT13ed character from copy and clear it <-,+ Read next character ] End character reading loop`, - "cell-size":`Calculate the value 256 and test if it's zero + "cell-size": `Calculate the value 256 and test if it's zero If the interpreter errors on overflow this is where it'll happen ++++++++[>++++++++<-]>[<++++>-] +<[>-< @@ -94,7 +93,6 @@ Clean up used cells. [[-]<]`, }; -export function getExample(name) -{ - return EXAMPLES[name]; +export function getExample(name) { + return EXAMPLES[name]; } diff --git a/modals.js b/modals.js index bbb7aef..0ace075 100644 --- a/modals.js +++ b/modals.js @@ -1,79 +1,63 @@ let highest_z_index = 10; -function focusOnModal(id) -{ - const modal = document.getElementById(id); - highest_z_index++; - modal.style.zIndex = highest_z_index; +function focusOnModal(id) { + const modal = document.getElementById(id); + highest_z_index++; + modal.style.zIndex = highest_z_index; } -function openModal(id) -{ - const modal = document.getElementById(id); - focusOnModal(id); - modal.removeAttribute("hidden"); +function openModal(id) { + const modal = document.getElementById(id); + focusOnModal(id); + modal.removeAttribute("hidden"); } // Allow user to close modal by pressing the little 'x' -function closeModal(id) -{ - const modal = document.getElementById(id); - modal.setAttribute("hidden",true); +function closeModal(id) { + const modal = document.getElementById(id); + modal.setAttribute("hidden", true); } // If a modal has multiple panels, allow switching -function switchToPanel(id) -{ - const main_view = this.querySelector(".modal-main-view"); - let found = false; - for(const panel of main_view.children) - { - if(panel.id === id) - { - found = true; - panel.removeAttribute("hidden"); - } - else - { - panel.hidden = true; - } - } - if(!found)throw("Can't switch to panel "+id); +function switchToPanel(id) { + const main_view = this.querySelector(".modal-main-view"); + let found = false; + for (const panel of main_view.children) { + if (panel.id === id) { + found = true; + panel.removeAttribute("hidden"); + } else { + panel.hidden = true; + } + } + if (!found) throw ("Can't switch to panel " + id); } -for(const modal of document.querySelectorAll(".modal")) -{ - const close_button = modal.querySelector(".close-modal"); - if(close_button)close_button.addEventListener("click", - closeModal.bind(null,modal.id)); +for (const modal of document.querySelectorAll(".modal")) { + const close_button = modal.querySelector(".close-modal"); + if (close_button) close_button.addEventListener("click", + closeModal.bind(null, modal.id)); - modal.addEventListener("click",focusOnModal.bind(null,modal.id)); + modal.addEventListener("click", focusOnModal.bind(null, modal.id)); - const switch_buttons = modal.querySelectorAll(".modal-nav button"); - for(const switch_button of switch_buttons) - { - const switch_id = switch_button.getAttribute("data-goto"); - if(switch_button !== switch_buttons[0]) - document.querySelector(`#${switch_id}`).hidden = true; + const switch_buttons = modal.querySelectorAll(".modal-nav button"); + for (const switch_button of switch_buttons) { + const switch_id = switch_button.getAttribute("data-goto"); + if (switch_button !== switch_buttons[0]) + document.querySelector(`#${switch_id}`).hidden = true; - switch_button.addEventListener("click",switchToPanel.bind(modal, switch_id)); - } + switch_button.addEventListener("click", switchToPanel.bind(modal, switch_id)); + } } -for(const button of document.querySelectorAll(".modal-activator")) -{ - let handler; - if(button.hasAttribute("data-modal-open")) - { - handler = openModal.bind(null,button.getAttribute("data-modal-open")); - } - else if(button.hasAttribute("data-modal-focus")) - { - const id = button.getAttribute("data-modal-focus"); - const modal = document.getElementById(id); - handler = focusOnModal.bind(null, id); - } - else - continue; - button.addEventListener("click", handler); +for (const button of document.querySelectorAll(".modal-activator")) { + let handler; + if (button.hasAttribute("data-modal-open")) { + handler = openModal.bind(null, button.getAttribute("data-modal-open")); + } else if (button.hasAttribute("data-modal-focus")) { + const id = button.getAttribute("data-modal-focus"); + handler = focusOnModal.bind(null, id); + } else + continue; + button.addEventListener("click", handler); } diff --git a/package-lock.json b/package-lock.json index fdcae28..70c2014 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,19 +11,1811 @@ "dependencies": { "codemirror-minified": "^5.65.0" }, - "devDependencies": {} + "devDependencies": { + "eslint": "^8.11.0", + "js-beautify": "^1.14.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", + "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } }, "node_modules/codemirror-minified": { "version": "5.65.0", "resolved": "https://registry.npmjs.org/codemirror-minified/-/codemirror-minified-5.65.0.tgz", "integrity": "sha512-AxpxR5XolsvgAjwE1BspomW6fhj541BxMyj0HT5TmeketKJ/kPSEiTZes/cQgHvHOmGB4clbR67Mz/ORrjYkMQ==" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "dev": true, + "dependencies": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + }, + "bin": { + "editorconfig": "bin/editorconfig" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.12.0.tgz", + "integrity": "sha512-it1oBL9alZg1S8UycLm5YDMAkIhtH6FtAzuZs6YvoGVldWjbS08BkAdb/ymP9LlAyq8koANu32U7Ib/w+UNh8Q==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.2.1", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/espree": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "dev": true, + "dependencies": { + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/js-beautify": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.0.tgz", + "integrity": "sha512-yuck9KirNSCAwyNJbqW+BxJqJ0NLJ4PwBUzQQACl5O3qHMBXVkXb/rD0ilh/Lat/tn88zSZ+CAHOlk0DsY7GuQ==", + "dev": true, + "dependencies": { + "config-chain": "^1.1.12", + "editorconfig": "^0.15.3", + "glob": "^7.1.3", + "nopt": "^5.0.0" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true } }, "dependencies": { + "@eslint/eslintrc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", + "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + } + }, + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, "codemirror-minified": { "version": "5.65.0", "resolved": "https://registry.npmjs.org/codemirror-minified/-/codemirror-minified-5.65.0.tgz", "integrity": "sha512-AxpxR5XolsvgAjwE1BspomW6fhj541BxMyj0HT5TmeketKJ/kPSEiTZes/cQgHvHOmGB4clbR67Mz/ORrjYkMQ==" + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "dev": true, + "requires": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.12.0.tgz", + "integrity": "sha512-it1oBL9alZg1S8UycLm5YDMAkIhtH6FtAzuZs6YvoGVldWjbS08BkAdb/ymP9LlAyq8koANu32U7Ib/w+UNh8Q==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.2.1", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "dev": true, + "requires": { + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-beautify": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.0.tgz", + "integrity": "sha512-yuck9KirNSCAwyNJbqW+BxJqJ0NLJ4PwBUzQQACl5O3qHMBXVkXb/rD0ilh/Lat/tn88zSZ+CAHOlk0DsY7GuQ==", + "dev": true, + "requires": { + "config-chain": "^1.1.12", + "editorconfig": "^0.15.3", + "glob": "^7.1.3", + "nopt": "^5.0.0" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true } } } diff --git a/package.json b/package.json index 860e043..ef0c882 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "BrainfuckDebugger", - "author":{ - "name":"Dagan Martinez", - "url":"https://dagans.dev" + "author": { + "name": "Dagan Martinez", + "url": "https://dagans.dev" }, "version": "0.1.0", "type": "module", @@ -13,10 +13,14 @@ "codemirror-minified": "^5.65.0" }, "devDependencies": { + "eslint": "^8.11.0", + "js-beautify": "^1.14.0" }, "scripts": { - "test": "node --experimental-modules test.js" + "test": "node --experimental-modules test.js", + "format": "js-beautify --end-with-newline *.js", + "lint": "eslint *.js" }, "license": "MIT", - "private":true + "private": true } diff --git a/test.js b/test.js index e5ece18..e14bb98 100644 --- a/test.js +++ b/test.js @@ -1,288 +1,249 @@ -import {TokenType, Debugger} from './Debugger.js'; - -function assert(claim, message) -{ - if (message == undefined) - message = ""; - if(!claim) - { - throw("Assertion failed:" + message); - } +import { + TokenType, + Debugger +} from './Debugger.js'; + +function assert(claim, message) { + if (message == undefined) + message = ""; + if (!claim) { + throw ("Assertion failed:" + message); + } } -function codifyString(str) -{ - let output=""; - for(const c of str) - { - if(c.charCodeAt(0) < 33) - { - output+="<"+c.charCodeAt(0)+">"; - } - else - { - output+=c; - } - } - return output; - -} -const SOURCES = [ - { - code:"+++[->++<]>>--->>++", - expected_result:"" - }, - { - code:"------- [+] +++", - expected_result:"" - }, - { - code:"+++++[-]+++", - expected_result:"" - }, - { - code:">++++++++[->-[->-[->-[-]<]<]<] ++++++++[<++++++++++>-]<[>+>+<<-]>-.>-----.>++++++++++.", - expected_result:"OK\n" - }, - { - code:" >++++++++[-<+++++++++>]<.>>+>-[+]++>++>+++[>[->+++<<+++>]<<]>-----.>-> +++..+++.>-.<<+[>[+>+]>>]<--------------.>>.+++.------.--------.>+.>+.", - expected_result:"Hello World!\n" - }, - { - code:"++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.", - expected_result:"Hello World!\n" - }, - { - code:"++++++++++[>++++++++++<-]>>++++++++++>->>>>>>>>>>>>>>>>-->+++++++[->++ ++++++++<]>[->+>+>+>+<<<<]+++>>+++>>>++++++++[-<++++<++++<++++>>>]++++ +[-<++++<++++>>]>>-->++++++[->+++++++++++<]>[->+>+>+>+<<<<]+++++>>+>++ ++++>++++++>++++++++[-<++++<++++<++++>>>]++++++[-<+++<+++<+++>>>]>>--> ---+[-<+]-<[+[->+]-<<->>>+>[-]++[-->++]-->+++[---++[--<++]---->>-<+>[+ +++[----<++++]--[>]++[-->++]--<]>++[--+[-<+]->>[-]+++++[---->++++]-->[ ->+<]>>[.>]++[-->++]]-->+++]---+[-<+]->>-[+>>>+[-<+]->>>++++++++++<<[- >+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]>>[-]>>>++++++++++<[->-[>+>>]>[+[-<+>]> +>>]<<<<<]>[-]>>[>++++++[-<++++++++>]<.<<+>+>[-]]<[<[->-<]++++++[->+++ +++++<]>.[-]]<<++++++[-<++++++++>]<.[-]<<[-<+>]+[-<+]->>]+[-]<<<.>>>+[ -<+]-<<]", - expected_result:"1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n11\nFizz\n13\n14\nFizzBuzz\n16\n17\nFizz\n19\nBuzz\nFizz\n22\n23\nFizz\nBuzz\n26\nFizz\n28\n29\nFizzBuzz\n31\n32\nFizz\n34\nBuzz\nFizz\n37\n38\nFizz\nBuzz\n41\nFizz\n43\n44\nFizzBuzz\n46\n47\nFizz\n49\nBuzz\nFizz\n52\n53\nFizz\nBuzz\n56\nFizz\n58\n59\nFizzBuzz\n61\n62\nFizz\n64\nBuzz\nFizz\n67\n68\nFizz\nBuzz\n71\nFizz\n73\n74\nFizzBuzz\n76\n77\nFizz\n79\nBuzz\nFizz\n82\n83\nFizz\nBuzz\n86\nFizz\n88\n89\nFizzBuzz\n91\n92\nFizz\n94\nBuzz\nFizz\n97\n98\nFizz\nBuzz\n" - } +const SOURCES = [{ + code: "+++[->++<]>>--->>++", + expected_result: "" + }, + { + code: "------- [+] +++", + expected_result: "" + }, + { + code: "+++++[-]+++", + expected_result: "" + }, + { + code: ">++++++++[->-[->-[->-[-]<]<]<] ++++++++[<++++++++++>-]<[>+>+<<-]>-.>-----.>++++++++++.", + expected_result: "OK\n" + }, + { + code: " >++++++++[-<+++++++++>]<.>>+>-[+]++>++>+++[>[->+++<<+++>]<<]>-----.>-> +++..+++.>-.<<+[>[+>+]>>]<--------------.>>.+++.------.--------.>+.>+.", + expected_result: "Hello World!\n" + }, + { + code: "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.", + expected_result: "Hello World!\n" + }, + { + code: "++++++++++[>++++++++++<-]>>++++++++++>->>>>>>>>>>>>>>>>-->+++++++[->++ ++++++++<]>[->+>+>+>+<<<<]+++>>+++>>>++++++++[-<++++<++++<++++>>>]++++ +[-<++++<++++>>]>>-->++++++[->+++++++++++<]>[->+>+>+>+<<<<]+++++>>+>++ ++++>++++++>++++++++[-<++++<++++<++++>>>]++++++[-<+++<+++<+++>>>]>>--> ---+[-<+]-<[+[->+]-<<->>>+>[-]++[-->++]-->+++[---++[--<++]---->>-<+>[+ +++[----<++++]--[>]++[-->++]--<]>++[--+[-<+]->>[-]+++++[---->++++]-->[ ->+<]>>[.>]++[-->++]]-->+++]---+[-<+]->>-[+>>>+[-<+]->>>++++++++++<<[- >+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]>>[-]>>>++++++++++<[->-[>+>>]>[+[-<+>]> +>>]<<<<<]>[-]>>[>++++++[-<++++++++>]<.<<+>+>[-]]<[<[->-<]++++++[->+++ +++++<]>.[-]]<<++++++[-<++++++++>]<.[-]<<[-<+>]+[-<+]->>]+[-]<<<.>>>+[ -<+]-<<]", + expected_result: "1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n11\nFizz\n13\n14\nFizzBuzz\n16\n17\nFizz\n19\nBuzz\nFizz\n22\n23\nFizz\nBuzz\n26\nFizz\n28\n29\nFizzBuzz\n31\n32\nFizz\n34\nBuzz\nFizz\n37\n38\nFizz\nBuzz\n41\nFizz\n43\n44\nFizzBuzz\n46\n47\nFizz\n49\nBuzz\nFizz\n52\n53\nFizz\nBuzz\n56\nFizz\n58\n59\nFizzBuzz\n61\n62\nFizz\n64\nBuzz\nFizz\n67\n68\nFizz\nBuzz\n71\nFizz\n73\n74\nFizzBuzz\n76\n77\nFizz\n79\nBuzz\nFizz\n82\n83\nFizz\nBuzz\n86\nFizz\n88\n89\nFizzBuzz\n91\n92\nFizz\n94\nBuzz\nFizz\n97\n98\nFizz\nBuzz\n" + } ]; -function basic_validation_test(optimize=true){ - for(const source of SOURCES) - { - const debug = new Debugger(source.code); - debug.optimize = optimize; - for(const token of debug.tokens) - { - if (token.partner) - { - let self_type = token.type; - let partner_type = debug.tokens[token.partner].type; - if(self_type == TokenType.BF_LOOP_CLOSE) - { - assert(partner_type ===TokenType.BF_LOOP_OPEN, "] should have [ as a partner"); - } - else - { - assert(self_type == TokenType.BF_LOOP_OPEN, "Non-loop token has partner"); - assert(partner_type ===TokenType.BF_LOOP_CLOSE, "[ should have ] as a partner"); - } - } - } - } - return true; +function basic_validation_test(optimize = true) { + for (const source of SOURCES) { + const debug = new Debugger(source.code); + debug.optimize = optimize; + for (const token of debug.tokens) { + if (token.partner) { + let self_type = token.type; + let partner_type = debug.tokens[token.partner].type; + if (self_type == TokenType.BF_LOOP_CLOSE) { + assert(partner_type === TokenType.BF_LOOP_OPEN, "] should have [ as a partner"); + } else { + assert(self_type == TokenType.BF_LOOP_OPEN, "Non-loop token has partner"); + assert(partner_type === TokenType.BF_LOOP_CLOSE, "[ should have ] as a partner"); + } + } + } + } + return true; } -function congruent_state_test(optimize=true){ - for(const source of SOURCES) - { - const debug = new Debugger(source.code); - debug.optimize = optimize; - let output = ""; - debug.output_callback = (val)=>{output+=val;}; +function congruent_state_test(optimize = true) { + for (const source of SOURCES) { + const debug = new Debugger(source.code); + debug.optimize = optimize; - while(!debug.atEnd()) - { - debug.step(); - } + let output = ""; + debug.output_callback = (val) => { + output += val; + }; - assert(output==source.expected_result); + while (!debug.atEnd()) { + debug.step(); + } + assert(output == source.expected_result); - const first_final_hash = debug.getStateHash(); - debug.reset(); - for(let i=0;!debug.atEnd();i++) - { - const hash1=debug.getStateHash(); - debug.step(); - + const first_final_hash = debug.getStateHash(); + debug.reset(); - const hash2=debug.getStateHash(); - debug.step(true); + for (let i = 0; !debug.atEnd(); i++) { + const hash1 = debug.getStateHash(); + debug.step(); - const hash3=debug.getStateHash(); - debug.step(); - assert(hash1===hash3, `hash1!==hash3 (pc:${debug.pc}, i:${i})`, debug); - const hash4=debug.getStateHash(); + const hash2 = debug.getStateHash(); + debug.step(true); - assert(hash2===hash4, "hash2!==hash4", debug); - } + const hash3 = debug.getStateHash(); + debug.step(); + assert(hash1 === hash3, `hash1!==hash3 (pc:${debug.pc}, i:${i})`, debug); - assert(debug.getStateHash()===first_final_hash, "Final hash failed"); - } - return true; -} -function two_steps_back_test(optimize=true){ - for(const source of ["+++++[->+.+<]>>>"]) - { - const debug = new Debugger(source); - debug.optimize = optimize; - - while(!debug.atEnd()) - { - debug.step(); - } - - const first_final_hash = debug.getStateHash(); - - while(debug.tokens[debug.pc].type !== TokenType.BF_OUTPUT) - { - debug.step(true); - } - - while(!debug.atEnd()) - { - debug.step(); - } - assert(first_final_hash == debug.getStateHash(), "Failed after rewinding to middle"); - - while(!debug.atBeginning()) - { - debug.step(true); - } - for(let i=0;i<10;i++) - { - assert([0,undefined].includes(debug.tape[i]), - "Tape was not cleared after rewinding("+debug.tape[i]+")"); - } - - } - return true; + const hash4 = debug.getStateHash(); + + assert(hash2 === hash4, "hash2!==hash4", debug); + } + + assert(debug.getStateHash() === first_final_hash, "Final hash failed"); + } + return true; } -function rewind_test(optimize=true){ - const debug=new Debugger(); - debug.optimize = optimize; - for(const source of SOURCES) - { - let output=""; - debug.load(source.code); +function two_steps_back_test(optimize = true) { + for (const source of ["+++++[->+.+<]>>>"]) { + const debug = new Debugger(source); + debug.optimize = optimize; + + while (!debug.atEnd()) { + debug.step(); + } + + const first_final_hash = debug.getStateHash(); + + while (debug.tokens[debug.pc].type !== TokenType.BF_OUTPUT) { + debug.step(true); + } + + while (!debug.atEnd()) { + debug.step(); + } + assert(first_final_hash == debug.getStateHash(), "Failed after rewinding to middle"); + + while (!debug.atBeginning()) { + debug.step(true); + } + for (let i = 0; i < 10; i++) { + assert([0, undefined].includes(debug.tape[i]), + "Tape was not cleared after rewinding(" + debug.tape[i] + ")"); + } + + } + return true; +} - assert(debug.source === source.code); - assert(debug.pc === 0); - assert(debug.pointer === 0); +function rewind_test(optimize = true) { + const debug = new Debugger(); + debug.optimize = optimize; + for (const source of SOURCES) { + let output = ""; + debug.load(source.code); - debug.output_callback = (val)=>{ output+=val; }; + assert(debug.source === source.code); + assert(debug.pc === 0); + assert(debug.pointer === 0); - let initial_hash = debug.getStateHash(); + debug.output_callback = (val) => { + output += val; + }; - while(!debug.atEnd()) - { - debug.step(); - } + let initial_hash = debug.getStateHash(); - let final_hash = debug.getStateHash(); + while (!debug.atEnd()) { + debug.step(); + } - assert(output === source.expected_result, "Before rewind: expected output not matched"); + assert(output === source.expected_result, "Before rewind: expected output not matched"); - /* Rewind */ - while(!debug.atBeginning()) - { - debug.step(true); - } + /* Rewind */ + while (!debug.atBeginning()) { + debug.step(true); + } - assert(debug.getStateHash() == initial_hash, "Initial hash is not the same"); + assert(debug.getStateHash() == initial_hash, "Initial hash is not the same"); - for(const token of debug.tokens) - { - if(token.pc_stack) - assert(token.pc_stack.length===1, `Ended up with non-empty PC stack in ${token.character}(column:${token.column}): ${token.pc_stack} `); - } + for (const token of debug.tokens) { + if (token.pc_stack) + assert(token.pc_stack.length === 1, `Ended up with non-empty PC stack in ${token.character}(column:${token.column}): ${token.pc_stack} `); + } - output=""; - while(!debug.atEnd()) - { - debug.step(); - } + output = ""; + while (!debug.atEnd()) { + debug.step(); + } - assert(output === source.expected_result, "After rewind: expected output not matched"); + assert(output === source.expected_result, "After rewind: expected output not matched"); - } - return true; + } + return true; } -function pinpoint_test(optimize=true){ - const code = ">++<.>>+>-[+]++>++>+++[>[->+++<<+++>]<<]"; - const debug=new Debugger(code); - debug.optimize = optimize; - - let i=0; - let initial_hash = debug.getStateHash(); - while(!debug.atEnd()) - { - debug.step(); - i++; - let pc = debug.pc; - for(let j=0;j